@read-frog/api-contract 0.22.0 → 0.24.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,6 +1,122 @@
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";
3
+ import { EBOOK_ALLOWED_COVER_CONTENT_TYPES, GATED_FEATURE_KEYS, 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
+ //#region src/schemas/app-locale.ts
5
+ /**
6
+ * The languages the website is in (`project.inlang/settings.json`; a test in
7
+ * apps/www keeps the two in step). Used wherever the server writes for a
8
+ * person: Stripe pages, emails, and the account's `locale`.
9
+ */
10
+ const appLocaleSchema = z.enum([
11
+ "en",
12
+ "es",
13
+ "ja",
14
+ "ko",
15
+ "ru",
16
+ "tr",
17
+ "vi",
18
+ "zh",
19
+ "zh-TW"
20
+ ]);
21
+ //#endregion
22
+ //#region src/schemas/billing.ts
23
+ const billingIntervalSchema = z.enum(["month", "year"]);
24
+ const billingSubscriptionStatusSchema = z.enum([
25
+ "incomplete",
26
+ "incomplete_expired",
27
+ "trialing",
28
+ "active",
29
+ "past_due",
30
+ "canceled",
31
+ "unpaid",
32
+ "paused"
33
+ ]);
34
+ const billingPlanSchema = z.enum([
35
+ "free",
36
+ "pro",
37
+ "ultra"
38
+ ]);
39
+ /**
40
+ * How many MCP tool calls each plan may make in a day (24 hours from the first
41
+ * one); `null` is no limit. Each `tools/call` counts once, whatever the tool.
42
+ *
43
+ * Read by the MCP server's gate AND by the website's copy, so the pages cannot
44
+ * promise calls the server refuses.
45
+ *
46
+ * Companion edit when this changes: the MCP docs under
47
+ * `apps/www/content/docs/mcp/` and `account-and-plans`, which state the numbers.
48
+ */
49
+ const MCP_DAILY_CALL_LIMITS = {
50
+ free: 10,
51
+ pro: 50,
52
+ ultra: null
53
+ };
54
+ const billingCheckoutPlanSchema = z.enum(["pro", "ultra"]);
55
+ const billingCurrencySchema = z.enum([
56
+ "usd",
57
+ "cad",
58
+ "cny"
59
+ ]);
60
+ const billingLocaleSchema = appLocaleSchema;
61
+ const billingAccessSourceSchema = z.enum(["subscription", "pass"]);
62
+ const billingScheduledChangeSchema = z.object({
63
+ plan: billingCheckoutPlanSchema,
64
+ interval: billingIntervalSchema,
65
+ effectiveAt: z.coerce.date()
66
+ }).strict();
67
+ /**
68
+ * The zone a payment deadline is shown in, as a date with no time. UTC−12 is
69
+ * the last zone to finish a day, and `dueBy` is the end of a day there, so the
70
+ * date it shows stays open in every customer's zone until their own midnight.
71
+ */
72
+ const BILLING_PAYMENT_DUE_TIME_ZONE = "Etc/GMT+12";
73
+ /**
74
+ * A renewal whose payment failed. The plan stays until `dueBy`; paying the
75
+ * invoice before then (or later, until the subscription is canceled) restores
76
+ * the subscription as if the payment had gone through.
77
+ */
78
+ const billingPaymentDueSchema = z.object({
79
+ /** The last instant of the plan; show it in BILLING_PAYMENT_DUE_TIME_ZONE. */
80
+ dueBy: z.coerce.date(),
81
+ /**
82
+ * The plan the payment keeps. Not `BillingStatus.plan`: past `dueBy` that
83
+ * already reads "free" while the invoice is still payable.
84
+ */
85
+ plan: billingCheckoutPlanSchema,
86
+ /** The Stripe-hosted page that pays the invoice; null if Stripe gave none. */
87
+ url: z.url().nullable()
88
+ }).strict();
89
+ const billingStatusSchema = z.object({
90
+ plan: billingPlanSchema,
91
+ status: billingSubscriptionStatusSchema.nullable(),
92
+ interval: billingIntervalSchema.nullable(),
93
+ currentPeriodEnd: z.coerce.date().nullable(),
94
+ /**
95
+ * When the subscription terminates, or null if it renews. Replaces the
96
+ * `cancelAtPeriodEnd` boolean: Stripe deprecated its counterpart and the
97
+ * Customer Portal no longer sets it, and the termination date is not always
98
+ * `currentPeriodEnd` — a stacked pass pushes that past the cancellation.
99
+ */
100
+ cancelAt: z.coerce.date().nullable(),
101
+ accessSource: billingAccessSourceSchema.nullable(),
102
+ scheduledChange: billingScheduledChangeSchema.nullable(),
103
+ paymentDue: billingPaymentDueSchema.nullable(),
104
+ unlimitedNotebaseNotes: z.boolean(),
105
+ notebaseNoteLimit: z.number().int().positive(),
106
+ notebaseNoteCount: z.number().int().min(0)
107
+ }).strict();
108
+ const billingCreateCheckoutSessionInputSchema = z.object({
109
+ currency: billingCurrencySchema,
110
+ interval: billingIntervalSchema,
111
+ locale: appLocaleSchema,
112
+ plan: billingCheckoutPlanSchema.default("pro"),
113
+ requestId: z.uuid().optional(),
114
+ attribution: checkoutAttributionInputSchema.optional()
115
+ }).strict();
116
+ const billingCreateCustomerPortalSessionInputSchema = z.object({ locale: appLocaleSchema }).strict();
117
+ const billingSessionUrlOutputSchema = z.object({ url: z.url() }).strict();
118
+ const billingCancelScheduledChangeOutputSchema = z.object({ success: z.literal(true) }).strict();
119
+ //#endregion
4
120
  //#region src/schemas/hosted-ai.ts
5
121
  const HostedAiOutputFieldTypeSchema = z.enum(["string", "number"]);
6
122
  const HostedAiOutputFieldSchema = z.strictObject({
@@ -29,7 +145,8 @@ const HostedAiFeatureSchema = z.enum([
29
145
  "selectionTranslation",
30
146
  "videoSubtitles",
31
147
  "inputTranslation",
32
- "languageDetection"
148
+ "languageDetection",
149
+ "pdfTranslation"
33
150
  ]);
34
151
  const HostedAiRequestIdSchema = z.uuid();
35
152
  const HostedAiRequestMetadataSchema = {
@@ -136,17 +253,30 @@ const HOSTED_AI_CLIENT_STREAM_PART_TYPES = [
136
253
  * useful response rather than a validation error.
137
254
  */
138
255
  const HostedAiStatusInputSchema = z.object({});
256
+ /**
257
+ * `pro_required` means the Pro plan or any plan above it; `ultra_required`
258
+ * means Ultra. Appended last, so a client that predates a value falls back on
259
+ * its own default instead of misreading it.
260
+ */
139
261
  const HostedAiUnavailableReasonSchema = z.enum([
140
262
  "authentication_required",
141
263
  "ultra_required",
142
264
  "quota_exhausted",
143
- "service_unavailable"
265
+ "service_unavailable",
266
+ "pro_required"
144
267
  ]);
268
+ /**
269
+ * The cheapest plan an account would need to buy for something it cannot use
270
+ * now. Any plan above it works too, so `pro` reads as "Pro or Ultra".
271
+ */
272
+ const HostedAiUpgradePlanSchema = billingPlanSchema.exclude(["free"]);
145
273
  const HostedAiCreditPolicyIdSchema = z.enum([
146
274
  "custom-action-guest-daily-v1",
147
275
  "custom-action-user-daily-v1",
148
276
  "custom-action-pro-daily-v1",
149
- "ultra-weekly-v1"
277
+ "ultra-weekly-v1",
278
+ "pro-weekly-v1",
279
+ "pro-weekly-v2"
150
280
  ]);
151
281
  const HostedAiCreditPeriodKindSchema = z.enum(["daily", "weekly"]);
152
282
  const HostedAiQuotaScopeSchema = z.enum(["guest", "user"]);
@@ -207,15 +337,26 @@ const HostedAiOneTimeCreditStatusSchema = z.strictObject({
207
337
  * pool ends at `expiresAt`. Narrow on `periodKind` before reading either.
208
338
  */
209
339
  const HostedAiCreditPoolStatusSchema = z.discriminatedUnion("periodKind", [HostedAiRecurringCreditStatusSchema, HostedAiOneTimeCreditStatusSchema]);
340
+ /** Feature-scoped credit display, separate from the legacy extension status shape. */
341
+ const HostedAiCreditPoolsInputSchema = z.strictObject({ feature: HostedAiFeatureSchema });
342
+ const HostedAiCreditPoolsOutputSchema = z.strictObject({ pools: z.array(HostedAiCreditPoolStatusSchema) });
210
343
  const HostedAiTierStatusSchema = z.strictObject({
211
344
  accessAllowed: z.boolean(),
212
345
  available: z.boolean(),
213
346
  unavailableReason: HostedAiUnavailableReasonSchema.nullable(),
214
347
  /**
215
- * Viewer-independent product fact: no non-Ultra account can ever use this
216
- * feature/tier, so signing in alone will not unlock it. Unlike the fields
217
- * above, this does not vary with the caller's identity or plan — clients use
218
- * it to label Ultra-only options rather than to gate the current user.
348
+ * The cheapest plan this account would need to use the tier, or null when it
349
+ * needs none: its plan or a one-time pool already covers it, or the tier is
350
+ * open to every signed-in account. For a guest it is the plan needed after
351
+ * signing in. Clients badge an option with it and offer that plan.
352
+ */
353
+ upgradeTo: HostedAiUpgradePlanSchema.nullable(),
354
+ /**
355
+ * @deprecated Read `upgradeTo`. Viewer-independent product fact: no
356
+ * non-Ultra account can ever use this feature/tier. Extensions released
357
+ * before `upgradeTo` badge options with it, including for Ultra accounts.
358
+ *
359
+ * TODO(2026-11-21): remove once those extensions have drained (#710).
219
360
  */
220
361
  requiresUltra: z.boolean(),
221
362
  modelRevision: z.string().trim().min(1)
@@ -251,6 +392,125 @@ const HostedAiStatusOutputSchema = z.strictObject({
251
392
  })
252
393
  });
253
394
  //#endregion
395
+ //#region src/schemas/pdf-translation.ts
396
+ const pdfTranslationJobStatusSchema = z.enum([
397
+ "queued",
398
+ "running",
399
+ "cancel_requested",
400
+ "succeeded",
401
+ "failed",
402
+ "cancelled",
403
+ "expired"
404
+ ]);
405
+ /**
406
+ * The two PDFs one translation makes: the translation alone, with the
407
+ * original's layout, and the original and translated pages side by side.
408
+ */
409
+ const pdfTranslationOutputVariantSchema = z.enum(["translated", "bilingual"]);
410
+ const languageSchema = z.string().min(2).max(40).regex(/^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$/i);
411
+ const pdfTranslationRequestUploadInputSchema = z.object({
412
+ fileName: z.string().trim().min(1).max(255).refine((fileName) => fileName.toLowerCase().endsWith(".pdf"), { message: "fileName must end with .pdf" }),
413
+ fileByteSize: z.number().int().min(1)
414
+ }).strict();
415
+ const pdfTranslationRequestUploadOutputSchema = z.object({
416
+ uploadId: z.uuid(),
417
+ upload: z.object({
418
+ url: z.url(),
419
+ headers: z.record(z.string(), z.string())
420
+ }).strict(),
421
+ expiresAt: z.coerce.date()
422
+ }).strict();
423
+ const pdfTranslationSubmitInputSchema = z.object({
424
+ 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" }),
425
+ idempotencyKey: z.string().trim().min(1).max(200),
426
+ targetLanguage: languageSchema,
427
+ modelTier: HostedAiModelTierSchema
428
+ }).strict();
429
+ const pdfTranslationJobIdInputSchema = z.object({ id: z.uuid() }).strict();
430
+ const pdfTranslationOutputInputSchema = z.object({
431
+ id: z.uuid(),
432
+ variant: pdfTranslationOutputVariantSchema
433
+ }).strict();
434
+ const pdfTranslationListInputSchema = z.object({}).strict();
435
+ const pdfTranslationJobResourceSchema = z.object({
436
+ id: z.uuid(),
437
+ status: pdfTranslationJobStatusSchema,
438
+ sourceFileName: z.string(),
439
+ targetLanguage: z.string(),
440
+ modelTier: HostedAiModelTierSchema,
441
+ batchId: z.uuid(),
442
+ batchPosition: z.number().int().min(0),
443
+ waitingAhead: z.number().int().min(0).nullable(),
444
+ freeTrial: z.boolean(),
445
+ outputs: z.object({
446
+ translated: z.boolean(),
447
+ bilingual: z.boolean()
448
+ }).strict(),
449
+ pageCount: z.number().int().min(1),
450
+ progressStage: z.string().nullable(),
451
+ progressPercent: z.number().min(0).max(100),
452
+ estimatedCostNanoUsd: z.number().int().min(0),
453
+ chargedCostNanoUsd: z.number().int().min(0),
454
+ error: z.object({
455
+ category: z.string(),
456
+ message: z.string()
457
+ }).strict().nullable(),
458
+ workerRelease: z.string().nullable(),
459
+ createdAt: z.coerce.date(),
460
+ startedAt: z.coerce.date().nullable(),
461
+ completedAt: z.coerce.date().nullable(),
462
+ outputExpiresAt: z.coerce.date().nullable()
463
+ }).strict();
464
+ const pdfTranslationListOutputSchema = z.object({ items: z.array(pdfTranslationJobResourceSchema) }).strict();
465
+ /** What a submission made: its batch, and one job per PDF in their order. */
466
+ const pdfTranslationSubmitOutputSchema = z.object({
467
+ batchId: z.uuid(),
468
+ jobs: z.array(pdfTranslationJobResourceSchema).min(1)
469
+ }).strict();
470
+ /** A job, and every job of its batch in their order (itself included). */
471
+ const pdfTranslationGetOutputSchema = z.object({
472
+ job: pdfTranslationJobResourceSchema,
473
+ batch: z.array(pdfTranslationJobResourceSchema).min(1)
474
+ }).strict();
475
+ const pdfTranslationStatusInputSchema = z.object({}).strict();
476
+ const pdfTranslationStatusOutputSchema = z.object({
477
+ freeTrialsRemaining: z.number().int().min(0),
478
+ /**
479
+ * Whether Built-in AI credit pays for PDF translation on the normal tier:
480
+ * a paid plan, or credit the account was given for every feature. Only a
481
+ * funded account submits more than one PDF or downloads a translation.
482
+ */
483
+ funded: z.boolean()
484
+ }).strict();
485
+ const pdfTranslationDownloadOutputSchema = z.object({
486
+ url: z.url(),
487
+ expiresAt: z.coerce.date()
488
+ }).strict();
489
+ const pdfTranslationPreviewOutputSchema = z.object({
490
+ url: z.url(),
491
+ expiresAt: z.coerce.date(),
492
+ /**
493
+ * Whether the URL opens the free translation's copy with the Read Frog
494
+ * watermark, which an account nothing funds reads: upgrading opens the
495
+ * PDF itself.
496
+ */
497
+ watermarked: z.boolean()
498
+ }).strict();
499
+ const pdfTranslationDeleteOutputSchema = z.object({ id: z.uuid() }).strict();
500
+ const PdfTranslationInsufficientCreditDataSchema = z.strictObject({
501
+ estimatedCostNanoUsd: z.number().int().min(0),
502
+ remainingNanoUsd: z.number().int().min(0),
503
+ resetAt: z.iso.datetime().nullable()
504
+ });
505
+ /**
506
+ * Which of a submission's PDFs a refusal is about, so the page can point at
507
+ * it. For an upload an earlier request used up, also the translation it made.
508
+ */
509
+ const PdfTranslationUploadErrorDataSchema = z.strictObject({
510
+ uploadId: z.uuid(),
511
+ jobId: z.uuid().optional()
512
+ });
513
+ //#endregion
254
514
  //#region src/public-errors.ts
255
515
  const CellValidationFailureReasonSchema = z.enum([
256
516
  "unknown_notebase_column",
@@ -283,7 +543,11 @@ const CardTemplateNotebaseColumnInUseDataSchema = z.object({ templates: z.array(
283
543
  id: z.uuid(),
284
544
  name: z.string()
285
545
  }).strict()) }).strict();
286
- const HostedAiTierRestrictedDataSchema = z.strictObject({ modelTier: HostedAiModelTierSchema });
546
+ const HostedAiTierRestrictedDataSchema = z.strictObject({
547
+ modelTier: HostedAiModelTierSchema,
548
+ /** The cheapest plan that unlocks it; a client offers "Pro or Ultra" for `pro`. */
549
+ upgradeTo: HostedAiUpgradePlanSchema
550
+ });
287
551
  const HostedAiQuotaExhaustedDataSchema = z.strictObject({
288
552
  modelTier: HostedAiModelTierSchema,
289
553
  policyId: HostedAiCreditPolicyIdSchema,
@@ -405,6 +669,10 @@ const PUBLIC_APP_ERROR_DEFS = {
405
669
  message: "A subscription change is already scheduled",
406
670
  status: 409
407
671
  },
672
+ BILLING_CHECKOUT_CONFLICT: {
673
+ message: "Please start a new checkout from the pricing page",
674
+ status: 409
675
+ },
408
676
  CARD_NOT_REVIEWABLE: {
409
677
  message: "Card cannot be reviewed in its current state",
410
678
  status: 409
@@ -437,6 +705,22 @@ const PUBLIC_APP_ERROR_DEFS = {
437
705
  message: "Card status change is unavailable",
438
706
  status: 409
439
707
  },
708
+ RESCHEDULE_PLAN_EXPIRED: {
709
+ message: "The reschedule plan has expired; preview it again",
710
+ status: 409
711
+ },
712
+ RESCHEDULE_STALE: {
713
+ message: "Cards changed after the reschedule preview; preview it again",
714
+ status: 409
715
+ },
716
+ RESCHEDULE_PREVIEW_TIMEOUT: {
717
+ message: "Planning the reschedule took too long",
718
+ status: 503
719
+ },
720
+ RESCHEDULE_DAILY_LIMIT_INVALID: {
721
+ message: "The daily limit is outside the range a reschedule may suggest",
722
+ status: 422
723
+ },
440
724
  NOTEBASE_VIEW_NOT_FOUND: {
441
725
  message: "Notebase view not found",
442
726
  status: 404
@@ -477,6 +761,77 @@ const PUBLIC_APP_ERROR_DEFS = {
477
761
  EMAIL_LINK_INVALID: {
478
762
  message: "This email link is not valid",
479
763
  status: 400
764
+ },
765
+ PDF_TRANSLATION_UNAVAILABLE: {
766
+ message: "PDF translation is not available right now",
767
+ status: 503
768
+ },
769
+ PDF_TRANSLATION_NOT_FOUND: {
770
+ message: "PDF translation not found",
771
+ status: 404
772
+ },
773
+ PDF_TRANSLATION_UPLOAD_NOT_FOUND: {
774
+ data: PdfTranslationUploadErrorDataSchema,
775
+ message: "PDF upload not found",
776
+ status: 404
777
+ },
778
+ PDF_TRANSLATION_UPLOAD_EXPIRED: {
779
+ data: PdfTranslationUploadErrorDataSchema,
780
+ message: "The PDF upload has expired; upload the file again",
781
+ status: 410
782
+ },
783
+ PDF_TRANSLATION_UPLOAD_NOT_COMPLETED: {
784
+ data: PdfTranslationUploadErrorDataSchema,
785
+ message: "The PDF upload has not been completed",
786
+ status: 409
787
+ },
788
+ PDF_TRANSLATION_FILE_TOO_LARGE: {
789
+ message: "The PDF exceeds the maximum allowed size",
790
+ status: 413
791
+ },
792
+ PDF_TRANSLATION_INVALID_PDF: {
793
+ data: PdfTranslationUploadErrorDataSchema,
794
+ message: "The file is not a readable PDF",
795
+ status: 422
796
+ },
797
+ PDF_TRANSLATION_ALREADY_TRANSLATED: {
798
+ data: PdfTranslationUploadErrorDataSchema,
799
+ message: "This PDF is already a translation; upload the original instead",
800
+ status: 422
801
+ },
802
+ PDF_TRANSLATION_PAGE_LIMIT_EXCEEDED: {
803
+ data: PdfTranslationUploadErrorDataSchema,
804
+ message: "The PDF has more pages than one translation allows",
805
+ status: 422
806
+ },
807
+ PDF_TRANSLATION_QUEUE_FULL: {
808
+ message: "Too many PDF translations are waiting; try again when some have finished",
809
+ status: 409
810
+ },
811
+ PDF_TRANSLATION_IDEMPOTENCY_CONFLICT: {
812
+ message: "This idempotency key was already used for a different PDF translation",
813
+ status: 409
814
+ },
815
+ PDF_TRANSLATION_INSUFFICIENT_CREDIT: {
816
+ data: PdfTranslationInsufficientCreditDataSchema,
817
+ message: "Not enough Built-in AI credit left to translate this PDF",
818
+ status: 429
819
+ },
820
+ PDF_TRANSLATION_NOT_CANCELLABLE: {
821
+ message: "This PDF translation has already finished",
822
+ status: 409
823
+ },
824
+ PDF_TRANSLATION_NOT_READY: {
825
+ message: "The translated PDF is not available",
826
+ status: 409
827
+ },
828
+ PDF_TRANSLATION_DOWNLOAD_RESTRICTED: {
829
+ message: "Downloading a translated PDF needs a Pro or Ultra plan",
830
+ status: 403
831
+ },
832
+ PDF_TRANSLATION_NOT_DELETABLE: {
833
+ message: "Cancel this PDF translation before deleting it",
834
+ status: 409
480
835
  }
481
836
  };
482
837
  function isPublicAppErrorCode(code) {
@@ -500,122 +855,8 @@ function pickPublicErrorMap(...codes) {
500
855
  }));
501
856
  }
502
857
  //#endregion
503
- //#region src/schemas/app-locale.ts
504
- /**
505
- * The languages the website is in (`project.inlang/settings.json`; a test in
506
- * apps/www keeps the two in step). Used wherever the server writes for a
507
- * person: Stripe pages, emails, and the account's `locale`.
508
- */
509
- const appLocaleSchema = z.enum([
510
- "en",
511
- "es",
512
- "ja",
513
- "ko",
514
- "ru",
515
- "tr",
516
- "vi",
517
- "zh",
518
- "zh-TW"
519
- ]);
520
- //#endregion
521
- //#region src/schemas/billing.ts
522
- const billingIntervalSchema = z.enum(["month", "year"]);
523
- const billingSubscriptionStatusSchema = z.enum([
524
- "incomplete",
525
- "incomplete_expired",
526
- "trialing",
527
- "active",
528
- "past_due",
529
- "canceled",
530
- "unpaid",
531
- "paused"
532
- ]);
533
- const billingPlanSchema = z.enum([
534
- "free",
535
- "pro",
536
- "ultra"
537
- ]);
538
- /**
539
- * How many MCP tool calls each plan may make in a day (24 hours from the first
540
- * one); `null` is no limit. Each `tools/call` counts once, whatever the tool.
541
- *
542
- * Read by the MCP server's gate AND by the website's copy, so the pages cannot
543
- * promise calls the server refuses.
544
- *
545
- * Companion edit when this changes: the MCP docs under
546
- * `apps/www/content/docs/mcp/` and `account-and-plans`, which state the numbers.
547
- */
548
- const MCP_DAILY_CALL_LIMITS = {
549
- free: 10,
550
- pro: 50,
551
- ultra: null
552
- };
553
- const billingCheckoutPlanSchema = z.enum(["pro", "ultra"]);
554
- const billingCurrencySchema = z.enum([
555
- "usd",
556
- "cad",
557
- "cny"
558
- ]);
559
- const billingLocaleSchema = appLocaleSchema;
560
- const billingAccessSourceSchema = z.enum(["subscription", "pass"]);
561
- const billingScheduledChangeSchema = z.object({
562
- plan: billingCheckoutPlanSchema,
563
- interval: billingIntervalSchema,
564
- effectiveAt: z.coerce.date()
565
- }).strict();
566
- /**
567
- * The zone a payment deadline is shown in, as a date with no time. UTC−12 is
568
- * the last zone to finish a day, and `dueBy` is the end of a day there, so the
569
- * date it shows stays open in every customer's zone until their own midnight.
570
- */
571
- const BILLING_PAYMENT_DUE_TIME_ZONE = "Etc/GMT+12";
572
- /**
573
- * A renewal whose payment failed. The plan stays until `dueBy`; paying the
574
- * invoice before then (or later, until the subscription is canceled) restores
575
- * the subscription as if the payment had gone through.
576
- */
577
- const billingPaymentDueSchema = z.object({
578
- /** The last instant of the plan; show it in BILLING_PAYMENT_DUE_TIME_ZONE. */
579
- dueBy: z.coerce.date(),
580
- /**
581
- * The plan the payment keeps. Not `BillingStatus.plan`: past `dueBy` that
582
- * already reads "free" while the invoice is still payable.
583
- */
584
- plan: billingCheckoutPlanSchema,
585
- /** The Stripe-hosted page that pays the invoice; null if Stripe gave none. */
586
- url: z.url().nullable()
587
- }).strict();
588
- const billingStatusSchema = z.object({
589
- plan: billingPlanSchema,
590
- status: billingSubscriptionStatusSchema.nullable(),
591
- interval: billingIntervalSchema.nullable(),
592
- currentPeriodEnd: z.coerce.date().nullable(),
593
- /**
594
- * When the subscription terminates, or null if it renews. Replaces the
595
- * `cancelAtPeriodEnd` boolean: Stripe deprecated its counterpart and the
596
- * Customer Portal no longer sets it, and the termination date is not always
597
- * `currentPeriodEnd` — a stacked pass pushes that past the cancellation.
598
- */
599
- cancelAt: z.coerce.date().nullable(),
600
- accessSource: billingAccessSourceSchema.nullable(),
601
- scheduledChange: billingScheduledChangeSchema.nullable(),
602
- paymentDue: billingPaymentDueSchema.nullable(),
603
- unlimitedNotebaseNotes: z.boolean(),
604
- notebaseNoteLimit: z.number().int().positive(),
605
- notebaseNoteCount: z.number().int().min(0)
606
- }).strict();
607
- const billingCreateCheckoutSessionInputSchema = z.object({
608
- currency: billingCurrencySchema,
609
- interval: billingIntervalSchema,
610
- locale: appLocaleSchema,
611
- plan: billingCheckoutPlanSchema.default("pro")
612
- }).strict();
613
- const billingCreateCustomerPortalSessionInputSchema = z.object({ locale: appLocaleSchema }).strict();
614
- const billingSessionUrlOutputSchema = z.object({ url: z.url() }).strict();
615
- const billingCancelScheduledChangeOutputSchema = z.object({ success: z.literal(true) }).strict();
616
- //#endregion
617
858
  //#region src/contracts/billing.ts
618
- const billingProcedure = oc.errors(pickPublicErrorMap("BILLING_NOT_CONFIGURED", "BILLING_CUSTOMER_NOT_FOUND", "BILLING_PASS_ACTIVE", "BILLING_CHANGE_SCHEDULED"));
859
+ const billingProcedure = oc.errors(pickPublicErrorMap("BILLING_NOT_CONFIGURED", "BILLING_CUSTOMER_NOT_FOUND", "BILLING_PASS_ACTIVE", "BILLING_CHANGE_SCHEDULED", "BILLING_CHECKOUT_CONFLICT"));
619
860
  const billingContract = {
620
861
  status: billingProcedure.route({
621
862
  method: "GET",
@@ -943,9 +1184,34 @@ const emailCategoryStateSchema = z.object({
943
1184
  required: z.boolean(),
944
1185
  subscribed: z.boolean()
945
1186
  }).strict();
1187
+ /**
1188
+ * The category whose emails a person can time: Practice reminders, seeded as
1189
+ * `practice` (packages/db's migration 0067). The settings page shows the
1190
+ * time under its switch.
1191
+ */
1192
+ const PRACTICE_REMINDER_CATEGORY_KEY = "practice";
1193
+ /**
1194
+ * When practice reminders reach someone who never chose a time: 18:00 in
1195
+ * their own time zone. The page shows it as the choice until one is made;
1196
+ * Ribbit's reminder automation sets the same as its own time, for people
1197
+ * without one (docs/ribbit/phase-3-automations.md).
1198
+ */
1199
+ const PRACTICE_REMINDER_DEFAULT_TIME = "18:00";
1200
+ /** A time of day on the hour, `HH:00`: Ribbit takes people into a schedule once an hour. */
1201
+ const practiceReminderTimeSchema = z.string().regex(/^([01]\d|2[0-3]):00$/, "Choose a time on the hour.");
1202
+ /** The times the page offers: every hour of the day. */
1203
+ const PRACTICE_REMINDER_TIMES = Array.from({ length: 24 }, (_, hour) => `${String(hour).padStart(2, "0")}:00`);
1204
+ /**
1205
+ * The reminders area of `user_preferences`, as the database holds it: what
1206
+ * is not there, or no longer reads, is the default. `practiceTime` is the
1207
+ * practice reminder's time of day, in the person's own zone; null until they
1208
+ * choose one.
1209
+ */
1210
+ const remindersPreferencesSchema = z.object({ practiceTime: practiceReminderTimeSchema.nullable().catch(null).default(null) });
946
1211
  const emailPreferencesStateSchema = z.object({
947
1212
  categories: z.array(emailCategoryStateSchema),
948
- unsubscribedAll: z.boolean()
1213
+ unsubscribedAll: z.boolean(),
1214
+ practiceReminderTime: practiceReminderTimeSchema.nullable()
949
1215
  }).strict();
950
1216
  /**
951
1217
  * What the page a link opens shows on top of the state: whose preferences they
@@ -958,7 +1224,8 @@ const emailPreferencesByTokenStateSchema = z.object({
958
1224
  }).strict();
959
1225
  const emailPreferencesChangesShape = {
960
1226
  categories: z.record(emailCategoryKeySchema, z.boolean()).optional(),
961
- unsubscribedAll: z.boolean().optional()
1227
+ unsubscribedAll: z.boolean().optional(),
1228
+ practiceReminderTime: practiceReminderTimeSchema.nullable().optional()
962
1229
  };
963
1230
  const emailPreferencesGetInputSchema = z.object({ locale: appLocaleSchema }).strict();
964
1231
  const emailPreferencesUpdateInputSchema = z.object({
@@ -1022,6 +1289,12 @@ const featureAccessContract = { status: oc.route({
1022
1289
  //#region src/contracts/hosted-ai.ts
1023
1290
  const hostedAiStreamErrors = pickPublicErrorMap("HOSTED_AI_TIER_RESTRICTED", "HOSTED_AI_QUOTA_EXHAUSTED");
1024
1291
  const hostedAiContract = {
1292
+ pools: oc.route({
1293
+ method: "GET",
1294
+ path: "/hosted-ai/pools",
1295
+ summary: "Get shared Built-in AI credit pools for a feature",
1296
+ tags: ["Hosted AI"]
1297
+ }).input(HostedAiCreditPoolsInputSchema).output(HostedAiCreditPoolsOutputSchema),
1025
1298
  status: oc.route({
1026
1299
  method: "GET",
1027
1300
  path: "/hosted-ai/status",
@@ -1397,6 +1670,7 @@ const notebaseSchema = z.object({
1397
1670
  srsWeights: srsWeightsSchema.nullable(),
1398
1671
  srsModelVersion: srsModelVersionSchema,
1399
1672
  srsSleepingAt: z.date().nullable(),
1673
+ srsSleepSource: srsSleepSourceSchema.nullable(),
1400
1674
  createdAt: z.date(),
1401
1675
  updatedAt: z.date()
1402
1676
  });
@@ -1566,7 +1840,7 @@ const notebaseColumnContract = {
1566
1840
  method: "DELETE",
1567
1841
  path: "/notebase-columns/{notebaseColumnId}",
1568
1842
  summary: "Delete notebase field",
1569
- description: "Delete an owned field and remove its values from notes. Primary fields and fields referenced by templates cannot be deleted.",
1843
+ 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.",
1570
1844
  tags: ["Notebase Columns"]
1571
1845
  }).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),
1572
1846
  reorder: oc.errors(pickPublicErrorMap("NOTEBASE_NOT_FOUND", "CONCURRENT_POSITION_CONFLICT")).route({
@@ -1643,6 +1917,65 @@ const notebaseRowContract = {
1643
1917
  }).input(NotebaseRowReorderInputSchema).output(NotebaseRowReorderOutputSchema)
1644
1918
  };
1645
1919
  //#endregion
1920
+ //#region src/contracts/pdf-translation.ts
1921
+ const pdfTranslationProcedure = oc.errors(pickPublicErrorMap("PDF_TRANSLATION_UNAVAILABLE"));
1922
+ const pdfTranslationContract = {
1923
+ status: pdfTranslationProcedure.route({
1924
+ method: "GET",
1925
+ path: "/pdf-translations/status",
1926
+ summary: "How many free PDF translations the account has left",
1927
+ tags: ["PDF Translation"]
1928
+ }).input(pdfTranslationStatusInputSchema).output(pdfTranslationStatusOutputSchema),
1929
+ list: pdfTranslationProcedure.route({
1930
+ method: "GET",
1931
+ path: "/pdf-translations",
1932
+ summary: "List recent PDF translations",
1933
+ tags: ["PDF Translation"]
1934
+ }).input(pdfTranslationListInputSchema).output(pdfTranslationListOutputSchema),
1935
+ requestUpload: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_FILE_TOO_LARGE")).route({
1936
+ method: "POST",
1937
+ path: "/pdf-translations/uploads",
1938
+ summary: "Request a signed upload for a PDF to translate",
1939
+ tags: ["PDF Translation"]
1940
+ }).input(pdfTranslationRequestUploadInputSchema).output(pdfTranslationRequestUploadOutputSchema),
1941
+ 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({
1942
+ method: "POST",
1943
+ path: "/pdf-translations",
1944
+ summary: "Translate uploaded PDFs",
1945
+ tags: ["PDF Translation"]
1946
+ }).input(pdfTranslationSubmitInputSchema).output(pdfTranslationSubmitOutputSchema),
1947
+ get: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_NOT_FOUND")).route({
1948
+ method: "GET",
1949
+ path: "/pdf-translations/{id}",
1950
+ summary: "Get a PDF translation's status, with the others submitted with it",
1951
+ tags: ["PDF Translation"]
1952
+ }).input(pdfTranslationJobIdInputSchema).output(pdfTranslationGetOutputSchema),
1953
+ cancel: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_NOT_FOUND", "PDF_TRANSLATION_NOT_CANCELLABLE")).route({
1954
+ method: "POST",
1955
+ path: "/pdf-translations/{id}/cancel",
1956
+ summary: "Cancel a PDF translation",
1957
+ tags: ["PDF Translation"]
1958
+ }).input(pdfTranslationJobIdInputSchema).output(pdfTranslationJobResourceSchema),
1959
+ getPreviewUrl: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_NOT_FOUND", "PDF_TRANSLATION_NOT_READY")).route({
1960
+ method: "GET",
1961
+ path: "/pdf-translations/{id}/preview-url",
1962
+ summary: "Get a short-lived URL to read a translated PDF in the browser",
1963
+ tags: ["PDF Translation"]
1964
+ }).input(pdfTranslationOutputInputSchema).output(pdfTranslationPreviewOutputSchema),
1965
+ getDownloadUrl: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_NOT_FOUND", "PDF_TRANSLATION_NOT_READY", "PDF_TRANSLATION_DOWNLOAD_RESTRICTED")).route({
1966
+ method: "GET",
1967
+ path: "/pdf-translations/{id}/download-url",
1968
+ summary: "Get a download URL for a translated PDF",
1969
+ tags: ["PDF Translation"]
1970
+ }).input(pdfTranslationOutputInputSchema).output(pdfTranslationDownloadOutputSchema),
1971
+ delete: pdfTranslationProcedure.errors(pickPublicErrorMap("PDF_TRANSLATION_NOT_FOUND", "PDF_TRANSLATION_NOT_DELETABLE")).route({
1972
+ method: "DELETE",
1973
+ path: "/pdf-translations/{id}",
1974
+ summary: "Delete a finished PDF translation and its files",
1975
+ tags: ["PDF Translation"]
1976
+ }).input(pdfTranslationJobIdInputSchema).output(pdfTranslationDeleteOutputSchema)
1977
+ };
1978
+ //#endregion
1646
1979
  //#region src/schemas/speech.ts
1647
1980
  /** The longest text one request reads aloud. */
1648
1981
  const SPEECH_TEXT_MAX_LENGTH = 500;
@@ -1910,6 +2243,122 @@ function bytesToUuid(bytes) {
1910
2243
  hex.slice(10, 16).join("")
1911
2244
  ].join("-");
1912
2245
  }
2246
+ const count = z.number().int().nonnegative();
2247
+ const srsBacklogStatsInputSchema = z.object({
2248
+ notebaseIds: z.array(z.uuid()).optional(),
2249
+ timezone: canonicalTimezoneSchema
2250
+ }).strict();
2251
+ /**
2252
+ * An Awake notebase with a positive daily review limit whose overdue reviews
2253
+ * fill at least `BACKLOG_PROMPT_DAYS.badge` days.
2254
+ */
2255
+ const srsBacklogStatsSchema = z.object({
2256
+ overdueReviewCount: count.describe("Review cards whose due date is before the start of today's study day."),
2257
+ 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."),
2258
+ backlogDays: z.number().nonnegative().describe("Days of reviews the backlog fills at that limit: overdueReviewCount / dailyLimit.")
2259
+ });
2260
+ /** Only the notebases that get the badge; the rest are absent. */
2261
+ const srsBacklogStatsOutputSchema = z.record(z.uuid(), srsBacklogStatsSchema);
2262
+ const rescheduleDailyLimitSchema = z.number().int().positive();
2263
+ const srsPreviewPostponeInputSchema = z.object({
2264
+ notebaseId: z.uuid(),
2265
+ timezone: canonicalTimezoneSchema,
2266
+ dailyLimit: rescheduleDailyLimitSchema.optional(),
2267
+ flattenFullRange: z.boolean().optional().describe("Flatten levels every plannable day (180) instead of only the chart days.")
2268
+ }).strict();
2269
+ const postponeThresholdSchema = z.number().min(POSTPONE_DAMAGE_THRESHOLD.min).max(POSTPONE_DAMAGE_THRESHOLD.max);
2270
+ const postponeDaySchema = z.object({
2271
+ day: z.number().int().positive(),
2272
+ postponed: count,
2273
+ rSum: z.number()
2274
+ });
2275
+ const rescheduleBaselineDaySchema = z.object({
2276
+ day: z.number().int().positive(),
2277
+ scheduled: count,
2278
+ rSum: z.number().nullable()
2279
+ });
2280
+ const spreadDaySchema = z.object({
2281
+ day: count,
2282
+ scheduled: count,
2283
+ backlog: count,
2284
+ backlogRSum: z.number(),
2285
+ surplusIn: count,
2286
+ surplusRSum: z.number(),
2287
+ surplusStay: count,
2288
+ surplusOut: count
2289
+ });
2290
+ const spreadKeptSchema = z.object({
2291
+ stuck: count,
2292
+ noRoom: count
2293
+ });
2294
+ const flattenStepSchema = z.object({
2295
+ checked: z.boolean(),
2296
+ fromToday: count,
2297
+ fromFuture: count,
2298
+ fromDays: count,
2299
+ kept: spreadKeptSchema,
2300
+ qSuggest: count,
2301
+ meanRAfter: z.number(),
2302
+ days: z.array(spreadDaySchema),
2303
+ /** Cards Postpone already moved that this Flatten moves again, and their R under Postpone. */
2304
+ postponedAgain: z.object({
2305
+ count,
2306
+ rSum: z.number()
2307
+ })
2308
+ });
2309
+ /** One threshold's Postpone alone, before its Flatten option is attached. */
2310
+ const postponeSummarySchema = z.object({
2311
+ threshold: postponeThresholdSchema,
2312
+ moved: count,
2313
+ overflowToday: count,
2314
+ meanRiBefore: z.number(),
2315
+ meanRAfter: z.number(),
2316
+ days: z.array(postponeDaySchema)
2317
+ });
2318
+ const postponeStepSchema = postponeSummarySchema.extend({ flatten: flattenStepSchema.nullable() });
2319
+ const postponePlanSchema = z.object({
2320
+ planId: z.string(),
2321
+ limit: z.number().int().positive(),
2322
+ steps: z.array(postponeStepSchema),
2323
+ skipped: z.object({
2324
+ belowFloor: count,
2325
+ maxInterval: count,
2326
+ invalid: count
2327
+ })
2328
+ });
2329
+ const rescheduleReadySchema = z.object({
2330
+ status: z.literal("ready"),
2331
+ expiresAt: z.date(),
2332
+ q: z.number().int().positive(),
2333
+ qConfigured: schedulingParamsShape.reviewsPerDay,
2334
+ qMax: z.number().int().positive(),
2335
+ overdueReviewCount: count,
2336
+ dueTodayReviewCount: count,
2337
+ usedToday: count
2338
+ });
2339
+ const srsPreviewPostponeOutputSchema = z.discriminatedUnion("status", [
2340
+ rescheduleReadySchema.extend({
2341
+ plan: postponePlanSchema,
2342
+ suggested: postponePlanSchema.nullable(),
2343
+ baseline: z.array(rescheduleBaselineDaySchema)
2344
+ }),
2345
+ z.object({ status: z.literal("quotaZero") }),
2346
+ z.object({ status: z.literal("invalidWeights") })
2347
+ ]);
2348
+ const srsApplyPostponeInputSchema = z.object({
2349
+ notebaseId: z.uuid(),
2350
+ planId: z.string().min(1),
2351
+ unlimited: z.boolean().optional()
2352
+ }).extend({
2353
+ threshold: postponeThresholdSchema,
2354
+ flatten: z.boolean().optional()
2355
+ }).strict();
2356
+ const srsRescheduleApplyOutputSchema = z.object({
2357
+ moved: count,
2358
+ txid: z.number().nullable(),
2359
+ reviewsPerDay: schedulingParamsShape.reviewsPerDay
2360
+ });
2361
+ const srsApplyPostponeOutputSchema = srsRescheduleApplyOutputSchema;
1913
2362
  //#endregion
1914
2363
  //#region src/contracts/srs.ts
1915
2364
  const srsContract = {
@@ -1973,7 +2422,19 @@ const srsContract = {
1973
2422
  summary: "Set card suspended",
1974
2423
  description: "Suspend or resume one owned card. enabled=true suspends and enabled=false resumes it. Existing state-change rules apply.",
1975
2424
  tags: ["SRS"]
1976
- }).errors(pickPublicErrorMap("CARD_NOT_FOUND", "CARD_ALREADY_SUSPENDED", "CARD_NOT_SUSPENDED", "CARD_STATUS_CHANGE_UNAVAILABLE")).input(srsSetCardSuspendedInputSchema).output(srsSetCardSuspendedOutputSchema)
2425
+ }).errors(pickPublicErrorMap("CARD_NOT_FOUND", "CARD_ALREADY_SUSPENDED", "CARD_NOT_SUSPENDED", "CARD_STATUS_CHANGE_UNAVAILABLE")).input(srsSetCardSuspendedInputSchema).output(srsSetCardSuspendedOutputSchema),
2426
+ previewPostpone: oc.errors(pickPublicErrorMap("NOTEBASE_NOT_FOUND", "RESCHEDULE_PREVIEW_TIMEOUT", "RESCHEDULE_DAILY_LIMIT_INVALID")).route({
2427
+ method: "POST",
2428
+ path: "/srs/postpone/preview",
2429
+ summary: "Preview postpone",
2430
+ tags: ["SRS"]
2431
+ }).input(srsPreviewPostponeInputSchema).output(srsPreviewPostponeOutputSchema),
2432
+ applyPostpone: oc.errors(pickPublicErrorMap("NOTEBASE_NOT_FOUND", "RESCHEDULE_PLAN_EXPIRED", "RESCHEDULE_STALE")).route({
2433
+ method: "POST",
2434
+ path: "/srs/postpone",
2435
+ summary: "Apply postpone",
2436
+ tags: ["SRS"]
2437
+ }).input(srsApplyPostponeInputSchema).output(srsApplyPostponeOutputSchema)
1977
2438
  };
1978
2439
  //#endregion
1979
2440
  //#region src/schemas/notebase-stats.ts
@@ -2045,7 +2506,14 @@ const statsContract = {
2045
2506
  path: "/notebases/stats/row-growth",
2046
2507
  summary: "Get notebase row growth statistics",
2047
2508
  tags: ["Statistics"]
2048
- }).input(statsInputSchema).output(notebaseRowGrowthStatsOutputSchema)
2509
+ }).input(statsInputSchema).output(notebaseRowGrowthStatsOutputSchema),
2510
+ backlogStats: defineAgentProcedure({
2511
+ method: "GET",
2512
+ path: "/srs/stats/backlog",
2513
+ summary: "Get review backlogs",
2514
+ 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.",
2515
+ tags: ["Statistics"]
2516
+ }).errors(pickPublicErrorMap("NOTEBASE_NOT_FOUND")).input(srsBacklogStatsInputSchema).output(srsBacklogStatsOutputSchema)
2049
2517
  };
2050
2518
  //#endregion
2051
2519
  //#region src/schemas/user.ts
@@ -2152,6 +2620,7 @@ const contract = {
2152
2620
  notebase: notebaseContract,
2153
2621
  notebaseColumn: notebaseColumnContract,
2154
2622
  notebaseRow: notebaseRowContract,
2623
+ pdfTranslation: pdfTranslationContract,
2155
2624
  speech: speechContract,
2156
2625
  srs: srsContract,
2157
2626
  stats: statsContract,
@@ -2184,6 +2653,6 @@ const contract = {
2184
2653
  }
2185
2654
  };
2186
2655
  //#endregion
2187
- 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, 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 };
2656
+ 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, 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, 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, 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, pdfTranslationDeleteOutputSchema, pdfTranslationDownloadOutputSchema, pdfTranslationGetOutputSchema, pdfTranslationJobIdInputSchema, pdfTranslationJobResourceSchema, pdfTranslationJobStatusSchema, pdfTranslationListInputSchema, pdfTranslationListOutputSchema, pdfTranslationOutputInputSchema, pdfTranslationOutputVariantSchema, pdfTranslationPreviewOutputSchema, pdfTranslationRequestUploadInputSchema, pdfTranslationRequestUploadOutputSchema, pdfTranslationStatusInputSchema, pdfTranslationStatusOutputSchema, pdfTranslationSubmitInputSchema, pdfTranslationSubmitOutputSchema, pickPublicErrorMap, postponePlanSchema, postponeStepSchema, postponeSummarySchema, practiceReminderTimeSchema, remindersPreferencesSchema, renderedCardSchema, 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 };
2188
2657
 
2189
2658
  //# sourceMappingURL=index.js.map