@devultur/convex 1.3.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +426 -9
  2. package/dist/bin/init.js +44 -23
  3. package/dist/chunk-EX3W77VY.js +245 -0
  4. package/dist/chunk-HOFTKJWT.js +58 -0
  5. package/dist/chunk-KAIVI7RB.js +21 -0
  6. package/dist/chunk-QBHIZBOQ.js +139 -0
  7. package/dist/{chunk-GKLFRSGI.js → chunk-YIPZZDGD.js} +8 -1
  8. package/dist/component/_generated/api.d.ts +6 -0
  9. package/dist/component/_generated/api.d.ts.map +1 -1
  10. package/dist/component/_generated/api.js.map +1 -1
  11. package/dist/component/_generated/component.d.ts +27 -0
  12. package/dist/component/_generated/component.d.ts.map +1 -1
  13. package/dist/component/library.d.ts +93 -0
  14. package/dist/component/library.d.ts.map +1 -0
  15. package/dist/component/library.js +74 -0
  16. package/dist/component/library.js.map +1 -0
  17. package/dist/component/mediaMeta.d.ts +46 -0
  18. package/dist/component/mediaMeta.d.ts.map +1 -0
  19. package/dist/component/mediaMeta.js +82 -0
  20. package/dist/component/mediaMeta.js.map +1 -0
  21. package/dist/component/metadata.d.ts +59 -0
  22. package/dist/component/metadata.d.ts.map +1 -0
  23. package/dist/component/metadata.js +32 -0
  24. package/dist/component/metadata.js.map +1 -0
  25. package/dist/component/public.d.ts +17 -1
  26. package/dist/component/public.d.ts.map +1 -1
  27. package/dist/component/public.js +20 -11
  28. package/dist/component/public.js.map +1 -1
  29. package/dist/component/schema.d.ts +17 -2
  30. package/dist/component/schema.d.ts.map +1 -1
  31. package/dist/component/schema.js +13 -1
  32. package/dist/component/schema.js.map +1 -1
  33. package/dist/component/uploads.d.ts +13 -0
  34. package/dist/component/uploads.d.ts.map +1 -1
  35. package/dist/component/uploads.js +24 -5
  36. package/dist/component/uploads.js.map +1 -1
  37. package/dist/error-labels-BfqcFh2R.d.ts +19 -0
  38. package/dist/index.d.ts +204 -93
  39. package/dist/index.js +200 -128
  40. package/dist/locales/es.d.ts +11 -0
  41. package/dist/locales/es.js +162 -0
  42. package/dist/media-picker-labels-CiVcNUZo.d.ts +114 -0
  43. package/dist/{pdf-render-CiCK6V1X.d.ts → pdf-render-BwJGagvz.d.ts} +1 -1
  44. package/dist/pdfjs.d.ts +13 -2
  45. package/dist/pdfjs.js +9 -0
  46. package/dist/react.d.ts +441 -66
  47. package/dist/react.js +1663 -550
  48. package/dist/types-LrusGVDf.d.ts +62 -0
  49. package/dist/validators.d.ts +17 -5
  50. package/dist/validators.js +1 -1
  51. package/package.json +8 -4
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
- import { VideoModuleConfig, ObjectLock, LockView, SetLockOptions, HoldPage, DevulturMedia } from '@devultur/core';
1
+ import { 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 * as convex_server from 'convex/server';
4
- import { FunctionReference, GenericQueryCtx, GenericDataModel, GenericMutationCtx, GenericActionCtx, PaginationOptions, PaginationResult } from 'convex/server';
5
- import { Value, ConvexError } from 'convex/values';
3
+ import { FunctionReference, FunctionVisibility, DefaultFunctionArgs, GenericQueryCtx, GenericDataModel, GenericMutationCtx, GenericActionCtx, RegisteredQuery, RegisteredMutation, RegisteredAction, PaginationOptions, PaginationResult } from 'convex/server';
4
+ import { PropertyValidators, Value, ConvexError } from 'convex/values';
5
+ import { D as DevulturComponentConfig, M as MediaRecord } from './types-LrusGVDf.js';
6
+ export { P as ProgressRecord } from './types-LrusGVDf.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-BfqcFh2R.js';
6
8
  export { dv } from './validators.js';
7
9
 
8
10
  /**
@@ -26,6 +28,23 @@ export { dv } from './validators.js';
26
28
  * ```
27
29
  */
28
30
  type ComponentApi<Name extends string | undefined = string | undefined> = {
31
+ library: {
32
+ backfillSearchText: FunctionReference<"mutation", "internal", {
33
+ batchSize?: number;
34
+ }, any, Name>;
35
+ searchMedia: FunctionReference<"query", "internal", {
36
+ paginationOpts: {
37
+ cursor: string | null;
38
+ endCursor?: string | null;
39
+ id?: number;
40
+ maximumBytesRead?: number;
41
+ maximumRowsRead?: number;
42
+ numItems: number;
43
+ };
44
+ search: string;
45
+ type?: "video" | "image" | "file";
46
+ }, any, Name>;
47
+ };
29
48
  lock: {
30
49
  getLock: FunctionReference<"action", "internal", {
31
50
  key: string;
@@ -46,6 +65,14 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
46
65
  until?: string;
47
66
  }, any, Name>;
48
67
  };
68
+ metadata: {
69
+ updateMediaMeta: FunctionReference<"mutation", "internal", {
70
+ alt?: string;
71
+ key: string;
72
+ tags?: Array<string>;
73
+ title?: string;
74
+ }, any, Name>;
75
+ };
49
76
  public: {
50
77
  createMedia: FunctionReference<"mutation", "internal", {
51
78
  contentType: string;
@@ -85,6 +112,7 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
85
112
  }, any, Name>;
86
113
  issueViewerToken: FunctionReference<"action", "internal", {
87
114
  sessionSecret?: string;
115
+ userId?: string;
88
116
  }, any, Name>;
89
117
  listCaptionsByMedia: FunctionReference<"query", "internal", {
90
118
  mediaKey: string;
@@ -154,59 +182,112 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
154
182
  filename?: string;
155
183
  height?: number;
156
184
  key: string;
185
+ pageCount?: number;
157
186
  width?: number;
158
187
  }, any, Name>;
159
188
  };
160
189
  };
161
190
 
162
- interface DevulturComponentConfig {
163
- video?: VideoModuleConfig;
191
+ type FunctionKind = "query" | "mutation" | "action";
192
+ type ContextOf<Kind extends FunctionKind> = Kind extends "query" ? GenericQueryCtx<GenericDataModel> : Kind extends "mutation" ? GenericMutationCtx<GenericDataModel> : GenericActionCtx<GenericDataModel>;
193
+ /** What a guard tells the function about its caller. */
194
+ interface CallerContext {
164
195
  /**
165
- * Lock every upload through the exposed `createUploadUrl` gets (retention and/or hold). Set here, on your server:
166
- * the browser never chooses a lock. To lock per upload, call `devultur.createUploadUrl(ctx, { lock })` from your
167
- * own function.
196
+ * The caller's user: the subject of `issueViewerToken`'s token, and the only `userId` the progress functions accept
197
+ * (another one is refused with `user_mismatch`).
168
198
  */
169
- upload?: {
170
- lock?: ObjectLock;
171
- };
199
+ userId?: string;
200
+ /** The caller may name any `userId` in the progress functions (an admin resetting a learner's progress). */
201
+ canActForOthers?: boolean;
172
202
  }
173
- interface MediaRecord {
174
- /** The media id (the `id` of its `DevulturMedia`), for every kind. */
175
- key: string;
176
- type: "video" | "image" | "file";
177
- filename: string;
178
- contentType: string;
179
- sizeBytes: number;
180
- /** Set by a confirmed upload; unset on records from before 1.1.0. */
181
- visibility?: "public" | "private";
182
- /** Key of the uploaded object (a video's raw file). Set by a confirmed upload. */
183
- objectKey?: string;
184
- width?: number;
185
- height?: number;
186
- transcodeStatus?: "queued" | "transcoding" | "captioning" | "ready" | "failed";
187
- transcodeProgress?: {
188
- current: number;
189
- total: number;
190
- };
191
- transcodeError?: string;
192
- playlistUrl?: string;
193
- thumbnailKey?: string;
194
- /** Key of the storyboard VTT (hover previews); URL via `buildStoryboardUrl` from `@devultur/core`. */
195
- storyboardKey?: string;
196
- captionLocales?: string[];
197
- /** True while requested captions haven't arrived; the video waits in "captioning" only then. */
198
- captionsPending?: boolean;
199
- duration?: number;
200
- createdAt: number;
201
- }
202
- interface ProgressRecord {
203
- userId: string;
204
- videoId: string;
205
- lastPosition: number;
206
- completedAt?: number;
207
- watchedPercent?: number;
208
- updatedAt: number;
203
+ interface ExposedFunction<Kind extends FunctionKind, Args extends DefaultFunctionArgs, Result> {
204
+ kind: Kind;
205
+ args: PropertyValidators;
206
+ handler: (ctx: ContextOf<Kind>, args: Args, caller: CallerContext) => Promise<Result>;
209
207
  }
208
+ declare function exposedFunctions(component: ComponentApi, config?: DevulturComponentConfig): {
209
+ issueViewerToken: ExposedFunction<"action", {
210
+ sessionSecret?: string | undefined;
211
+ }, any>;
212
+ createUploadUrl: ExposedFunction<"action", {
213
+ visibility?: "public" | "private" | undefined;
214
+ contentType: string;
215
+ filename: string;
216
+ }, any>;
217
+ confirmUpload: ExposedFunction<"action", {
218
+ filename?: string | undefined;
219
+ height?: number | undefined;
220
+ pageCount?: number | undefined;
221
+ width?: number | undefined;
222
+ key: string;
223
+ }, any>;
224
+ updateMediaMeta: ExposedFunction<"mutation", {
225
+ alt?: string | undefined;
226
+ tags?: string[] | undefined;
227
+ title?: string | undefined;
228
+ key: string;
229
+ }, any>;
230
+ deleteMedia: ExposedFunction<"action", {
231
+ key: string;
232
+ }, any>;
233
+ deleteVideo: ExposedFunction<"action", {
234
+ visibility?: "public" | "private" | undefined;
235
+ videoId: string;
236
+ }, any>;
237
+ processVideo: ExposedFunction<"action", {
238
+ key: string;
239
+ }, any>;
240
+ getMedia: ExposedFunction<"query", {
241
+ key: string;
242
+ }, any>;
243
+ listMediaPage: ExposedFunction<"query", {
244
+ type?: "video" | "image" | "file" | undefined;
245
+ paginationOpts: {
246
+ id?: number;
247
+ endCursor?: string | null;
248
+ maximumRowsRead?: number;
249
+ maximumBytesRead?: number;
250
+ numItems: number;
251
+ cursor: string | null;
252
+ };
253
+ }, any>;
254
+ searchMedia: ExposedFunction<"query", {
255
+ type?: "video" | "image" | "file" | undefined;
256
+ paginationOpts: {
257
+ id?: number;
258
+ endCursor?: string | null;
259
+ maximumRowsRead?: number;
260
+ maximumBytesRead?: number;
261
+ numItems: number;
262
+ cursor: string | null;
263
+ };
264
+ search: string;
265
+ }, any>;
266
+ saveProgress: ExposedFunction<"mutation", {
267
+ videoId: string;
268
+ userId: string;
269
+ position: number;
270
+ }, any>;
271
+ loadProgress: ExposedFunction<"query", {
272
+ videoId: string;
273
+ userId: string;
274
+ }, any>;
275
+ markComplete: ExposedFunction<"mutation", {
276
+ videoId: string;
277
+ userId: string;
278
+ }, any>;
279
+ resetProgress: ExposedFunction<"mutation", {
280
+ videoId: string;
281
+ userId: string;
282
+ }, any>;
283
+ };
284
+ type ExposedFunctions = ReturnType<typeof exposedFunctions>;
285
+ 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;
287
+ /** The Convex functions registered from `ExposedFunctions`, each with its own args and result. */
288
+ type RegisteredFunctions<Visibility extends FunctionVisibility> = {
289
+ [Name in ExposedFunctionName]: Registered<ExposedFunctions[Name], Visibility>;
290
+ };
210
291
 
211
292
  type DevulturComponent = ComponentApi;
212
293
  type QueryCtx = GenericQueryCtx<GenericDataModel>;
@@ -222,14 +303,30 @@ type MediaPageArgs = {
222
303
  type?: MediaType;
223
304
  paginationOpts: PaginationOptions;
224
305
  };
306
+ type SearchMediaArgs = MediaPageArgs & {
307
+ search: string;
308
+ };
309
+ /** `updated`: records this first batch filled. `isDone`: `false` while later batches are scheduled. */
310
+ type BackfillResult = {
311
+ updated: number;
312
+ isDone: boolean;
313
+ };
225
314
  type ConfirmUploadArgs = {
226
315
  key: string;
227
316
  filename?: string;
228
317
  width?: number;
229
318
  height?: number;
319
+ pageCount?: number;
320
+ };
321
+ type MediaMetaArgs = {
322
+ key: string;
323
+ title?: string;
324
+ alt?: string;
325
+ tags?: string[];
230
326
  };
231
327
  declare class Devultur {
232
- private component;
328
+ /** The mounted component (`components.devultur`) this client calls. */
329
+ readonly component: DevulturComponent;
233
330
  constructor(component: DevulturComponent);
234
331
  getMedia(ctx: QueryCtx, key: string): Promise<any>;
235
332
  saveProgress(ctx: MutationCtx, args: {
@@ -249,8 +346,16 @@ declare class Devultur {
249
346
  /**
250
347
  * Records an upload in the component once its bytes are stored (after the PUT): it then shows in `listMedia`.
251
348
  * Returns the record, or `null` when nothing is stored at `key`. Uploads nobody confirms are recorded a day later.
349
+ * `width`, `height` and `pageCount` are the client's hints (positive integers up to 100,000); an image size the
350
+ * Worker read from the bytes wins over them.
252
351
  */
253
352
  confirmUpload(ctx: ActionCtx, args: ConfirmUploadArgs): Promise<MediaRecord | null>;
353
+ /**
354
+ * Sets a record's `title`, `alt` and/or `tags` (only the ones passed; an empty string clears a title or alt, `[]`
355
+ * the tags). `key` is the media id. Trimmed and deduplicated; past title 200, alt 1000 or 20 tags of 50 characters
356
+ * it throws `invalid_media_metadata`. Returns the updated record, or `null` when there is none.
357
+ */
358
+ updateMediaMeta(ctx: MutationCtx, args: MediaMetaArgs): Promise<MediaRecord | null>;
254
359
  /**
255
360
  * The recorded media (every confirmed upload, and every video sent to `processVideo`), optionally of one type.
256
361
  * `mediaFromRecord(record)` turns a row into the reference `<Image>` and `dv.media()` take. Unbounded: it reads every
@@ -261,6 +366,19 @@ declare class Devultur {
261
366
  }): Promise<MediaRecord[]>;
262
367
  /** One page of the recorded media, newest first, optionally of one type. Takes Convex's `paginationOpts`. */
263
368
  listMediaPage(ctx: QueryCtx, args: MediaPageArgs): Promise<PaginationResult<MediaRecord>>;
369
+ /**
370
+ * One page of the records whose title or filename matches `search` (its last word as a prefix), best match first,
371
+ * optionally of one type. A blank `search` lists newest first, like `listMediaPage`. Records from before 1.4.0
372
+ * match once `backfillSearchText` (or any write) gives them a `searchText`.
373
+ */
374
+ searchMedia(ctx: QueryCtx, args: SearchMediaArgs): Promise<PaginationResult<MediaRecord>>;
375
+ /**
376
+ * One-off for records written before 1.4.0: gives every record without a `searchText` one, `batchSize` records
377
+ * per mutation (default 100, at most 1000). Runs the first batch and schedules the rest. Safe to run again.
378
+ */
379
+ backfillSearchText(ctx: MutationCtx, options?: {
380
+ batchSize?: number;
381
+ }): Promise<BackfillResult>;
264
382
  /** The lock in force on `key`. */
265
383
  getLock(ctx: ActionCtx, key: string): Promise<LockView>;
266
384
  /** Sets or extends `key`'s retention (shortening a governance one needs `bypassGovernance` and the Worker's hook). */
@@ -269,48 +387,11 @@ declare class Devultur {
269
387
  setHold(ctx: ActionCtx, keys: string[]): Promise<Pick<HoldPage, "updated" | "skipped">>;
270
388
  /** Releases `keys`' holds: a retention `period` starts now; without a retention they're free. */
271
389
  releaseHold(ctx: ActionCtx, keys: string[]): Promise<Pick<HoldPage, "updated" | "skipped">>;
272
- static exposeApi(component: DevulturComponent, config?: DevulturComponentConfig): {
273
- issueViewerToken: convex_server.RegisteredAction<"public", {
274
- sessionSecret?: string;
275
- }, Promise<any>>;
276
- createUploadUrl: convex_server.RegisteredAction<"public", {
277
- filename: string;
278
- contentType: string;
279
- visibility?: "public" | "private";
280
- }, Promise<any>>;
281
- confirmUpload: convex_server.RegisteredAction<"public", ConfirmUploadArgs, Promise<any>>;
282
- deleteMedia: convex_server.RegisteredAction<"public", {
283
- key: string;
284
- }, Promise<any>>;
285
- deleteVideo: convex_server.RegisteredAction<"public", {
286
- videoId: string;
287
- visibility?: "public" | "private";
288
- }, Promise<any>>;
289
- processVideo: convex_server.RegisteredAction<"public", {
290
- key: string;
291
- }, Promise<any>>;
292
- getMedia: convex_server.RegisteredQuery<"public", {
293
- key: string;
294
- }, Promise<any>>;
295
- listMediaPage: convex_server.RegisteredQuery<"public", MediaPageArgs, Promise<any>>;
296
- saveProgress: convex_server.RegisteredMutation<"public", {
297
- userId: string;
298
- videoId: string;
299
- position: number;
300
- }, Promise<any>>;
301
- loadProgress: convex_server.RegisteredQuery<"public", {
302
- userId: string;
303
- videoId: string;
304
- }, Promise<any>>;
305
- markComplete: convex_server.RegisteredMutation<"public", {
306
- userId: string;
307
- videoId: string;
308
- }, Promise<any>>;
309
- resetProgress: convex_server.RegisteredMutation<"public", {
310
- userId: string;
311
- videoId: string;
312
- }, Promise<any>>;
313
- };
390
+ /**
391
+ * The component's functions for your app to export. They have no auth of their own: anyone who can call your
392
+ * Convex deployment can call them. `defineDevulturFunctions` returns the same functions behind your guard.
393
+ */
394
+ static exposeApi(component: DevulturComponent, config?: DevulturComponentConfig): RegisteredFunctions<"public">;
314
395
  }
315
396
 
316
397
  /** `data` of the `ConvexError` a component action throws when the Worker refuses a request. */
@@ -329,11 +410,41 @@ declare function isDevulturError(error: unknown): error is ConvexError<DevulturE
329
410
  /** The refusal's `{ code, message, status, details? }`, or `null` when `error` isn't one. */
330
411
  declare function devulturErrorOf(error: unknown): DevulturErrorData | null;
331
412
 
413
+ type ArgsOf<Fn> = Fn extends {
414
+ handler: (ctx: never, args: infer Args, caller: never) => unknown;
415
+ } ? Args : never;
416
+ /** One call to guard: which function, of which kind, with the caller's arguments. Narrow on `name`. */
417
+ type DevulturOperation = {
418
+ [Name in ExposedFunctionName]: {
419
+ name: Name;
420
+ kind: ExposedFunctions[Name]["kind"];
421
+ args: ArgsOf<ExposedFunctions[Name]>;
422
+ };
423
+ }[ExposedFunctionName];
424
+ /** The ctx of the guarded function: a query's, a mutation's or an action's (all of them have `auth`). */
425
+ type DevulturGuardCtx = GenericQueryCtx<GenericDataModel> | GenericMutationCtx<GenericDataModel> | GenericActionCtx<GenericDataModel>;
426
+ /**
427
+ * Throws to deny the call. May return what it learned about the caller: a `userId` becomes the subject of the token
428
+ * `issueViewerToken` issues, and the only user the progress functions act for (another `userId` in their arguments is
429
+ * refused with `user_mismatch`, unless the guard also returns `canActForOthers: true`).
430
+ */
431
+ type DevulturGuard = (ctx: DevulturGuardCtx, operation: DevulturOperation) => GuardResult | Promise<GuardResult>;
432
+ type GuardResult = CallerContext | undefined | void;
433
+ interface DevulturFunctionsOptions<Visibility extends FunctionVisibility> {
434
+ guard: DevulturGuard;
435
+ /** `"internal"` registers them as internal functions (callable from your server only). Default `"public"`. */
436
+ visibility?: Visibility;
437
+ /** Same as `Devultur.exposeApi`'s: the transcode preset, caption locales and upload lock. */
438
+ config?: DevulturComponentConfig;
439
+ }
440
+ /** `Devultur.exposeApi`'s functions, each calling `options.guard` before it runs. Export the ones your app uses. */
441
+ declare function defineDevulturFunctions<Visibility extends FunctionVisibility = "public">(devultur: Devultur, options: DevulturFunctionsOptions<Visibility>): RegisteredFunctions<Visibility>;
442
+
332
443
  /**
333
444
  * The `DevulturMedia` reference of a component record (a `listMedia` row), ready for `<Image>`, `<DownloadLink>` or a
334
445
  * `dv.media()` field. `null` for a record without a visibility: one from before 1.1.0, or a video only `processVideo`
335
- * recorded.
446
+ * recorded. A stored reference is a copy: a later `updateMediaMeta` changes the record, not the references to it.
336
447
  */
337
448
  declare function mediaFromRecord(record: MediaRecord): DevulturMedia | null;
338
449
 
339
- export { Devultur, type DevulturComponentConfig, type DevulturErrorData, type MediaRecord, type ProgressRecord, devulturErrorOf, isDevulturError, mediaFromRecord };
450
+ export { type CallerContext, Devultur, DevulturComponentConfig, type DevulturErrorData, type DevulturFunctionsOptions, type DevulturGuard, type DevulturGuardCtx, type DevulturOperation, MediaRecord, type RegisteredFunctions, defineDevulturFunctions, devulturErrorOf, isDevulturError, mediaFromRecord };