@read-frog/api-contract 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { eventIterator, oc } from "@orpc/contract";
2
2
  import { z } from "zod";
3
- import { EBOOK_ALLOWED_COVER_CONTENT_TYPES, GATED_FEATURE_KEYS, NOTEBASE_COLUMN_MAX_WIDTH, NOTEBASE_COLUMN_MIN_WIDTH, SRS_REVIEW_DURATION_MS_MAX, activeScheduleStatusSchema, canonicalTimeZone, cardIdentityShape, cardMemoryStateShape, cardStateSchema, cardStateSchema as cardStateSchema$1, cardTemplateConfigSchema, cardTemplateCreatedBySchema, fsrsMemoryStateSchema, fsrsReviewLogSnapshotSchema, getVideoIdFromUrl, langCodeISO6393Schema, notebaseColumnConfigSchema, reviewRatingSchema, scheduleStatusSchema, scheduleStatusSchema as scheduleStatusSchema$1, schedulingParamsSchema, schedulingParamsShape, srsModelVersionSchema, srsStepSchema, srsWeightsSchema, transcriptSegmentSchema } from "@read-frog/definitions";
4
- //#region src/schemas/app-locale.ts
3
+ import { EBOOK_ALLOWED_COVER_CONTENT_TYPES, GATED_FEATURE_KEYS, MEDIA_ASSET_STATUS_VALUES, MEDIA_CONTENT_TYPES, NOTEBASE_COLUMN_MAX_WIDTH, NOTEBASE_COLUMN_MIN_WIDTH, PDF_TRANSLATION_MAX_BATCH_FILES, POSTPONE_DAMAGE_THRESHOLD, SRS_REVIEW_DURATION_MS_MAX, activeScheduleStatusSchema, canonicalTimeZone, cardIdentityShape, cardMemoryStateShape, cardStateSchema, cardStateSchema as cardStateSchema$1, cardTemplateConfigSchema, cardTemplateCreatedBySchema, checkoutAttributionInputSchema, fsrsMemoryStateSchema, fsrsReviewLogSnapshotSchema, getVideoIdFromUrl, langCodeISO6393Schema, notebaseColumnConfigSchema, reviewRatingSchema, scheduleStatusSchema, scheduleStatusSchema as scheduleStatusSchema$1, schedulingParamsSchema, schedulingParamsShape, srsModelVersionSchema, srsSleepSourceSchema, srsStepSchema, srsWeightsSchema, transcriptSegmentSchema } from "@read-frog/definitions";
4
+ // src/schemas/app-locale.ts
5
5
  /**
6
6
  * The languages the website is in (`project.inlang/settings.json`; a test in
7
7
  * apps/www keeps the two in step). Used wherever the server writes for a
@@ -18,8 +18,7 @@ const appLocaleSchema = z.enum([
18
18
  "zh",
19
19
  "zh-TW"
20
20
  ]);
21
- //#endregion
22
- //#region src/schemas/billing.ts
21
+ // src/schemas/billing.ts
23
22
  const billingIntervalSchema = z.enum(["month", "year"]);
24
23
  const billingSubscriptionStatusSchema = z.enum([
25
24
  "incomplete",
@@ -51,6 +50,21 @@ const MCP_DAILY_CALL_LIMITS = {
51
50
  pro: 50,
52
51
  ultra: null
53
52
  };
53
+ /**
54
+ * How many ebooks each plan may keep at once. Free keeps one, so it reads one
55
+ * book at a time; deleting a book frees its place for the next.
56
+ *
57
+ * Read by the API's upload gate AND by the website's copy (the pricing page),
58
+ * so the pages cannot promise books the server refuses.
59
+ *
60
+ * Companion edit when this changes: `account-and-plans` under
61
+ * `apps/www/content/docs/`, which states the numbers.
62
+ */
63
+ const EBOOK_LIMIT_BY_PLAN = {
64
+ free: 1,
65
+ pro: 10,
66
+ ultra: 80
67
+ };
54
68
  const billingCheckoutPlanSchema = z.enum(["pro", "ultra"]);
55
69
  const billingCurrencySchema = z.enum([
56
70
  "usd",
@@ -109,13 +123,14 @@ const billingCreateCheckoutSessionInputSchema = z.object({
109
123
  currency: billingCurrencySchema,
110
124
  interval: billingIntervalSchema,
111
125
  locale: appLocaleSchema,
112
- plan: billingCheckoutPlanSchema.default("pro")
126
+ plan: billingCheckoutPlanSchema.default("pro"),
127
+ requestId: z.uuid().optional(),
128
+ attribution: checkoutAttributionInputSchema.optional()
113
129
  }).strict();
114
130
  const billingCreateCustomerPortalSessionInputSchema = z.object({ locale: appLocaleSchema }).strict();
115
131
  const billingSessionUrlOutputSchema = z.object({ url: z.url() }).strict();
116
132
  const billingCancelScheduledChangeOutputSchema = z.object({ success: z.literal(true) }).strict();
117
- //#endregion
118
- //#region src/schemas/hosted-ai.ts
133
+ // src/schemas/hosted-ai.ts
119
134
  const HostedAiOutputFieldTypeSchema = z.enum(["string", "number"]);
120
135
  const HostedAiOutputFieldSchema = z.strictObject({
121
136
  name: z.string().trim().min(1).max(80),
@@ -143,7 +158,8 @@ const HostedAiFeatureSchema = z.enum([
143
158
  "selectionTranslation",
144
159
  "videoSubtitles",
145
160
  "inputTranslation",
146
- "languageDetection"
161
+ "languageDetection",
162
+ "pdfTranslation"
147
163
  ]);
148
164
  const HostedAiRequestIdSchema = z.uuid();
149
165
  const HostedAiRequestMetadataSchema = {
@@ -271,7 +287,9 @@ const HostedAiCreditPolicyIdSchema = z.enum([
271
287
  "custom-action-guest-daily-v1",
272
288
  "custom-action-user-daily-v1",
273
289
  "custom-action-pro-daily-v1",
274
- "ultra-weekly-v1"
290
+ "ultra-weekly-v1",
291
+ "pro-weekly-v1",
292
+ "pro-weekly-v2"
275
293
  ]);
276
294
  const HostedAiCreditPeriodKindSchema = z.enum(["daily", "weekly"]);
277
295
  const HostedAiQuotaScopeSchema = z.enum(["guest", "user"]);
@@ -332,6 +350,9 @@ const HostedAiOneTimeCreditStatusSchema = z.strictObject({
332
350
  * pool ends at `expiresAt`. Narrow on `periodKind` before reading either.
333
351
  */
334
352
  const HostedAiCreditPoolStatusSchema = z.discriminatedUnion("periodKind", [HostedAiRecurringCreditStatusSchema, HostedAiOneTimeCreditStatusSchema]);
353
+ /** Feature-scoped credit display, separate from the legacy extension status shape. */
354
+ const HostedAiCreditPoolsInputSchema = z.strictObject({ feature: HostedAiFeatureSchema });
355
+ const HostedAiCreditPoolsOutputSchema = z.strictObject({ pools: z.array(HostedAiCreditPoolStatusSchema) });
335
356
  const HostedAiTierStatusSchema = z.strictObject({
336
357
  accessAllowed: z.boolean(),
337
358
  available: z.boolean(),
@@ -383,8 +404,125 @@ const HostedAiStatusOutputSchema = z.strictObject({
383
404
  languageDetection: HostedAiFeatureStatusSchema
384
405
  })
385
406
  });
386
- //#endregion
387
- //#region src/public-errors.ts
407
+ // src/schemas/pdf-translation.ts
408
+ const pdfTranslationJobStatusSchema = z.enum([
409
+ "queued",
410
+ "running",
411
+ "cancel_requested",
412
+ "succeeded",
413
+ "failed",
414
+ "cancelled",
415
+ "expired"
416
+ ]);
417
+ /**
418
+ * The two PDFs one translation makes: the translation alone, with the
419
+ * original's layout, and the original and translated pages side by side.
420
+ */
421
+ const pdfTranslationOutputVariantSchema = z.enum(["translated", "bilingual"]);
422
+ const languageSchema = z.string().min(2).max(40).regex(/^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$/i);
423
+ const pdfTranslationRequestUploadInputSchema = z.object({
424
+ fileName: z.string().trim().min(1).max(255).refine((fileName) => fileName.toLowerCase().endsWith(".pdf"), { message: "fileName must end with .pdf" }),
425
+ fileByteSize: z.number().int().min(1)
426
+ }).strict();
427
+ const pdfTranslationRequestUploadOutputSchema = z.object({
428
+ uploadId: z.uuid(),
429
+ upload: z.object({
430
+ url: z.url(),
431
+ headers: z.record(z.string(), z.string())
432
+ }).strict(),
433
+ expiresAt: z.coerce.date()
434
+ }).strict();
435
+ const pdfTranslationSubmitInputSchema = z.object({
436
+ uploadIds: z.array(z.uuid()).min(1).max(PDF_TRANSLATION_MAX_BATCH_FILES).refine((ids) => new Set(ids).size === ids.length, { message: "uploadIds must not repeat" }),
437
+ idempotencyKey: z.string().trim().min(1).max(200),
438
+ targetLanguage: languageSchema,
439
+ modelTier: HostedAiModelTierSchema
440
+ }).strict();
441
+ const pdfTranslationJobIdInputSchema = z.object({ id: z.uuid() }).strict();
442
+ const pdfTranslationOutputInputSchema = z.object({
443
+ id: z.uuid(),
444
+ variant: pdfTranslationOutputVariantSchema
445
+ }).strict();
446
+ const pdfTranslationListInputSchema = z.object({}).strict();
447
+ const pdfTranslationJobResourceSchema = z.object({
448
+ id: z.uuid(),
449
+ status: pdfTranslationJobStatusSchema,
450
+ sourceFileName: z.string(),
451
+ targetLanguage: z.string(),
452
+ modelTier: HostedAiModelTierSchema,
453
+ batchId: z.uuid(),
454
+ batchPosition: z.number().int().min(0),
455
+ waitingAhead: z.number().int().min(0).nullable(),
456
+ freeTrial: z.boolean(),
457
+ outputs: z.object({
458
+ translated: z.boolean(),
459
+ bilingual: z.boolean()
460
+ }).strict(),
461
+ pageCount: z.number().int().min(1),
462
+ progressStage: z.string().nullable(),
463
+ progressPercent: z.number().min(0).max(100),
464
+ estimatedCostNanoUsd: z.number().int().min(0),
465
+ chargedCostNanoUsd: z.number().int().min(0),
466
+ error: z.object({
467
+ category: z.string(),
468
+ message: z.string()
469
+ }).strict().nullable(),
470
+ workerRelease: z.string().nullable(),
471
+ createdAt: z.coerce.date(),
472
+ startedAt: z.coerce.date().nullable(),
473
+ completedAt: z.coerce.date().nullable(),
474
+ outputExpiresAt: z.coerce.date().nullable()
475
+ }).strict();
476
+ const pdfTranslationListOutputSchema = z.object({ items: z.array(pdfTranslationJobResourceSchema) }).strict();
477
+ /** What a submission made: its batch, and one job per PDF in their order. */
478
+ const pdfTranslationSubmitOutputSchema = z.object({
479
+ batchId: z.uuid(),
480
+ jobs: z.array(pdfTranslationJobResourceSchema).min(1)
481
+ }).strict();
482
+ /** A job, and every job of its batch in their order (itself included). */
483
+ const pdfTranslationGetOutputSchema = z.object({
484
+ job: pdfTranslationJobResourceSchema,
485
+ batch: z.array(pdfTranslationJobResourceSchema).min(1)
486
+ }).strict();
487
+ const pdfTranslationStatusInputSchema = z.object({}).strict();
488
+ const pdfTranslationStatusOutputSchema = z.object({
489
+ freeTrialsRemaining: z.number().int().min(0),
490
+ /**
491
+ * Whether Built-in AI credit pays for PDF translation on the normal tier:
492
+ * a paid plan, or credit the account was given for every feature. Only a
493
+ * funded account submits more than one PDF or downloads a translation.
494
+ */
495
+ funded: z.boolean()
496
+ }).strict();
497
+ const pdfTranslationDownloadOutputSchema = z.object({
498
+ url: z.url(),
499
+ expiresAt: z.coerce.date()
500
+ }).strict();
501
+ const pdfTranslationPreviewOutputSchema = z.object({
502
+ url: z.url(),
503
+ expiresAt: z.coerce.date(),
504
+ /**
505
+ * Whether the URL opens the free translation's copy with the Read Frog
506
+ * watermark, which an account nothing funds reads: upgrading opens the
507
+ * PDF itself.
508
+ */
509
+ watermarked: z.boolean()
510
+ }).strict();
511
+ const pdfTranslationDeleteOutputSchema = z.object({ id: z.uuid() }).strict();
512
+ const PdfTranslationInsufficientCreditDataSchema = z.strictObject({
513
+ estimatedCostNanoUsd: z.number().int().min(0),
514
+ remainingNanoUsd: z.number().int().min(0),
515
+ resetAt: z.iso.datetime().nullable()
516
+ });
517
+ /**
518
+ * Which of a submission's PDFs a refusal is about, so the page can point at
519
+ * it. For an upload an earlier request used up, also the translation it made.
520
+ */
521
+ const PdfTranslationUploadErrorDataSchema = z.strictObject({
522
+ uploadId: z.uuid(),
523
+ jobId: z.uuid().optional()
524
+ });
525
+ // src/public-errors.ts
388
526
  const CellValidationFailureReasonSchema = z.enum([
389
527
  "unknown_notebase_column",
390
528
  "type_mismatch",
@@ -542,6 +680,10 @@ const PUBLIC_APP_ERROR_DEFS = {
542
680
  message: "A subscription change is already scheduled",
543
681
  status: 409
544
682
  },
683
+ BILLING_CHECKOUT_CONFLICT: {
684
+ message: "Please start a new checkout from the pricing page",
685
+ status: 409
686
+ },
545
687
  CARD_NOT_REVIEWABLE: {
546
688
  message: "Card cannot be reviewed in its current state",
547
689
  status: 409
@@ -574,6 +716,22 @@ const PUBLIC_APP_ERROR_DEFS = {
574
716
  message: "Card status change is unavailable",
575
717
  status: 409
576
718
  },
719
+ RESCHEDULE_PLAN_EXPIRED: {
720
+ message: "The reschedule plan has expired; preview it again",
721
+ status: 409
722
+ },
723
+ RESCHEDULE_STALE: {
724
+ message: "Cards changed after the reschedule preview; preview it again",
725
+ status: 409
726
+ },
727
+ RESCHEDULE_PREVIEW_TIMEOUT: {
728
+ message: "Planning the reschedule took too long",
729
+ status: 503
730
+ },
731
+ RESCHEDULE_DAILY_LIMIT_INVALID: {
732
+ message: "The daily limit is outside the range a reschedule may suggest",
733
+ status: 422
734
+ },
577
735
  NOTEBASE_VIEW_NOT_FOUND: {
578
736
  message: "Notebase view not found",
579
737
  status: 404
@@ -591,10 +749,6 @@ const PUBLIC_APP_ERROR_DEFS = {
591
749
  message: "Concurrent position conflict, please retry",
592
750
  status: 409
593
751
  },
594
- EBOOK_BETA_RESTRICTED: {
595
- message: "Ebooks are currently in beta for selected accounts",
596
- status: 403
597
- },
598
752
  EBOOK_NOT_FOUND: {
599
753
  message: "Ebook not found",
600
754
  status: 404
@@ -611,9 +765,100 @@ const PUBLIC_APP_ERROR_DEFS = {
611
765
  message: "Ebook upload has not been completed",
612
766
  status: 409
613
767
  },
768
+ MEDIA_BETA_RESTRICTED: {
769
+ message: "Media uploads are currently in beta for selected accounts",
770
+ status: 403
771
+ },
772
+ MEDIA_NOT_FOUND: {
773
+ message: "Media file not found",
774
+ status: 404
775
+ },
776
+ MEDIA_FILE_TOO_LARGE: {
777
+ message: "Media file exceeds the maximum allowed size",
778
+ status: 413
779
+ },
780
+ MEDIA_QUOTA_EXCEEDED: {
781
+ message: "Not enough media storage space left on your plan",
782
+ status: 403
783
+ },
784
+ MEDIA_UPLOAD_NOT_COMPLETED: {
785
+ message: "Media upload has not been completed",
786
+ status: 409
787
+ },
614
788
  EMAIL_LINK_INVALID: {
615
789
  message: "This email link is not valid",
616
790
  status: 400
791
+ },
792
+ PDF_TRANSLATION_UNAVAILABLE: {
793
+ message: "PDF translation is not available right now",
794
+ status: 503
795
+ },
796
+ PDF_TRANSLATION_NOT_FOUND: {
797
+ message: "PDF translation not found",
798
+ status: 404
799
+ },
800
+ PDF_TRANSLATION_UPLOAD_NOT_FOUND: {
801
+ data: PdfTranslationUploadErrorDataSchema,
802
+ message: "PDF upload not found",
803
+ status: 404
804
+ },
805
+ PDF_TRANSLATION_UPLOAD_EXPIRED: {
806
+ data: PdfTranslationUploadErrorDataSchema,
807
+ message: "The PDF upload has expired; upload the file again",
808
+ status: 410
809
+ },
810
+ PDF_TRANSLATION_UPLOAD_NOT_COMPLETED: {
811
+ data: PdfTranslationUploadErrorDataSchema,
812
+ message: "The PDF upload has not been completed",
813
+ status: 409
814
+ },
815
+ PDF_TRANSLATION_FILE_TOO_LARGE: {
816
+ message: "The PDF exceeds the maximum allowed size",
817
+ status: 413
818
+ },
819
+ PDF_TRANSLATION_INVALID_PDF: {
820
+ data: PdfTranslationUploadErrorDataSchema,
821
+ message: "The file is not a readable PDF",
822
+ status: 422
823
+ },
824
+ PDF_TRANSLATION_ALREADY_TRANSLATED: {
825
+ data: PdfTranslationUploadErrorDataSchema,
826
+ message: "This PDF is already a translation; upload the original instead",
827
+ status: 422
828
+ },
829
+ PDF_TRANSLATION_PAGE_LIMIT_EXCEEDED: {
830
+ data: PdfTranslationUploadErrorDataSchema,
831
+ message: "The PDF has more pages than one translation allows",
832
+ status: 422
833
+ },
834
+ PDF_TRANSLATION_QUEUE_FULL: {
835
+ message: "Too many PDF translations are waiting; try again when some have finished",
836
+ status: 409
837
+ },
838
+ PDF_TRANSLATION_IDEMPOTENCY_CONFLICT: {
839
+ message: "This idempotency key was already used for a different PDF translation",
840
+ status: 409
841
+ },
842
+ PDF_TRANSLATION_INSUFFICIENT_CREDIT: {
843
+ data: PdfTranslationInsufficientCreditDataSchema,
844
+ message: "Not enough Built-in AI credit left to translate this PDF",
845
+ status: 429
846
+ },
847
+ PDF_TRANSLATION_NOT_CANCELLABLE: {
848
+ message: "This PDF translation has already finished",
849
+ status: 409
850
+ },
851
+ PDF_TRANSLATION_NOT_READY: {
852
+ message: "The translated PDF is not available",
853
+ status: 409
854
+ },
855
+ PDF_TRANSLATION_DOWNLOAD_RESTRICTED: {
856
+ message: "Downloading a translated PDF needs a Pro or Ultra plan",
857
+ status: 403
858
+ },
859
+ PDF_TRANSLATION_NOT_DELETABLE: {
860
+ message: "Cancel this PDF translation before deleting it",
861
+ status: 409
617
862
  }
618
863
  };
619
864
  function isPublicAppErrorCode(code) {
@@ -636,9 +881,8 @@ function pickPublicErrorMap(...codes) {
636
881
  }];
637
882
  }));
638
883
  }
639
- //#endregion
640
- //#region src/contracts/billing.ts
641
- const billingProcedure = oc.errors(pickPublicErrorMap("BILLING_NOT_CONFIGURED", "BILLING_CUSTOMER_NOT_FOUND", "BILLING_PASS_ACTIVE", "BILLING_CHANGE_SCHEDULED"));
884
+ // src/contracts/billing.ts
885
+ const billingProcedure = oc.errors(pickPublicErrorMap("BILLING_NOT_CONFIGURED", "BILLING_CUSTOMER_NOT_FOUND", "BILLING_PASS_ACTIVE", "BILLING_CHANGE_SCHEDULED", "BILLING_CHECKOUT_CONFLICT"));
642
886
  const billingContract = {
643
887
  status: billingProcedure.route({
644
888
  method: "GET",
@@ -665,8 +909,7 @@ const billingContract = {
665
909
  tags: ["Billing"]
666
910
  }).output(billingCancelScheduledChangeOutputSchema)
667
911
  };
668
- //#endregion
669
- //#region src/contracts/shared.ts
912
+ // src/contracts/shared.ts
670
913
  /**
671
914
  * Declares a procedure that is exposed to agents as an MCP tool, not only to
672
915
  * the REST/OpenAPI surface.
@@ -682,8 +925,7 @@ function defineAgentProcedure(route) {
682
925
  description: route.description
683
926
  }).route(route);
684
927
  }
685
- //#endregion
686
- //#region src/schemas/pagination.ts
928
+ // src/schemas/pagination.ts
687
929
  const paginationShape = {
688
930
  limit: z.number().int().min(1).max(500).optional(),
689
931
  offset: z.number().int().min(0).optional()
@@ -694,15 +936,13 @@ function pageSchema(itemSchema) {
694
936
  hasMore: z.boolean()
695
937
  });
696
938
  }
697
- //#endregion
698
- //#region src/schemas/resource-mutation.ts
939
+ // src/schemas/resource-mutation.ts
699
940
  const expectedUpdatedAtSchema = z.iso.datetime({ offset: true });
700
941
  const deletionResultSchema = z.object({
701
942
  id: z.uuid(),
702
943
  txid: z.number()
703
944
  });
704
- //#endregion
705
- //#region src/schemas/card.ts
945
+ // src/schemas/card.ts
706
946
  const cardTemplateSchema = z.object({
707
947
  id: z.uuid(),
708
948
  notebaseId: z.uuid(),
@@ -762,8 +1002,7 @@ const CardGenerateOutputSchema = z.object({
762
1002
  created: z.number().int().min(0),
763
1003
  txid: z.number()
764
1004
  });
765
- //#endregion
766
- //#region src/contracts/card.ts
1005
+ // src/contracts/card.ts
767
1006
  const cardContract = {
768
1007
  list: defineAgentProcedure({
769
1008
  method: "GET",
@@ -786,8 +1025,7 @@ const cardContract = {
786
1025
  tags: ["Cards"]
787
1026
  }).input(CardGenerateInputSchema).output(CardGenerateOutputSchema)
788
1027
  };
789
- //#endregion
790
- //#region src/contracts/card-template.ts
1028
+ // src/contracts/card-template.ts
791
1029
  const cardTemplateContract = {
792
1030
  list: defineAgentProcedure({
793
1031
  method: "GET",
@@ -825,8 +1063,7 @@ const cardTemplateContract = {
825
1063
  tags: ["Card Templates"]
826
1064
  }).errors(pickPublicErrorMap("CARD_TEMPLATE_NOT_FOUND")).input(CardTemplateDeleteInputSchema).output(CardTemplateDeleteOutputSchema)
827
1065
  };
828
- //#endregion
829
- //#region src/schemas/ebook.ts
1066
+ // src/schemas/ebook.ts
830
1067
  const ebookStatusSchema = z.enum(["pending", "ready"]);
831
1068
  const ebookCoverContentTypeSchema = z.enum(EBOOK_ALLOWED_COVER_CONTENT_TYPES);
832
1069
  const ebookListItemSchema = z.object({
@@ -862,7 +1099,14 @@ const ebookRequestUploadInputSchema = z.object({
862
1099
  cover: z.object({
863
1100
  contentType: ebookCoverContentTypeSchema,
864
1101
  byteSize: z.number().int().min(1)
865
- }).strict().optional()
1102
+ }).strict().optional(),
1103
+ /**
1104
+ * The client's key for this upload. Asking again with the same key, after
1105
+ * an answer that never arrived or for a retry, returns the same pending
1106
+ * book with fresh targets instead of reserving another place in the
1107
+ * library's allowance.
1108
+ */
1109
+ uploadKey: z.uuid().optional()
866
1110
  }).strict();
867
1111
  /**
868
1112
  * A signed PUT: send the file to `url` with exactly `headers`. The signature
@@ -899,61 +1143,59 @@ const ebookRenameInputSchema = ebookRenameDataSchema.extend({ id: z.uuid() });
899
1143
  const ebookRenameOutputSchema = z.object({ ebook: ebookListItemSchema }).strict();
900
1144
  const ebookDeleteInputSchema = z.object({ id: z.uuid() }).strict();
901
1145
  const ebookDeleteOutputSchema = z.object({ id: z.uuid() }).strict();
902
- //#endregion
903
- //#region src/contracts/ebook.ts
1146
+ // src/contracts/ebook.ts
904
1147
  const ebookProcedure = oc;
905
1148
  const ebookContract = {
906
- list: ebookProcedure.errors(pickPublicErrorMap("EBOOK_BETA_RESTRICTED")).route({
1149
+ list: ebookProcedure.route({
907
1150
  method: "GET",
908
1151
  path: "/ebooks",
909
1152
  summary: "List ebooks with quota",
910
1153
  tags: ["Ebooks"]
911
1154
  }).input(ebookListInputSchema).output(ebookListOutputSchema),
912
- get: ebookProcedure.errors(pickPublicErrorMap("EBOOK_BETA_RESTRICTED", "EBOOK_NOT_FOUND")).route({
1155
+ get: ebookProcedure.errors(pickPublicErrorMap("EBOOK_NOT_FOUND")).route({
913
1156
  method: "GET",
914
1157
  path: "/ebooks/{id}",
915
1158
  summary: "Get an ebook with reading progress",
916
1159
  tags: ["Ebooks"]
917
1160
  }).input(ebookGetInputSchema).output(ebookGetOutputSchema),
918
- requestUpload: ebookProcedure.errors(pickPublicErrorMap("EBOOK_BETA_RESTRICTED", "EBOOK_LIMIT_EXCEEDED", "EBOOK_FILE_TOO_LARGE")).route({
1161
+ requestUpload: ebookProcedure.errors(pickPublicErrorMap("EBOOK_LIMIT_EXCEEDED", "EBOOK_FILE_TOO_LARGE")).route({
919
1162
  method: "POST",
920
1163
  path: "/ebooks/uploads",
921
1164
  summary: "Request presigned upload URLs for a new ebook",
922
1165
  tags: ["Ebooks"]
923
1166
  }).input(ebookRequestUploadInputSchema).output(ebookRequestUploadOutputSchema),
924
- finalizeUpload: ebookProcedure.errors(pickPublicErrorMap("EBOOK_BETA_RESTRICTED", "EBOOK_NOT_FOUND", "EBOOK_UPLOAD_NOT_COMPLETED", "EBOOK_FILE_TOO_LARGE")).route({
1167
+ finalizeUpload: ebookProcedure.errors(pickPublicErrorMap("EBOOK_NOT_FOUND", "EBOOK_UPLOAD_NOT_COMPLETED", "EBOOK_FILE_TOO_LARGE")).route({
925
1168
  method: "POST",
926
1169
  path: "/ebooks/{ebookId}/finalize",
927
1170
  summary: "Finalize an ebook upload",
928
1171
  tags: ["Ebooks"]
929
1172
  }).input(ebookFinalizeUploadInputSchema).output(ebookFinalizeUploadOutputSchema),
930
- getDownloadUrl: ebookProcedure.errors(pickPublicErrorMap("EBOOK_BETA_RESTRICTED", "EBOOK_NOT_FOUND")).route({
1173
+ getDownloadUrl: ebookProcedure.errors(pickPublicErrorMap("EBOOK_NOT_FOUND")).route({
931
1174
  method: "GET",
932
1175
  path: "/ebooks/{id}/download-url",
933
1176
  summary: "Get a presigned download URL for an ebook",
934
1177
  tags: ["Ebooks"]
935
1178
  }).input(ebookGetDownloadUrlInputSchema).output(ebookGetDownloadUrlOutputSchema),
936
- updateProgress: ebookProcedure.errors(pickPublicErrorMap("EBOOK_BETA_RESTRICTED", "EBOOK_NOT_FOUND")).route({
1179
+ updateProgress: ebookProcedure.errors(pickPublicErrorMap("EBOOK_NOT_FOUND")).route({
937
1180
  method: "PATCH",
938
1181
  path: "/ebooks/{id}/progress",
939
1182
  summary: "Update ebook reading progress",
940
1183
  tags: ["Ebooks"]
941
1184
  }).input(ebookUpdateProgressInputSchema).output(ebookUpdateProgressOutputSchema),
942
- rename: ebookProcedure.errors(pickPublicErrorMap("EBOOK_BETA_RESTRICTED", "EBOOK_NOT_FOUND")).route({
1185
+ rename: ebookProcedure.errors(pickPublicErrorMap("EBOOK_NOT_FOUND")).route({
943
1186
  method: "PATCH",
944
1187
  path: "/ebooks/{id}",
945
1188
  summary: "Rename an ebook",
946
1189
  tags: ["Ebooks"]
947
1190
  }).input(ebookRenameInputSchema).output(ebookRenameOutputSchema),
948
- delete: ebookProcedure.errors(pickPublicErrorMap("EBOOK_BETA_RESTRICTED", "EBOOK_NOT_FOUND")).route({
1191
+ delete: ebookProcedure.errors(pickPublicErrorMap("EBOOK_NOT_FOUND")).route({
949
1192
  method: "DELETE",
950
1193
  path: "/ebooks/{id}",
951
1194
  summary: "Delete an ebook",
952
1195
  tags: ["Ebooks"]
953
1196
  }).input(ebookDeleteInputSchema).output(ebookDeleteOutputSchema)
954
1197
  };
955
- //#endregion
956
- //#region src/schemas/email-preferences.ts
1198
+ // src/schemas/email-preferences.ts
957
1199
  /** A category's key, such as `promotions`. */
958
1200
  const emailCategoryKeySchema = z.string().max(64).regex(/^[a-z][a-z0-9_]*$/);
959
1201
  /** The token in an email's unsubscribe link. */
@@ -966,9 +1208,34 @@ const emailCategoryStateSchema = z.object({
966
1208
  required: z.boolean(),
967
1209
  subscribed: z.boolean()
968
1210
  }).strict();
1211
+ /**
1212
+ * The category whose emails a person can time: Practice reminders, seeded as
1213
+ * `practice` (packages/db's migration 0067). The settings page shows the
1214
+ * time under its switch.
1215
+ */
1216
+ const PRACTICE_REMINDER_CATEGORY_KEY = "practice";
1217
+ /**
1218
+ * When practice reminders reach someone who never chose a time: 18:00 in
1219
+ * their own time zone. The page shows it as the choice until one is made;
1220
+ * Ribbit's reminder automation sets the same as its own time, for people
1221
+ * without one (docs/ribbit/phase-3-automations.md).
1222
+ */
1223
+ const PRACTICE_REMINDER_DEFAULT_TIME = "18:00";
1224
+ /** A time of day on the hour, `HH:00`: Ribbit takes people into a schedule once an hour. */
1225
+ const practiceReminderTimeSchema = z.string().regex(/^([01]\d|2[0-3]):00$/, "Choose a time on the hour.");
1226
+ /** The times the page offers: every hour of the day. */
1227
+ const PRACTICE_REMINDER_TIMES = Array.from({ length: 24 }, (_, hour) => `${String(hour).padStart(2, "0")}:00`);
1228
+ /**
1229
+ * The reminders area of `user_preferences`, as the database holds it: what
1230
+ * is not there, or no longer reads, is the default. `practiceTime` is the
1231
+ * practice reminder's time of day, in the person's own zone; null until they
1232
+ * choose one.
1233
+ */
1234
+ const remindersPreferencesSchema = z.object({ practiceTime: practiceReminderTimeSchema.nullable().catch(null).default(null) });
969
1235
  const emailPreferencesStateSchema = z.object({
970
1236
  categories: z.array(emailCategoryStateSchema),
971
- unsubscribedAll: z.boolean()
1237
+ unsubscribedAll: z.boolean(),
1238
+ practiceReminderTime: practiceReminderTimeSchema.nullable()
972
1239
  }).strict();
973
1240
  /**
974
1241
  * What the page a link opens shows on top of the state: whose preferences they
@@ -981,7 +1248,8 @@ const emailPreferencesByTokenStateSchema = z.object({
981
1248
  }).strict();
982
1249
  const emailPreferencesChangesShape = {
983
1250
  categories: z.record(emailCategoryKeySchema, z.boolean()).optional(),
984
- unsubscribedAll: z.boolean().optional()
1251
+ unsubscribedAll: z.boolean().optional(),
1252
+ practiceReminderTime: practiceReminderTimeSchema.nullable().optional()
985
1253
  };
986
1254
  const emailPreferencesGetInputSchema = z.object({ locale: appLocaleSchema }).strict();
987
1255
  const emailPreferencesUpdateInputSchema = z.object({
@@ -997,8 +1265,7 @@ const emailPreferencesUpdateByTokenInputSchema = z.object({
997
1265
  locale: appLocaleSchema,
998
1266
  ...emailPreferencesChangesShape
999
1267
  }).strict();
1000
- //#endregion
1001
- //#region src/contracts/email-preferences.ts
1268
+ // src/contracts/email-preferences.ts
1002
1269
  const emailPreferencesContract = {
1003
1270
  get: oc.route({
1004
1271
  method: "GET",
@@ -1025,26 +1292,29 @@ const emailPreferencesContract = {
1025
1292
  tags: ["Email preferences"]
1026
1293
  }).errors(pickPublicErrorMap("EMAIL_LINK_INVALID")).input(emailPreferencesUpdateByTokenInputSchema).output(emailPreferencesByTokenStateSchema)
1027
1294
  };
1028
- //#endregion
1029
- //#region src/schemas/feature-access.ts
1295
+ // src/schemas/feature-access.ts
1030
1296
  const GatedFeatureKeySchema = z.enum(GATED_FEATURE_KEYS);
1031
1297
  const FeatureAccessStatusInputSchema = z.object({ featureKey: GatedFeatureKeySchema }).strict();
1032
1298
  const FeatureAccessStatusOutputSchema = z.object({
1033
1299
  featureKey: GatedFeatureKeySchema,
1034
1300
  allowed: z.boolean()
1035
1301
  });
1036
- //#endregion
1037
- //#region src/contracts/feature-access.ts
1302
+ // src/contracts/feature-access.ts
1038
1303
  const featureAccessContract = { status: oc.route({
1039
1304
  method: "GET",
1040
1305
  path: "/feature-access/status",
1041
1306
  summary: "Get whether the caller can use a gated feature",
1042
1307
  tags: ["Feature Access"]
1043
1308
  }).input(FeatureAccessStatusInputSchema).output(FeatureAccessStatusOutputSchema) };
1044
- //#endregion
1045
- //#region src/contracts/hosted-ai.ts
1309
+ // src/contracts/hosted-ai.ts
1046
1310
  const hostedAiStreamErrors = pickPublicErrorMap("HOSTED_AI_TIER_RESTRICTED", "HOSTED_AI_QUOTA_EXHAUSTED");
1047
1311
  const hostedAiContract = {
1312
+ pools: oc.route({
1313
+ method: "GET",
1314
+ path: "/hosted-ai/pools",
1315
+ summary: "Get shared Built-in AI credit pools for a feature",
1316
+ tags: ["Hosted AI"]
1317
+ }).input(HostedAiCreditPoolsInputSchema).output(HostedAiCreditPoolsOutputSchema),
1048
1318
  status: oc.route({
1049
1319
  method: "GET",
1050
1320
  path: "/hosted-ai/status",
@@ -1109,8 +1379,7 @@ const hostedAiContract = {
1109
1379
  tags: ["Hosted AI"]
1110
1380
  }).input(HostedAiNoteSuggestionStreamInputSchema).output(eventIterator(HostedAiStreamPartSchema)).errors(hostedAiStreamErrors) }
1111
1381
  };
1112
- //#endregion
1113
- //#region src/schemas/mastery-goal.ts
1382
+ // src/schemas/mastery-goal.ts
1114
1383
  const MASTERY_GOAL_TARGET_MAX = 1e6;
1115
1384
  /** How many mastered cards to aim for: the cards `stats.srsMemoryGrowth` counts. */
1116
1385
  const masteryGoalTargetSchema = z.number().int().min(1).max(MASTERY_GOAL_TARGET_MAX);
@@ -1118,8 +1387,7 @@ const masteryGoalTargetSchema = z.number().int().min(1).max(MASTERY_GOAL_TARGET_
1118
1387
  const masteryGoalUpdateInputSchema = z.object({ target: masteryGoalTargetSchema.nullable() }).strict();
1119
1388
  /** The goal's target, or `null` while none is set. */
1120
1389
  const masteryGoalOutputSchema = z.object({ target: masteryGoalTargetSchema.nullable() }).strict();
1121
- //#endregion
1122
- //#region src/contracts/mastery-goal.ts
1390
+ // src/contracts/mastery-goal.ts
1123
1391
  const masteryGoalContract = {
1124
1392
  get: oc.route({
1125
1393
  method: "GET",
@@ -1134,8 +1402,7 @@ const masteryGoalContract = {
1134
1402
  tags: ["Goals"]
1135
1403
  }).input(masteryGoalUpdateInputSchema).output(masteryGoalOutputSchema)
1136
1404
  };
1137
- //#endregion
1138
- //#region src/schemas/mcp-connection.ts
1405
+ // src/schemas/mcp-connection.ts
1139
1406
  const mcpConnectionSchema = z.object({
1140
1407
  /** OAuth client identifier. For a CIMD client this is an https URL. */
1141
1408
  clientId: z.string(),
@@ -1155,8 +1422,20 @@ const mcpConnectionSchema = z.object({
1155
1422
  const mcpConnectionListOutputSchema = z.array(mcpConnectionSchema);
1156
1423
  const mcpConnectionRevokeInputSchema = z.object({ clientId: z.string().min(1) }).strict();
1157
1424
  const mcpConnectionRevokeOutputSchema = z.object({ clientId: z.string() }).strict();
1158
- //#endregion
1159
- //#region src/contracts/mcp-connection.ts
1425
+ /**
1426
+ * How many MCP tool calls the caller has used of their plan's
1427
+ * `MCP_DAILY_CALL_LIMITS`, read without counting one. The window is 24 hours
1428
+ * from the first call in it, not a calendar day.
1429
+ */
1430
+ const mcpCallUsageSchema = z.object({
1431
+ /** Calls used in the current window, at most `limit`. */
1432
+ usedCalls: z.number().int().min(0),
1433
+ /** null: the plan has no daily limit. */
1434
+ limit: z.number().int().positive().nullable(),
1435
+ /** When the current 24-hour window ends; null when no window is open or there is no limit. */
1436
+ resetAt: z.iso.datetime().nullable()
1437
+ }).strict();
1438
+ // src/contracts/mcp-connection.ts
1160
1439
  const mcpConnectionContract = {
1161
1440
  list: oc.route({
1162
1441
  method: "GET",
@@ -1169,10 +1448,95 @@ const mcpConnectionContract = {
1169
1448
  path: "/mcp-connections/revoke",
1170
1449
  summary: "Withdraw a client's authorization and revoke its tokens",
1171
1450
  tags: ["MCP Connections"]
1172
- }).input(mcpConnectionRevokeInputSchema).output(mcpConnectionRevokeOutputSchema)
1451
+ }).input(mcpConnectionRevokeInputSchema).output(mcpConnectionRevokeOutputSchema),
1452
+ usage: oc.route({
1453
+ method: "GET",
1454
+ path: "/mcp-connections/usage",
1455
+ summary: "Get the MCP tool calls the caller has used of their plan's daily limit",
1456
+ tags: ["MCP Connections"]
1457
+ }).input(z.object({}).strict()).output(mcpCallUsageSchema)
1458
+ };
1459
+ // src/schemas/media.ts
1460
+ const mediaContentTypeSchema = z.enum(MEDIA_CONTENT_TYPES);
1461
+ const mediaAssetStatusSchema = z.enum(MEDIA_ASSET_STATUS_VALUES);
1462
+ /** Why the worker rejected an upload. */
1463
+ const mediaFailureCodeSchema = z.enum([
1464
+ "unsupported_format",
1465
+ "invalid_file",
1466
+ "file_too_large",
1467
+ "image_too_large",
1468
+ "audio_too_long",
1469
+ "quota_exceeded",
1470
+ "processing_failed"
1471
+ ]);
1472
+ const mediaAssetMetadataSchema = z.discriminatedUnion("kind", [z.object({
1473
+ kind: z.literal("image"),
1474
+ width: z.number().int(),
1475
+ height: z.number().int()
1476
+ }).strict(), z.object({
1477
+ kind: z.literal("audio"),
1478
+ durationMs: z.number().int()
1479
+ }).strict()]);
1480
+ const mediaAssetSchema = z.object({
1481
+ id: z.uuid(),
1482
+ /** What a cell stores to reference the asset; null until it is ready. */
1483
+ uri: z.string().nullable(),
1484
+ status: mediaAssetStatusSchema,
1485
+ contentType: z.string().nullable(),
1486
+ fileByteSize: z.number().int(),
1487
+ metadata: mediaAssetMetadataSchema.nullable(),
1488
+ failureCode: mediaFailureCodeSchema.nullable(),
1489
+ createdAt: z.coerce.date()
1490
+ }).strict();
1491
+ const mediaRequestUploadInputSchema = z.object({
1492
+ contentType: mediaContentTypeSchema,
1493
+ byteSize: z.number().int().min(1)
1494
+ }).strict();
1495
+ const mediaRequestUploadOutputSchema = z.object({
1496
+ assetId: z.uuid(),
1497
+ /** A signed PUT: send the file to `url` with exactly `headers`. */
1498
+ upload: z.object({
1499
+ url: z.url(),
1500
+ headers: z.record(z.string(), z.string())
1501
+ }).strict(),
1502
+ expiresAt: z.coerce.date()
1503
+ }).strict();
1504
+ const mediaAssetIdInputSchema = z.object({ id: z.uuid() }).strict();
1505
+ const mediaAssetOutputSchema = z.object({ asset: mediaAssetSchema }).strict();
1506
+ const mediaUsageOutputSchema = z.object({
1507
+ usedBytes: z.number().int().min(0),
1508
+ /** Held by uploads that are not done yet. */
1509
+ reservedBytes: z.number().int().min(0),
1510
+ limitBytes: z.number().int().min(0)
1511
+ }).strict();
1512
+ // src/contracts/media.ts
1513
+ const mediaContract = {
1514
+ requestUpload: oc.errors(pickPublicErrorMap("MEDIA_BETA_RESTRICTED", "MEDIA_FILE_TOO_LARGE", "MEDIA_QUOTA_EXCEEDED")).route({
1515
+ method: "POST",
1516
+ path: "/media/uploads",
1517
+ summary: "Reserve space and get a signed upload URL for a media file",
1518
+ tags: ["Media"]
1519
+ }).input(mediaRequestUploadInputSchema).output(mediaRequestUploadOutputSchema),
1520
+ completeUpload: oc.errors(pickPublicErrorMap("MEDIA_BETA_RESTRICTED", "MEDIA_NOT_FOUND", "MEDIA_UPLOAD_NOT_COMPLETED")).route({
1521
+ method: "POST",
1522
+ path: "/media/{id}/complete",
1523
+ summary: "Queue an uploaded media file for validation",
1524
+ tags: ["Media"]
1525
+ }).input(mediaAssetIdInputSchema).output(mediaAssetOutputSchema),
1526
+ get: oc.errors(pickPublicErrorMap("MEDIA_BETA_RESTRICTED", "MEDIA_NOT_FOUND")).route({
1527
+ method: "GET",
1528
+ path: "/media/{id}",
1529
+ summary: "Get a media asset and its upload status",
1530
+ tags: ["Media"]
1531
+ }).input(mediaAssetIdInputSchema).output(mediaAssetOutputSchema),
1532
+ usage: oc.errors(pickPublicErrorMap("MEDIA_BETA_RESTRICTED")).route({
1533
+ method: "GET",
1534
+ path: "/media/usage",
1535
+ summary: "Get the media space used, reserved and allowed",
1536
+ tags: ["Media"]
1537
+ }).input(z.object({}).strict()).output(mediaUsageOutputSchema)
1173
1538
  };
1174
- //#endregion
1175
- //#region src/schemas/notebase-column.ts
1539
+ // src/schemas/notebase-column.ts
1176
1540
  const notebaseColumnWidthSchema = z.number().int().min(NOTEBASE_COLUMN_MIN_WIDTH).max(NOTEBASE_COLUMN_MAX_WIDTH);
1177
1541
  const notebaseColumnSchema = z.object({
1178
1542
  id: z.string(),
@@ -1221,8 +1585,7 @@ const NotebaseColumnReorderInputSchema = z.object({
1221
1585
  ids: z.array(z.uuid())
1222
1586
  });
1223
1587
  const NotebaseColumnReorderOutputSchema = z.object({ txid: z.number() });
1224
- //#endregion
1225
- //#region src/schemas/notebase-row.ts
1588
+ // src/schemas/notebase-row.ts
1226
1589
  const notebaseRowCellsSchema = z.record(z.string(), z.unknown());
1227
1590
  const notebaseRowSchema = z.object({
1228
1591
  id: z.string(),
@@ -1345,8 +1708,7 @@ const NotebaseRowListInputSchema = z.object({
1345
1708
  const NotebaseRowListOutputSchema = pageSchema(notebaseRowSchema);
1346
1709
  const NotebaseRowGetInputSchema = z.object({ id: z.uuid() });
1347
1710
  const NotebaseRowGetOutputSchema = notebaseRowSchema;
1348
- //#endregion
1349
- //#region src/schemas/notebase-view.ts
1711
+ // src/schemas/notebase-view.ts
1350
1712
  const notebaseViewTypeSchema = z.enum([
1351
1713
  "table",
1352
1714
  "kanban",
@@ -1395,8 +1757,7 @@ const notebaseViewSchema = z.object({
1395
1757
  createdAt: z.coerce.date(),
1396
1758
  updatedAt: z.coerce.date()
1397
1759
  });
1398
- //#endregion
1399
- //#region src/schemas/notebase.ts
1760
+ // src/schemas/notebase.ts
1400
1761
  const NotebaseListInputSchema = z.object({});
1401
1762
  const notebaseSummarySchema = z.object({
1402
1763
  id: z.string(),
@@ -1420,6 +1781,7 @@ const notebaseSchema = z.object({
1420
1781
  srsWeights: srsWeightsSchema.nullable(),
1421
1782
  srsModelVersion: srsModelVersionSchema,
1422
1783
  srsSleepingAt: z.date().nullable(),
1784
+ srsSleepSource: srsSleepSourceSchema.nullable(),
1423
1785
  createdAt: z.date(),
1424
1786
  updatedAt: z.date()
1425
1787
  });
@@ -1509,8 +1871,7 @@ const NotebaseGetSchemaOutputSchema = z.object({
1509
1871
  updatedAt: z.coerce.date(),
1510
1872
  notebaseColumns: z.array(notebaseColumnSchema)
1511
1873
  });
1512
- //#endregion
1513
- //#region src/contracts/notebase.ts
1874
+ // src/contracts/notebase.ts
1514
1875
  const notebaseContract = {
1515
1876
  list: defineAgentProcedure({
1516
1877
  method: "GET",
@@ -1568,8 +1929,7 @@ const notebaseContract = {
1568
1929
  tags: ["Notebases"]
1569
1930
  }).errors(pickPublicErrorMap("NOTEBASE_NOT_FOUND")).input(NotebaseDeleteInputSchema).output(NotebaseDeleteOutputSchema)
1570
1931
  };
1571
- //#endregion
1572
- //#region src/contracts/notebase-column.ts
1932
+ // src/contracts/notebase-column.ts
1573
1933
  const notebaseColumnContract = {
1574
1934
  create: defineAgentProcedure({
1575
1935
  method: "POST",
@@ -1589,7 +1949,7 @@ const notebaseColumnContract = {
1589
1949
  method: "DELETE",
1590
1950
  path: "/notebase-columns/{notebaseColumnId}",
1591
1951
  summary: "Delete notebase field",
1592
- description: "Delete an owned field and remove its values from notes. Primary fields and fields referenced by templates cannot be deleted.",
1952
+ description: "Delete an owned field and remove its values from notes. Primary fields cannot be deleted, nor can a field a template references: one a columns face lists, or a layout face names as {{ [\"<column id>\"] }}. A layout that loops over ctx.fields, as the default dictionary template's back does to show every other filled field, references none of them, so those can be deleted and simply leave the card.",
1593
1953
  tags: ["Notebase Columns"]
1594
1954
  }).errors(pickPublicErrorMap("NOTEBASE_COLUMN_NOT_FOUND", "PRIMARY_NOTEBASE_COLUMN_DELETE_NOT_ALLOWED", "CARD_TEMPLATE_NOTEBASE_COLUMN_IN_USE", "CONCURRENT_POSITION_CONFLICT")).input(NotebaseColumnDeleteInputSchema).output(NotebaseColumnDeleteOutputSchema),
1595
1955
  reorder: oc.errors(pickPublicErrorMap("NOTEBASE_NOT_FOUND", "CONCURRENT_POSITION_CONFLICT")).route({
@@ -1599,8 +1959,7 @@ const notebaseColumnContract = {
1599
1959
  tags: ["Notebase Columns"]
1600
1960
  }).input(NotebaseColumnReorderInputSchema).output(NotebaseColumnReorderOutputSchema)
1601
1961
  };
1602
- //#endregion
1603
- //#region src/contracts/notebase-row.ts
1962
+ // src/contracts/notebase-row.ts
1604
1963
  const notebaseRowContract = {
1605
1964
  list: defineAgentProcedure({
1606
1965
  method: "GET",
@@ -1665,8 +2024,65 @@ const notebaseRowContract = {
1665
2024
  tags: ["Notebase Rows"]
1666
2025
  }).input(NotebaseRowReorderInputSchema).output(NotebaseRowReorderOutputSchema)
1667
2026
  };
1668
- //#endregion
1669
- //#region src/schemas/speech.ts
2027
+ // src/contracts/pdf-translation.ts
2028
+ const pdfTranslationProcedure = oc.errors(pickPublicErrorMap("PDF_TRANSLATION_UNAVAILABLE"));
2029
+ const pdfTranslationContract = {
2030
+ status: pdfTranslationProcedure.route({
2031
+ method: "GET",
2032
+ path: "/pdf-translations/status",
2033
+ summary: "How many free PDF translations the account has left",
2034
+ tags: ["PDF Translation"]
2035
+ }).input(pdfTranslationStatusInputSchema).output(pdfTranslationStatusOutputSchema),
2036
+ list: pdfTranslationProcedure.route({
2037
+ method: "GET",
2038
+ path: "/pdf-translations",
2039
+ summary: "List recent PDF translations",
2040
+ tags: ["PDF Translation"]
2041
+ }).input(pdfTranslationListInputSchema).output(pdfTranslationListOutputSchema),
2042
+ requestUpload: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_FILE_TOO_LARGE")).route({
2043
+ method: "POST",
2044
+ path: "/pdf-translations/uploads",
2045
+ summary: "Request a signed upload for a PDF to translate",
2046
+ tags: ["PDF Translation"]
2047
+ }).input(pdfTranslationRequestUploadInputSchema).output(pdfTranslationRequestUploadOutputSchema),
2048
+ submit: pdfTranslationProcedure.errors(pickPublicErrorMap("HOSTED_AI_TIER_RESTRICTED", "PDF_TRANSLATION_UPLOAD_NOT_FOUND", "PDF_TRANSLATION_UPLOAD_EXPIRED", "PDF_TRANSLATION_UPLOAD_NOT_COMPLETED", "PDF_TRANSLATION_FILE_TOO_LARGE", "PDF_TRANSLATION_INVALID_PDF", "PDF_TRANSLATION_ALREADY_TRANSLATED", "PDF_TRANSLATION_PAGE_LIMIT_EXCEEDED", "PDF_TRANSLATION_QUEUE_FULL", "PDF_TRANSLATION_IDEMPOTENCY_CONFLICT", "PDF_TRANSLATION_INSUFFICIENT_CREDIT")).route({
2049
+ method: "POST",
2050
+ path: "/pdf-translations",
2051
+ summary: "Translate uploaded PDFs",
2052
+ tags: ["PDF Translation"]
2053
+ }).input(pdfTranslationSubmitInputSchema).output(pdfTranslationSubmitOutputSchema),
2054
+ get: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_NOT_FOUND")).route({
2055
+ method: "GET",
2056
+ path: "/pdf-translations/{id}",
2057
+ summary: "Get a PDF translation's status, with the others submitted with it",
2058
+ tags: ["PDF Translation"]
2059
+ }).input(pdfTranslationJobIdInputSchema).output(pdfTranslationGetOutputSchema),
2060
+ cancel: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_NOT_FOUND", "PDF_TRANSLATION_NOT_CANCELLABLE")).route({
2061
+ method: "POST",
2062
+ path: "/pdf-translations/{id}/cancel",
2063
+ summary: "Cancel a PDF translation",
2064
+ tags: ["PDF Translation"]
2065
+ }).input(pdfTranslationJobIdInputSchema).output(pdfTranslationJobResourceSchema),
2066
+ getPreviewUrl: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_NOT_FOUND", "PDF_TRANSLATION_NOT_READY")).route({
2067
+ method: "GET",
2068
+ path: "/pdf-translations/{id}/preview-url",
2069
+ summary: "Get a short-lived URL to read a translated PDF in the browser",
2070
+ tags: ["PDF Translation"]
2071
+ }).input(pdfTranslationOutputInputSchema).output(pdfTranslationPreviewOutputSchema),
2072
+ getDownloadUrl: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_NOT_FOUND", "PDF_TRANSLATION_NOT_READY", "PDF_TRANSLATION_DOWNLOAD_RESTRICTED")).route({
2073
+ method: "GET",
2074
+ path: "/pdf-translations/{id}/download-url",
2075
+ summary: "Get a download URL for a translated PDF",
2076
+ tags: ["PDF Translation"]
2077
+ }).input(pdfTranslationOutputInputSchema).output(pdfTranslationDownloadOutputSchema),
2078
+ delete: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_NOT_FOUND", "PDF_TRANSLATION_NOT_DELETABLE")).route({
2079
+ method: "DELETE",
2080
+ path: "/pdf-translations/{id}",
2081
+ summary: "Delete a finished PDF translation and its files",
2082
+ tags: ["PDF Translation"]
2083
+ }).input(pdfTranslationJobIdInputSchema).output(pdfTranslationDeleteOutputSchema)
2084
+ };
2085
+ // src/schemas/speech.ts
1670
2086
  /** The longest text one request reads aloud. */
1671
2087
  const SPEECH_TEXT_MAX_LENGTH = 500;
1672
2088
  /**
@@ -1740,8 +2156,7 @@ const speechSynthesizeOutputSchema = z.object({
1740
2156
  url: z.url(),
1741
2157
  expiresAt: z.coerce.date()
1742
2158
  }).strict();
1743
- //#endregion
1744
- //#region src/contracts/speech.ts
2159
+ // src/contracts/speech.ts
1745
2160
  const speechContract = {
1746
2161
  getPreferences: oc.route({
1747
2162
  method: "GET",
@@ -1768,8 +2183,7 @@ const speechContract = {
1768
2183
  tags: ["Speech"]
1769
2184
  }).input(speechSynthesizeInputSchema).output(speechSynthesizeOutputSchema)
1770
2185
  };
1771
- //#endregion
1772
- //#region src/schemas/timezone.ts
2186
+ // src/schemas/timezone.ts
1773
2187
  const timezoneFormatters = /* @__PURE__ */ new Map();
1774
2188
  function toCacheKey(timezone) {
1775
2189
  return timezone.replace(/[A-Z]/g, (letter) => letter.toLowerCase());
@@ -1812,8 +2226,7 @@ const canonicalTimezoneSchema = timezoneSchema.transform((timezone, ctx) => {
1812
2226
  }
1813
2227
  return name;
1814
2228
  });
1815
- //#endregion
1816
- //#region src/schemas/srs.ts
2229
+ // src/schemas/srs.ts
1817
2230
  const stepSchema = srsStepSchema;
1818
2231
  const SRS_REVIEW_CLIENT_ID_NAMESPACE = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
1819
2232
  const srsReviewClientIdNamePrefix = "readfrog:srs-review";
@@ -1879,7 +2292,7 @@ const srsListCardRevlogsOutputSchema = z.object({
1879
2292
  const srsReviewOutputSchema = z.object({
1880
2293
  card: cardSchema,
1881
2294
  revlog: srsRevlogSchema,
1882
- txid: z.number(),
2295
+ txid: z.number().nullable(),
1883
2296
  created: z.boolean()
1884
2297
  });
1885
2298
  const srsRollbackReviewOutputSchema = z.object({
@@ -1933,8 +2346,123 @@ function bytesToUuid(bytes) {
1933
2346
  hex.slice(10, 16).join("")
1934
2347
  ].join("-");
1935
2348
  }
1936
- //#endregion
1937
- //#region src/contracts/srs.ts
2349
+ const count = z.number().int().nonnegative();
2350
+ const srsBacklogStatsInputSchema = z.object({
2351
+ notebaseIds: z.array(z.uuid()).optional(),
2352
+ timezone: canonicalTimezoneSchema
2353
+ }).strict();
2354
+ /**
2355
+ * An Awake notebase with a positive daily review limit whose overdue reviews
2356
+ * fill at least `BACKLOG_PROMPT_DAYS.badge` days.
2357
+ */
2358
+ const srsBacklogStatsSchema = z.object({
2359
+ overdueReviewCount: count.describe("Review cards whose due date is before the start of today's study day."),
2360
+ dailyLimit: z.number().int().positive().describe("The notebase's own daily review limit, which the backlog is measured against. Always positive: a notebase with no daily reviews (0) or an unlimited limit (-1) is never listed."),
2361
+ backlogDays: z.number().nonnegative().describe("Days of reviews the backlog fills at that limit: overdueReviewCount / dailyLimit.")
2362
+ });
2363
+ /** Only the notebases that get the badge; the rest are absent. */
2364
+ const srsBacklogStatsOutputSchema = z.record(z.uuid(), srsBacklogStatsSchema);
2365
+ const rescheduleDailyLimitSchema = z.number().int().positive();
2366
+ const srsPreviewPostponeInputSchema = z.object({
2367
+ notebaseId: z.uuid(),
2368
+ timezone: canonicalTimezoneSchema,
2369
+ dailyLimit: rescheduleDailyLimitSchema.optional(),
2370
+ flattenFullRange: z.boolean().optional().describe("Flatten levels every plannable day (180) instead of only the chart days.")
2371
+ }).strict();
2372
+ const postponeThresholdSchema = z.number().min(POSTPONE_DAMAGE_THRESHOLD.min).max(POSTPONE_DAMAGE_THRESHOLD.max);
2373
+ const postponeDaySchema = z.object({
2374
+ day: z.number().int().positive(),
2375
+ postponed: count,
2376
+ rSum: z.number()
2377
+ });
2378
+ const rescheduleBaselineDaySchema = z.object({
2379
+ day: z.number().int().positive(),
2380
+ scheduled: count,
2381
+ rSum: z.number().nullable()
2382
+ });
2383
+ const spreadDaySchema = z.object({
2384
+ day: count,
2385
+ scheduled: count,
2386
+ backlog: count,
2387
+ backlogRSum: z.number(),
2388
+ surplusIn: count,
2389
+ surplusRSum: z.number(),
2390
+ surplusStay: count,
2391
+ surplusOut: count
2392
+ });
2393
+ const spreadKeptSchema = z.object({
2394
+ stuck: count,
2395
+ noRoom: count
2396
+ });
2397
+ const flattenStepSchema = z.object({
2398
+ checked: z.boolean(),
2399
+ fromToday: count,
2400
+ fromFuture: count,
2401
+ fromDays: count,
2402
+ kept: spreadKeptSchema,
2403
+ qSuggest: count,
2404
+ meanRAfter: z.number(),
2405
+ days: z.array(spreadDaySchema),
2406
+ /** Cards Postpone already moved that this Flatten moves again, and their R under Postpone. */
2407
+ postponedAgain: z.object({
2408
+ count,
2409
+ rSum: z.number()
2410
+ })
2411
+ });
2412
+ /** One threshold's Postpone alone, before its Flatten option is attached. */
2413
+ const postponeSummarySchema = z.object({
2414
+ threshold: postponeThresholdSchema,
2415
+ moved: count,
2416
+ overflowToday: count,
2417
+ meanRiBefore: z.number(),
2418
+ meanRAfter: z.number(),
2419
+ days: z.array(postponeDaySchema)
2420
+ });
2421
+ const postponeStepSchema = postponeSummarySchema.extend({ flatten: flattenStepSchema.nullable() });
2422
+ const postponePlanSchema = z.object({
2423
+ planId: z.string(),
2424
+ limit: z.number().int().positive(),
2425
+ steps: z.array(postponeStepSchema),
2426
+ skipped: z.object({
2427
+ belowFloor: count,
2428
+ maxInterval: count,
2429
+ invalid: count
2430
+ })
2431
+ });
2432
+ const rescheduleReadySchema = z.object({
2433
+ status: z.literal("ready"),
2434
+ expiresAt: z.date(),
2435
+ q: z.number().int().positive(),
2436
+ qConfigured: schedulingParamsShape.reviewsPerDay,
2437
+ qMax: z.number().int().positive(),
2438
+ overdueReviewCount: count,
2439
+ dueTodayReviewCount: count,
2440
+ usedToday: count
2441
+ });
2442
+ const srsPreviewPostponeOutputSchema = z.discriminatedUnion("status", [
2443
+ rescheduleReadySchema.extend({
2444
+ plan: postponePlanSchema,
2445
+ suggested: postponePlanSchema.nullable(),
2446
+ baseline: z.array(rescheduleBaselineDaySchema)
2447
+ }),
2448
+ z.object({ status: z.literal("quotaZero") }),
2449
+ z.object({ status: z.literal("invalidWeights") })
2450
+ ]);
2451
+ const srsApplyPostponeInputSchema = z.object({
2452
+ notebaseId: z.uuid(),
2453
+ planId: z.string().min(1),
2454
+ unlimited: z.boolean().optional()
2455
+ }).extend({
2456
+ threshold: postponeThresholdSchema,
2457
+ flatten: z.boolean().optional()
2458
+ }).strict();
2459
+ const srsRescheduleApplyOutputSchema = z.object({
2460
+ moved: count,
2461
+ txid: z.number().nullable(),
2462
+ reviewsPerDay: schedulingParamsShape.reviewsPerDay
2463
+ });
2464
+ const srsApplyPostponeOutputSchema = srsRescheduleApplyOutputSchema;
2465
+ // src/contracts/srs.ts
1938
2466
  const srsContract = {
1939
2467
  scheduleStatusStats: defineAgentProcedure({
1940
2468
  method: "GET",
@@ -1996,10 +2524,21 @@ const srsContract = {
1996
2524
  summary: "Set card suspended",
1997
2525
  description: "Suspend or resume one owned card. enabled=true suspends and enabled=false resumes it. Existing state-change rules apply.",
1998
2526
  tags: ["SRS"]
1999
- }).errors(pickPublicErrorMap("CARD_NOT_FOUND", "CARD_ALREADY_SUSPENDED", "CARD_NOT_SUSPENDED", "CARD_STATUS_CHANGE_UNAVAILABLE")).input(srsSetCardSuspendedInputSchema).output(srsSetCardSuspendedOutputSchema)
2527
+ }).errors(pickPublicErrorMap("CARD_NOT_FOUND", "CARD_ALREADY_SUSPENDED", "CARD_NOT_SUSPENDED", "CARD_STATUS_CHANGE_UNAVAILABLE")).input(srsSetCardSuspendedInputSchema).output(srsSetCardSuspendedOutputSchema),
2528
+ previewPostpone: oc.errors(pickPublicErrorMap("NOTEBASE_NOT_FOUND", "RESCHEDULE_PREVIEW_TIMEOUT", "RESCHEDULE_DAILY_LIMIT_INVALID")).route({
2529
+ method: "POST",
2530
+ path: "/srs/postpone/preview",
2531
+ summary: "Preview postpone",
2532
+ tags: ["SRS"]
2533
+ }).input(srsPreviewPostponeInputSchema).output(srsPreviewPostponeOutputSchema),
2534
+ applyPostpone: oc.errors(pickPublicErrorMap("NOTEBASE_NOT_FOUND", "RESCHEDULE_PLAN_EXPIRED", "RESCHEDULE_STALE")).route({
2535
+ method: "POST",
2536
+ path: "/srs/postpone",
2537
+ summary: "Apply postpone",
2538
+ tags: ["SRS"]
2539
+ }).input(srsApplyPostponeInputSchema).output(srsApplyPostponeOutputSchema)
2000
2540
  };
2001
- //#endregion
2002
- //#region src/schemas/notebase-stats.ts
2541
+ // src/schemas/notebase-stats.ts
2003
2542
  const notebaseActivityStatsItemSchema = z.object({
2004
2543
  date: z.iso.date(),
2005
2544
  notes: z.number().int().nonnegative()
@@ -2013,8 +2552,7 @@ const notebaseRowGrowthStatsOutputSchema = z.object({
2013
2552
  baseTotal: z.number().int().nonnegative(),
2014
2553
  daily: z.array(notebaseRowGrowthStatsItemSchema)
2015
2554
  }).strict();
2016
- //#endregion
2017
- //#region src/schemas/srs-stats.ts
2555
+ // src/schemas/srs-stats.ts
2018
2556
  const srsActivityStatsItemSchema = z.object({
2019
2557
  date: z.iso.date(),
2020
2558
  answers: z.number().int().nonnegative(),
@@ -2032,8 +2570,7 @@ const srsMemoryGrowthStatsOutputSchema = z.object({
2032
2570
  baseTotal: z.number().int().nonnegative(),
2033
2571
  daily: z.array(srsMemoryGrowthStatsItemSchema)
2034
2572
  }).strict();
2035
- //#endregion
2036
- //#region src/schemas/stats.ts
2573
+ // src/schemas/stats.ts
2037
2574
  const statsNotebaseIdsSchema = z.array(z.uuid()).min(1).transform((ids) => Array.from(new Set(ids)));
2038
2575
  const statsInputSchema = z.object({
2039
2576
  notebaseIds: statsNotebaseIdsSchema.optional(),
@@ -2048,8 +2585,7 @@ const activityStatsOutputSchema = z.object({
2048
2585
  srs: srsActivityStatsOutputSchema,
2049
2586
  notebase: notebaseActivityStatsOutputSchema
2050
2587
  }).strict();
2051
- //#endregion
2052
- //#region src/contracts/stats.ts
2588
+ // src/contracts/stats.ts
2053
2589
  const statsContract = {
2054
2590
  activity: oc.errors(pickPublicErrorMap("NOTEBASE_NOT_FOUND")).route({
2055
2591
  method: "GET",
@@ -2068,10 +2604,97 @@ const statsContract = {
2068
2604
  path: "/notebases/stats/row-growth",
2069
2605
  summary: "Get notebase row growth statistics",
2070
2606
  tags: ["Statistics"]
2071
- }).input(statsInputSchema).output(notebaseRowGrowthStatsOutputSchema)
2607
+ }).input(statsInputSchema).output(notebaseRowGrowthStatsOutputSchema),
2608
+ backlogStats: defineAgentProcedure({
2609
+ method: "GET",
2610
+ path: "/srs/stats/backlog",
2611
+ summary: "Get review backlogs",
2612
+ description: "Read overdue review backlogs for owned awake notebases in the supplied timezone. Only a notebase whose overdue reviews fill two or more days of its daily review limit is listed; the rest are left out. A notebase whose daily review limit is 0 or unlimited (-1) never returns anything, even when its ID is requested. Does not return note content or card faces.",
2613
+ tags: ["Statistics"]
2614
+ }).errors(pickPublicErrorMap("NOTEBASE_NOT_FOUND")).input(srsBacklogStatsInputSchema).output(srsBacklogStatsOutputSchema)
2072
2615
  };
2073
- //#endregion
2074
- //#region src/schemas/user.ts
2616
+ // src/schemas/web-sync.ts
2617
+ /** The shapes the web app syncs, by their names in `@repo/electric-contract`. */
2618
+ const webSyncShapeSchema = z.enum([
2619
+ "notebases",
2620
+ "notebaseColumns",
2621
+ "notebaseRows",
2622
+ "cardTemplates",
2623
+ "cards",
2624
+ "revlogs",
2625
+ "mediaAssets"
2626
+ ]);
2627
+ /** The write whose change the page waited to see come back over Electric. */
2628
+ const webSyncOperationSchema = z.enum([
2629
+ "review",
2630
+ "reviewReplay",
2631
+ "undo",
2632
+ "bury",
2633
+ "suspend",
2634
+ "deleteNote",
2635
+ "insert",
2636
+ "update",
2637
+ "delete",
2638
+ "setSleep",
2639
+ "srsSettings",
2640
+ "cardStatus",
2641
+ "createTemplate",
2642
+ "updateTemplate"
2643
+ ]);
2644
+ /** How the shape that lagged was receiving live changes. */
2645
+ const webSyncTransportSchema = z.enum(["sse", "longPoll"]);
2646
+ /**
2647
+ * A write wait is only reported once its first wait ran out: `recovered` when
2648
+ * reconnecting the lagging shapes brought the change, `failed` when the page
2649
+ * gave up on it.
2650
+ */
2651
+ const webSyncWriteOutcomeSchema = z.enum(["recovered", "failed"]);
2652
+ const webSyncStreamErrorTypeSchema = z.enum([
2653
+ "unauthorized",
2654
+ "forbidden",
2655
+ "badRequest",
2656
+ "clientError",
2657
+ "missingHeaders",
2658
+ "unexpected"
2659
+ ]);
2660
+ /** `initial` before the shape first loaded, when the page shows the error at once. */
2661
+ const webSyncStreamPhaseSchema = z.enum(["initial", "live"]);
2662
+ const webSyncPageSchema = z.enum(["reviewCombined", "reviewNotebase"]);
2663
+ const webSyncUnavailableReasonSchema = z.enum([
2664
+ "syncTimeout",
2665
+ "streamFailed",
2666
+ "notebaseGone"
2667
+ ]);
2668
+ const webSyncEventSchema = z.discriminatedUnion("type", [
2669
+ z.object({
2670
+ type: z.literal("writeWait"),
2671
+ operation: webSyncOperationSchema,
2672
+ outcome: webSyncWriteOutcomeSchema,
2673
+ transport: webSyncTransportSchema
2674
+ }).strict(),
2675
+ z.object({
2676
+ type: z.literal("streamError"),
2677
+ shape: webSyncShapeSchema,
2678
+ errorType: webSyncStreamErrorTypeSchema,
2679
+ phase: webSyncStreamPhaseSchema
2680
+ }).strict(),
2681
+ z.object({
2682
+ type: z.literal("unavailable"),
2683
+ page: webSyncPageSchema,
2684
+ reason: webSyncUnavailableReasonSchema
2685
+ }).strict()
2686
+ ]);
2687
+ /** A page sends what happened within a second or so as one batch. */
2688
+ const WEB_SYNC_REPORT_MAX_EVENTS = 20;
2689
+ const reportWebSyncInputSchema = z.object({ events: z.array(webSyncEventSchema).min(1).max(20) }).strict();
2690
+ // src/contracts/telemetry.ts
2691
+ const telemetryContract = { reportWebSync: oc.route({
2692
+ method: "POST",
2693
+ path: "/telemetry/web-sync",
2694
+ summary: "Report problems the web app had keeping its synced data live",
2695
+ tags: ["Telemetry"]
2696
+ }).input(reportWebSyncInputSchema).output(z.void()) };
2697
+ // src/schemas/user.ts
2075
2698
  const userEnsureTimezoneInputSchema = z.object({ timezone: timezoneSchema }).strict();
2076
2699
  const userEnsureTimezoneOutputSchema = z.object({
2077
2700
  timezone: timezoneSchema,
@@ -2086,8 +2709,7 @@ const userEnsureLocaleOutputSchema = z.object({
2086
2709
  }).strict();
2087
2710
  const userUpdateLocaleInputSchema = z.object({ locale: appLocaleSchema }).strict();
2088
2711
  const userUpdateLocaleOutputSchema = z.object({ locale: appLocaleSchema }).strict();
2089
- //#endregion
2090
- //#region src/contracts/user.ts
2712
+ // src/contracts/user.ts
2091
2713
  const userContract = {
2092
2714
  ensureTimezone: oc.route({
2093
2715
  method: "POST",
@@ -2114,8 +2736,7 @@ const userContract = {
2114
2736
  tags: ["Users"]
2115
2737
  }).input(userUpdateLocaleInputSchema).output(userUpdateLocaleOutputSchema)
2116
2738
  };
2117
- //#endregion
2118
- //#region src/schemas/video-transcript.ts
2739
+ // src/schemas/video-transcript.ts
2119
2740
  const videoTranscriptStatusSchema = z.enum([
2120
2741
  "pending",
2121
2742
  "processing",
@@ -2160,8 +2781,7 @@ const videoTranscriptUsageSchema = z.object({
2160
2781
  plan: billingPlanSchema,
2161
2782
  pools: z.array(videoTranscriptUsagePoolSchema)
2162
2783
  });
2163
- //#endregion
2164
- //#region src/index.ts
2784
+ // src/index.ts
2165
2785
  const contract = {
2166
2786
  billing: billingContract,
2167
2787
  card: cardContract,
@@ -2172,12 +2792,15 @@ const contract = {
2172
2792
  hostedAi: hostedAiContract,
2173
2793
  masteryGoal: masteryGoalContract,
2174
2794
  mcpConnection: mcpConnectionContract,
2795
+ media: mediaContract,
2175
2796
  notebase: notebaseContract,
2176
2797
  notebaseColumn: notebaseColumnContract,
2177
2798
  notebaseRow: notebaseRowContract,
2799
+ pdfTranslation: pdfTranslationContract,
2178
2800
  speech: speechContract,
2179
2801
  srs: srsContract,
2180
2802
  stats: statsContract,
2803
+ telemetry: telemetryContract,
2181
2804
  user: userContract,
2182
2805
  videoTranscript: {
2183
2806
  create: oc.errors(pickPublicErrorMap("VIDEO_TRANSCRIPTION_QUOTA_EXCEEDED", "VIDEO_TRANSCRIPTION_SUBSCRIPTION_REQUIRED", "VIDEO_TRANSCRIPTION_PAYMENT_REQUIRED", "VIDEO_TRANSCRIPTION_UNSUPPORTED_LENGTH")).route({
@@ -2206,7 +2829,6 @@ const contract = {
2206
2829
  }).input(videoTranscriptGetInputSchema).output(videoTranscriptSubtitlesSchema)
2207
2830
  }
2208
2831
  };
2209
- //#endregion
2210
- export { BILLING_PAYMENT_DUE_TIME_ZONE, CardGenerateInputSchema, CardGenerateOutputSchema, CardGetInputSchema, CardGetOutputSchema, CardListInputSchema, CardListOutputSchema, CardTemplateCreateInputSchema, CardTemplateCreateOutputSchema, CardTemplateDeleteInputSchema, CardTemplateDeleteOutputSchema, CardTemplateGetInputSchema, CardTemplateGetOutputSchema, CardTemplateInvalidColumnsDataSchema, CardTemplateInvalidLayoutDataSchema, CardTemplateListInputSchema, CardTemplateListOutputSchema, CardTemplateNotebaseColumnInUseDataSchema, CardTemplateUpdateInputSchema, CardTemplateUpdateOutputSchema, CellValidationFailedDataSchema, CellValidationFailureDetailsSchema, CellValidationFailureReasonSchema, DEFAULT_SPEECH_PREFERENCES, FeatureAccessStatusInputSchema, FeatureAccessStatusOutputSchema, GatedFeatureKeySchema, HOSTED_AI_CLIENT_STREAM_PART_TYPES, HOSTED_AI_NOTE_SUGGESTION_MAX_NOTES, HOSTED_AI_NOTE_SUGGESTION_MAX_NOTE_FIELDS, HostedAiCreditPeriodKindSchema, HostedAiCreditPolicyIdSchema, HostedAiCreditPoolStatusSchema, HostedAiFeatureSchema, HostedAiFeatureStatusSchema, HostedAiModelTierSchema, HostedAiNoteSuggestionObjectSchema, HostedAiNoteSuggestionStreamInputSchema, HostedAiOneTimeCreditStatusSchema, HostedAiOutputFieldSchema, HostedAiOutputFieldTypeSchema, HostedAiQuotaExhaustedDataSchema, HostedAiQuotaScopeSchema, HostedAiRateLimitErrorDataSchema, HostedAiRecurringCreditStatusSchema, HostedAiRequestIdSchema, HostedAiStatusInputSchema, HostedAiStatusOutputSchema, HostedAiStreamPartSchema, HostedAiStreamStructuredObjectInputSchema, HostedAiStreamTextInputSchema, HostedAiTierRestrictedDataSchema, HostedAiTierStatusSchema, HostedAiUnavailableReasonSchema, HostedAiUpgradePlanSchema, MASTERY_GOAL_TARGET_MAX, MCP_DAILY_CALL_LIMITS, NOTEBASE_ROW_CREATE_MANY_MAX_ROWS, NOTEBASE_ROW_DELETE_MANY_MAX_ROWS, NOTEBASE_ROW_UPDATE_MANY_MAX_ROWS, NotebaseColumnCreateInputSchema, NotebaseColumnCreateOutputSchema, NotebaseColumnDeleteInputSchema, NotebaseColumnDeleteOutputSchema, NotebaseColumnReorderInputSchema, NotebaseColumnReorderOutputSchema, NotebaseColumnUpdateInputSchema, NotebaseColumnUpdateOutputSchema, NotebaseCreateInputSchema, NotebaseCreateOutputSchema, NotebaseDeleteInputSchema, NotebaseDeleteOutputSchema, NotebaseGetInputSchema, NotebaseGetOutputSchema, NotebaseGetSchemaInputSchema, NotebaseGetSchemaOutputSchema, NotebaseGetSummaryInputSchema, NotebaseGetSummaryOutputSchema, NotebaseListInputSchema, NotebaseListItemSchema, NotebaseListOutputSchema, NotebaseRowCreateInputSchema, NotebaseRowCreateManyInputSchema, NotebaseRowCreateManyOutputSchema, NotebaseRowCreateOutputSchema, NotebaseRowDeleteInputSchema, NotebaseRowDeleteManyInputSchema, NotebaseRowDeleteManyOutputSchema, NotebaseRowDeleteOutputSchema, NotebaseRowGetInputSchema, NotebaseRowGetOutputSchema, NotebaseRowListInputSchema, NotebaseRowListOutputSchema, NotebaseRowReorderInputSchema, NotebaseRowReorderOutputSchema, NotebaseRowUpdateInputSchema, NotebaseRowUpdateManyInputSchema, NotebaseRowUpdateManyOutputSchema, NotebaseRowUpdateOutputSchema, NotebaseSetSleepInputSchema, NotebaseSetSleepOutputSchema, NotebaseUpdateInputSchema, NotebaseUpdateOutputSchema, PUBLIC_APP_ERROR_DEFS, SPEECH_DAILY_REQUEST_LIMITS, SPEECH_RATE_MAX, SPEECH_RATE_MIN, SPEECH_TEXT_MAX_LENGTH, SRS_REVIEW_CLIENT_ID_NAMESPACE, SRS_REVIEW_DURATION_MS_MAX, SpeechDailyLimitReachedDataSchema, activityStatsOutputSchema, appLocaleSchema, billingAccessSourceSchema, billingCancelScheduledChangeOutputSchema, billingCheckoutPlanSchema, billingCreateCheckoutSessionInputSchema, billingCreateCustomerPortalSessionInputSchema, billingCurrencySchema, billingIntervalSchema, billingLocaleSchema, billingPaymentDueSchema, billingPlanSchema, billingScheduledChangeSchema, billingSessionUrlOutputSchema, billingStatusSchema, billingSubscriptionStatusSchema, canonicalTimezoneSchema, cardSchema, cardStateSchema, cardTemplateSchema, contract, createSrsReviewClientId, defineAgentProcedure, deletionResultSchema, ebookCoverContentTypeSchema, ebookDeleteInputSchema, ebookDeleteOutputSchema, ebookDetailSchema, ebookFinalizeUploadInputSchema, ebookFinalizeUploadOutputSchema, ebookGetDownloadUrlInputSchema, ebookGetDownloadUrlOutputSchema, ebookGetInputSchema, ebookGetOutputSchema, ebookListInputSchema, ebookListItemSchema, ebookListOutputSchema, ebookPresignedUploadSchema, ebookQuotaSchema, ebookRenameDataSchema, ebookRenameInputSchema, ebookRenameOutputSchema, ebookRequestUploadInputSchema, ebookRequestUploadOutputSchema, ebookStatusSchema, ebookUpdateProgressDataSchema, ebookUpdateProgressInputSchema, ebookUpdateProgressOutputSchema, emailCategoryKeySchema, emailCategoryStateSchema, emailLinkTokenSchema, emailPreferencesByTokenStateSchema, emailPreferencesGetByTokenInputSchema, emailPreferencesGetInputSchema, emailPreferencesStateSchema, emailPreferencesUpdateByTokenInputSchema, emailPreferencesUpdateInputSchema, expectedUpdatedAtSchema, getPublicErrorDefinition, isPublicAppErrorCode, masteryGoalOutputSchema, masteryGoalTargetSchema, masteryGoalUpdateInputSchema, mcpConnectionListOutputSchema, mcpConnectionRevokeInputSchema, mcpConnectionRevokeOutputSchema, mcpConnectionSchema, notebaseActivityStatsItemSchema, notebaseActivityStatsOutputSchema, notebaseColumnCreateDataSchema, notebaseColumnSchema, notebaseColumnUpdateDataSchema, notebaseColumnWidthSchema, notebaseCreateDataSchema, notebaseRowCellsSchema, notebaseRowCreateDataSchema, notebaseRowGrowthStatsItemSchema, notebaseRowGrowthStatsOutputSchema, notebaseRowSchema, notebaseRowUpdateDataSchema, notebaseSchema, notebaseSummarySchema, notebaseUpdateDataSchema, notebaseViewConfigSchema, notebaseViewCreateDataSchema, notebaseViewFilterSchema, notebaseViewFiltersSchema, notebaseViewSchema, notebaseViewSortSchema, notebaseViewSortsSchema, notebaseViewTypeSchema, notebaseViewUpdateDataSchema, pageSchema, paginationShape, pickPublicErrorMap, renderedCardSchema, reviewRatingSchema, scheduleStatusSchema, schedulingParamsSchema, speechPreferencesSchema, speechPreferencesUpdateInputSchema, speechRateSchema, speechSynthesizeInputSchema, speechSynthesizeOutputSchema, speechVoiceGenderSchema, speechVoiceNameSchema, speechVoiceSchema, speechVoicesOutputSchema, srsAcknowledgeOptimizerResultsInputSchema, srsAcknowledgeOptimizerResultsOutputSchema, srsActivityStatsItemSchema, srsActivityStatsOutputSchema, srsListCardRevlogsInputSchema, srsListCardRevlogsOutputSchema, srsListUnreadOptimizerResultsInputSchema, srsListUnreadOptimizerResultsOutputSchema, srsManualCardStatusInputSchema, srsMemoryGrowthStatsItemSchema, srsMemoryGrowthStatsOutputSchema, srsOptimizerUnreadResultSchema, srsRecentNotebaseScheduleStatusStatsInputSchema, srsRecentNotebaseScheduleStatusStatsOutputSchema, srsReviewInputSchema, srsReviewOutputSchema, srsRevlogSchema, srsRevlogWithoutSnapshotSchema, srsRollbackReviewInputSchema, srsRollbackReviewOutputSchema, srsScheduleStatusStatsInputSchema, srsScheduleStatusStatsOutputSchema, srsScheduleStatusStatsSchema, srsSetCardBuriedInputSchema, srsSetCardBuriedOutputSchema, srsSetCardSuspendedInputSchema, srsSetCardSuspendedOutputSchema, srsTxidOutputSchema, statsInputSchema, stepSchema, timezoneSchema, userEnsureLocaleInputSchema, userEnsureLocaleOutputSchema, userEnsureTimezoneInputSchema, userEnsureTimezoneOutputSchema, userUpdateLocaleInputSchema, userUpdateLocaleOutputSchema, userUpdateTimezoneInputSchema, userUpdateTimezoneOutputSchema, videoTranscriptCreateInputSchema, videoTranscriptGetInputSchema, videoTranscriptResourceSchema, videoTranscriptStatusSchema, videoTranscriptSubtitlesSchema, videoTranscriptUsagePoolSchema, videoTranscriptUsageSchema };
2832
+ export { BILLING_PAYMENT_DUE_TIME_ZONE, CardGenerateInputSchema, CardGenerateOutputSchema, CardGetInputSchema, CardGetOutputSchema, CardListInputSchema, CardListOutputSchema, CardTemplateCreateInputSchema, CardTemplateCreateOutputSchema, CardTemplateDeleteInputSchema, CardTemplateDeleteOutputSchema, CardTemplateGetInputSchema, CardTemplateGetOutputSchema, CardTemplateInvalidColumnsDataSchema, CardTemplateInvalidLayoutDataSchema, CardTemplateListInputSchema, CardTemplateListOutputSchema, CardTemplateNotebaseColumnInUseDataSchema, CardTemplateUpdateInputSchema, CardTemplateUpdateOutputSchema, CellValidationFailedDataSchema, CellValidationFailureDetailsSchema, CellValidationFailureReasonSchema, DEFAULT_SPEECH_PREFERENCES, EBOOK_LIMIT_BY_PLAN, FeatureAccessStatusInputSchema, FeatureAccessStatusOutputSchema, GatedFeatureKeySchema, HOSTED_AI_CLIENT_STREAM_PART_TYPES, HOSTED_AI_NOTE_SUGGESTION_MAX_NOTES, HOSTED_AI_NOTE_SUGGESTION_MAX_NOTE_FIELDS, HostedAiCreditPeriodKindSchema, HostedAiCreditPolicyIdSchema, HostedAiCreditPoolStatusSchema, HostedAiCreditPoolsInputSchema, HostedAiCreditPoolsOutputSchema, HostedAiFeatureSchema, HostedAiFeatureStatusSchema, HostedAiModelTierSchema, HostedAiNoteSuggestionObjectSchema, HostedAiNoteSuggestionStreamInputSchema, HostedAiOneTimeCreditStatusSchema, HostedAiOutputFieldSchema, HostedAiOutputFieldTypeSchema, HostedAiQuotaExhaustedDataSchema, HostedAiQuotaScopeSchema, HostedAiRateLimitErrorDataSchema, HostedAiRecurringCreditStatusSchema, HostedAiRequestIdSchema, HostedAiStatusInputSchema, HostedAiStatusOutputSchema, HostedAiStreamPartSchema, HostedAiStreamStructuredObjectInputSchema, HostedAiStreamTextInputSchema, HostedAiTierRestrictedDataSchema, HostedAiTierStatusSchema, HostedAiUnavailableReasonSchema, HostedAiUpgradePlanSchema, MASTERY_GOAL_TARGET_MAX, MCP_DAILY_CALL_LIMITS, NOTEBASE_ROW_CREATE_MANY_MAX_ROWS, NOTEBASE_ROW_DELETE_MANY_MAX_ROWS, NOTEBASE_ROW_UPDATE_MANY_MAX_ROWS, NotebaseColumnCreateInputSchema, NotebaseColumnCreateOutputSchema, NotebaseColumnDeleteInputSchema, NotebaseColumnDeleteOutputSchema, NotebaseColumnReorderInputSchema, NotebaseColumnReorderOutputSchema, NotebaseColumnUpdateInputSchema, NotebaseColumnUpdateOutputSchema, NotebaseCreateInputSchema, NotebaseCreateOutputSchema, NotebaseDeleteInputSchema, NotebaseDeleteOutputSchema, NotebaseGetInputSchema, NotebaseGetOutputSchema, NotebaseGetSchemaInputSchema, NotebaseGetSchemaOutputSchema, NotebaseGetSummaryInputSchema, NotebaseGetSummaryOutputSchema, NotebaseListInputSchema, NotebaseListItemSchema, NotebaseListOutputSchema, NotebaseRowCreateInputSchema, NotebaseRowCreateManyInputSchema, NotebaseRowCreateManyOutputSchema, NotebaseRowCreateOutputSchema, NotebaseRowDeleteInputSchema, NotebaseRowDeleteManyInputSchema, NotebaseRowDeleteManyOutputSchema, NotebaseRowDeleteOutputSchema, NotebaseRowGetInputSchema, NotebaseRowGetOutputSchema, NotebaseRowListInputSchema, NotebaseRowListOutputSchema, NotebaseRowReorderInputSchema, NotebaseRowReorderOutputSchema, NotebaseRowUpdateInputSchema, NotebaseRowUpdateManyInputSchema, NotebaseRowUpdateManyOutputSchema, NotebaseRowUpdateOutputSchema, NotebaseSetSleepInputSchema, NotebaseSetSleepOutputSchema, NotebaseUpdateInputSchema, NotebaseUpdateOutputSchema, PRACTICE_REMINDER_CATEGORY_KEY, PRACTICE_REMINDER_DEFAULT_TIME, PRACTICE_REMINDER_TIMES, PUBLIC_APP_ERROR_DEFS, PdfTranslationInsufficientCreditDataSchema, PdfTranslationUploadErrorDataSchema, SPEECH_DAILY_REQUEST_LIMITS, SPEECH_RATE_MAX, SPEECH_RATE_MIN, SPEECH_TEXT_MAX_LENGTH, SRS_REVIEW_CLIENT_ID_NAMESPACE, SRS_REVIEW_DURATION_MS_MAX, SpeechDailyLimitReachedDataSchema, WEB_SYNC_REPORT_MAX_EVENTS, activityStatsOutputSchema, appLocaleSchema, billingAccessSourceSchema, billingCancelScheduledChangeOutputSchema, billingCheckoutPlanSchema, billingCreateCheckoutSessionInputSchema, billingCreateCustomerPortalSessionInputSchema, billingCurrencySchema, billingIntervalSchema, billingLocaleSchema, billingPaymentDueSchema, billingPlanSchema, billingScheduledChangeSchema, billingSessionUrlOutputSchema, billingStatusSchema, billingSubscriptionStatusSchema, canonicalTimezoneSchema, cardSchema, cardStateSchema, cardTemplateSchema, contract, createSrsReviewClientId, defineAgentProcedure, deletionResultSchema, ebookCoverContentTypeSchema, ebookDeleteInputSchema, ebookDeleteOutputSchema, ebookDetailSchema, ebookFinalizeUploadInputSchema, ebookFinalizeUploadOutputSchema, ebookGetDownloadUrlInputSchema, ebookGetDownloadUrlOutputSchema, ebookGetInputSchema, ebookGetOutputSchema, ebookListInputSchema, ebookListItemSchema, ebookListOutputSchema, ebookPresignedUploadSchema, ebookQuotaSchema, ebookRenameDataSchema, ebookRenameInputSchema, ebookRenameOutputSchema, ebookRequestUploadInputSchema, ebookRequestUploadOutputSchema, ebookStatusSchema, ebookUpdateProgressDataSchema, ebookUpdateProgressInputSchema, ebookUpdateProgressOutputSchema, emailCategoryKeySchema, emailCategoryStateSchema, emailLinkTokenSchema, emailPreferencesByTokenStateSchema, emailPreferencesGetByTokenInputSchema, emailPreferencesGetInputSchema, emailPreferencesStateSchema, emailPreferencesUpdateByTokenInputSchema, emailPreferencesUpdateInputSchema, expectedUpdatedAtSchema, flattenStepSchema, getPublicErrorDefinition, isPublicAppErrorCode, masteryGoalOutputSchema, masteryGoalTargetSchema, masteryGoalUpdateInputSchema, mcpCallUsageSchema, mcpConnectionListOutputSchema, mcpConnectionRevokeInputSchema, mcpConnectionRevokeOutputSchema, mcpConnectionSchema, mediaAssetIdInputSchema, mediaAssetMetadataSchema, mediaAssetOutputSchema, mediaAssetSchema, mediaAssetStatusSchema, mediaContentTypeSchema, mediaFailureCodeSchema, mediaRequestUploadInputSchema, mediaRequestUploadOutputSchema, mediaUsageOutputSchema, notebaseActivityStatsItemSchema, notebaseActivityStatsOutputSchema, notebaseColumnCreateDataSchema, notebaseColumnSchema, notebaseColumnUpdateDataSchema, notebaseColumnWidthSchema, notebaseCreateDataSchema, notebaseRowCellsSchema, notebaseRowCreateDataSchema, notebaseRowGrowthStatsItemSchema, notebaseRowGrowthStatsOutputSchema, notebaseRowSchema, notebaseRowUpdateDataSchema, notebaseSchema, notebaseSummarySchema, notebaseUpdateDataSchema, notebaseViewConfigSchema, notebaseViewCreateDataSchema, notebaseViewFilterSchema, notebaseViewFiltersSchema, notebaseViewSchema, notebaseViewSortSchema, notebaseViewSortsSchema, notebaseViewTypeSchema, notebaseViewUpdateDataSchema, pageSchema, paginationShape, pdfTranslationDeleteOutputSchema, pdfTranslationDownloadOutputSchema, pdfTranslationGetOutputSchema, pdfTranslationJobIdInputSchema, pdfTranslationJobResourceSchema, pdfTranslationJobStatusSchema, pdfTranslationListInputSchema, pdfTranslationListOutputSchema, pdfTranslationOutputInputSchema, pdfTranslationOutputVariantSchema, pdfTranslationPreviewOutputSchema, pdfTranslationRequestUploadInputSchema, pdfTranslationRequestUploadOutputSchema, pdfTranslationStatusInputSchema, pdfTranslationStatusOutputSchema, pdfTranslationSubmitInputSchema, pdfTranslationSubmitOutputSchema, pickPublicErrorMap, postponePlanSchema, postponeStepSchema, postponeSummarySchema, practiceReminderTimeSchema, remindersPreferencesSchema, renderedCardSchema, reportWebSyncInputSchema, reviewRatingSchema, scheduleStatusSchema, schedulingParamsSchema, speechPreferencesSchema, speechPreferencesUpdateInputSchema, speechRateSchema, speechSynthesizeInputSchema, speechSynthesizeOutputSchema, speechVoiceGenderSchema, speechVoiceNameSchema, speechVoiceSchema, speechVoicesOutputSchema, spreadDaySchema, srsAcknowledgeOptimizerResultsInputSchema, srsAcknowledgeOptimizerResultsOutputSchema, srsActivityStatsItemSchema, srsActivityStatsOutputSchema, srsApplyPostponeInputSchema, srsApplyPostponeOutputSchema, srsBacklogStatsInputSchema, srsBacklogStatsOutputSchema, srsBacklogStatsSchema, srsListCardRevlogsInputSchema, srsListCardRevlogsOutputSchema, srsListUnreadOptimizerResultsInputSchema, srsListUnreadOptimizerResultsOutputSchema, srsManualCardStatusInputSchema, srsMemoryGrowthStatsItemSchema, srsMemoryGrowthStatsOutputSchema, srsOptimizerUnreadResultSchema, srsPreviewPostponeInputSchema, srsPreviewPostponeOutputSchema, srsRecentNotebaseScheduleStatusStatsInputSchema, srsRecentNotebaseScheduleStatusStatsOutputSchema, srsRescheduleApplyOutputSchema, srsReviewInputSchema, srsReviewOutputSchema, srsRevlogSchema, srsRevlogWithoutSnapshotSchema, srsRollbackReviewInputSchema, srsRollbackReviewOutputSchema, srsScheduleStatusStatsInputSchema, srsScheduleStatusStatsOutputSchema, srsScheduleStatusStatsSchema, srsSetCardBuriedInputSchema, srsSetCardBuriedOutputSchema, srsSetCardSuspendedInputSchema, srsSetCardSuspendedOutputSchema, srsTxidOutputSchema, statsInputSchema, stepSchema, timezoneSchema, userEnsureLocaleInputSchema, userEnsureLocaleOutputSchema, userEnsureTimezoneInputSchema, userEnsureTimezoneOutputSchema, userUpdateLocaleInputSchema, userUpdateLocaleOutputSchema, userUpdateTimezoneInputSchema, userUpdateTimezoneOutputSchema, videoTranscriptCreateInputSchema, videoTranscriptGetInputSchema, videoTranscriptResourceSchema, videoTranscriptStatusSchema, videoTranscriptSubtitlesSchema, videoTranscriptUsagePoolSchema, videoTranscriptUsageSchema, webSyncEventSchema, webSyncOperationSchema, webSyncPageSchema, webSyncShapeSchema, webSyncStreamErrorTypeSchema, webSyncStreamPhaseSchema, webSyncTransportSchema, webSyncUnavailableReasonSchema, webSyncWriteOutcomeSchema };
2211
2833
 
2212
2834
  //# sourceMappingURL=index.js.map