@vestcards/server-types 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/apps/server/src/app.d.ts +155 -4
  2. package/dist/apps/server/src/config/env.d.ts +2 -2
  3. package/dist/apps/server/src/libs/mappers.d.ts +5 -0
  4. package/dist/apps/server/src/modules/auth/index.d.ts +2 -2
  5. package/dist/apps/server/src/modules/auth/lib.d.ts +69 -16
  6. package/dist/apps/server/src/modules/auth/utils.d.ts +1 -0
  7. package/dist/apps/server/src/modules/card/index.d.ts +92 -3
  8. package/dist/apps/server/src/modules/card/model.d.ts +17 -0
  9. package/dist/apps/server/src/modules/card/service.d.ts +8 -1
  10. package/dist/apps/server/src/modules/deck/index.d.ts +2 -2
  11. package/dist/apps/server/src/modules/library/index.d.ts +2 -2
  12. package/dist/apps/server/src/modules/study/index.d.ts +2 -2
  13. package/dist/apps/server/src/modules/study/service.d.ts +3 -3
  14. package/dist/apps/server/src/modules/topic/index.d.ts +2 -2
  15. package/dist/apps/server/src/modules/user/errors.d.ts +3 -0
  16. package/dist/apps/server/src/modules/user/index.d.ts +65 -3
  17. package/dist/apps/server/src/modules/user/model.d.ts +6 -0
  18. package/dist/apps/server/src/modules/user/service.d.ts +4 -0
  19. package/dist/apps/server/src/tests/helpers/fixtures.d.ts +1 -0
  20. package/dist/apps/server/src/utils/api.d.ts +1 -1
  21. package/dist/apps/server/src/utils/select.d.ts +17 -0
  22. package/dist/packages/db-core/src/schema/auth.d.ts +60 -0
  23. package/dist/packages/db-core/src/schema/deck.d.ts +17 -0
  24. package/dist/packages/db-core/src/schema/index.d.ts +1 -0
  25. package/dist/packages/email-core/src/templates/deleteAccountRequest.d.ts +8 -0
  26. package/dist/packages/email-core/src/templates/footer.d.ts +1 -1
  27. package/dist/packages/email-core/src/templates/index.d.ts +2 -0
  28. package/dist/packages/shared/src/spaced-repetition/config.d.ts +5 -0
  29. package/dist/packages/shared/src/spaced-repetition/fsrs.d.ts +13 -0
  30. package/dist/packages/shared/src/spaced-repetition/index.d.ts +4 -0
  31. package/dist/packages/shared/src/spaced-repetition/session-manager.d.ts +25 -0
  32. package/dist/packages/shared/src/spaced-repetition/utils.d.ts +26 -0
  33. package/dist/packages/shared/src/theme/tokens/border.d.ts +1 -1
  34. package/dist/packages/shared/src/types/deck.d.ts +11 -1
  35. package/dist/packages/shared/src/types/permissions.d.ts +4 -0
  36. package/package.json +1 -1
  37. package/dist/apps/server/src/modules/study/lib/fsrs.d.ts +0 -12
  38. /package/dist/apps/server/src/modules/study/{lib/constants.d.ts → constants.d.ts} +0 -0
@@ -65,7 +65,7 @@ declare const app: Elysia<"", {
65
65
  route: string;
66
66
  request: Request;
67
67
  store: {};
68
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
68
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
69
69
  readonly 100: "Continue";
70
70
  readonly 101: "Switching Protocols";
71
71
  readonly 102: "Processing";
@@ -239,7 +239,7 @@ declare const app: Elysia<"", {
239
239
  route: string;
240
240
  request: Request;
241
241
  store: {};
242
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
242
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
243
243
  readonly 100: "Continue";
244
244
  readonly 101: "Switching Protocols";
245
245
  readonly 102: "Processing";
@@ -450,11 +450,11 @@ declare const app: Elysia<"", {
450
450
  headers: {};
451
451
  response: {
452
452
  200: {
453
+ status: "not-reviewed" | "card-updated" | "demand-rejected" | "card-removed";
453
454
  type: string;
454
455
  createdAt: Date;
455
456
  updatedAt: Date;
456
457
  userId: string;
457
- status: "not-reviewed" | "card-updated" | "demand-rejected" | "card-removed";
458
458
  cardId: string;
459
459
  content: string;
460
460
  } | null;
@@ -503,6 +503,95 @@ declare const app: Elysia<"", {
503
503
  };
504
504
  };
505
505
  };
506
+ } & {
507
+ v1: {
508
+ card: {
509
+ suspend: {
510
+ post: {
511
+ body: {
512
+ cardId: string;
513
+ };
514
+ params: {};
515
+ query: {};
516
+ headers: {};
517
+ response: {
518
+ 200: {
519
+ success: boolean;
520
+ };
521
+ 422: {
522
+ type: "validation";
523
+ on: string;
524
+ summary?: string;
525
+ message?: string;
526
+ found?: unknown;
527
+ property?: string;
528
+ expected?: string;
529
+ };
530
+ };
531
+ };
532
+ };
533
+ };
534
+ };
535
+ } & {
536
+ v1: {
537
+ card: {
538
+ suspend: {
539
+ delete: {
540
+ body: {};
541
+ params: {};
542
+ query: {
543
+ cardId: string;
544
+ };
545
+ headers: {};
546
+ response: {
547
+ 200: {
548
+ success: boolean;
549
+ };
550
+ 422: {
551
+ type: "validation";
552
+ on: string;
553
+ summary?: string;
554
+ message?: string;
555
+ found?: unknown;
556
+ property?: string;
557
+ expected?: string;
558
+ };
559
+ };
560
+ };
561
+ };
562
+ };
563
+ };
564
+ } & {
565
+ v1: {
566
+ card: {
567
+ "user-state": {
568
+ get: {
569
+ body: {};
570
+ params: {};
571
+ query: {
572
+ deckId: string;
573
+ };
574
+ headers: {};
575
+ response: {
576
+ 200: {
577
+ cardId: string;
578
+ suspended: boolean;
579
+ toReview: boolean;
580
+ }[];
581
+ 422: {
582
+ type: "validation";
583
+ on: string;
584
+ summary?: string;
585
+ message?: string;
586
+ found?: unknown;
587
+ property?: string;
588
+ expected?: string;
589
+ };
590
+ };
591
+ };
592
+ };
593
+ };
594
+ };
506
595
  } & {
507
596
  v1: {
508
597
  decks: {
@@ -1165,6 +1254,68 @@ declare const app: Elysia<"", {
1165
1254
  };
1166
1255
  };
1167
1256
  };
1257
+ } & {
1258
+ v1: {
1259
+ user: {
1260
+ account: {
1261
+ "delete-request": {
1262
+ post: {
1263
+ body: {
1264
+ email: string;
1265
+ };
1266
+ params: {};
1267
+ query: {};
1268
+ headers: {};
1269
+ response: {
1270
+ 200: {
1271
+ success: boolean;
1272
+ };
1273
+ 422: {
1274
+ type: "validation";
1275
+ on: string;
1276
+ summary?: string;
1277
+ message?: string;
1278
+ found?: unknown;
1279
+ property?: string;
1280
+ expected?: string;
1281
+ };
1282
+ };
1283
+ };
1284
+ };
1285
+ };
1286
+ };
1287
+ };
1288
+ } & {
1289
+ v1: {
1290
+ user: {
1291
+ account: {
1292
+ "confirm-delete": {
1293
+ post: {
1294
+ body: {
1295
+ token: string;
1296
+ };
1297
+ params: {};
1298
+ query: {};
1299
+ headers: {};
1300
+ response: {
1301
+ 200: {
1302
+ success: boolean;
1303
+ };
1304
+ 422: {
1305
+ type: "validation";
1306
+ on: string;
1307
+ summary?: string;
1308
+ message?: string;
1309
+ found?: unknown;
1310
+ property?: string;
1311
+ expected?: string;
1312
+ };
1313
+ };
1314
+ };
1315
+ };
1316
+ };
1317
+ };
1318
+ };
1168
1319
  } & {
1169
1320
  v1: {
1170
1321
  user: {
@@ -1190,8 +1341,8 @@ declare const app: Elysia<"", {
1190
1341
  "complete-profile": {
1191
1342
  post: {
1192
1343
  body: {
1193
- dayTimeReminder?: string | undefined;
1194
1344
  university?: number | undefined;
1345
+ dayTimeReminder?: string | undefined;
1195
1346
  course?: number | undefined;
1196
1347
  goal: string;
1197
1348
  hoursStudied: string;
@@ -2,8 +2,8 @@ export declare const config: {
2
2
  databaseUrl: string;
3
3
  baseUrl: string;
4
4
  webAppUrl: string;
5
- redisUrl: string | undefined;
6
- redisToken: string | undefined;
5
+ redisUrl: string;
6
+ redisToken: string;
7
7
  betterAuthSecret: string;
8
8
  googleClientId: string;
9
9
  googleClientSecret: string;
@@ -0,0 +1,5 @@
1
+ import type { CardReview, NewCardReview, NewReviewLog } from '@vestcards/db-core';
2
+ import type { ICardReview, IReviewLog } from '@vestcards/shared';
3
+ export declare function cardReviewToICardReview(row: CardReview): ICardReview;
4
+ export declare function iCardReviewToNewCardReview(card: ICardReview): NewCardReview;
5
+ export declare function iReviewLogToNewReviewLog(log: IReviewLog): NewReviewLog;
@@ -41,7 +41,7 @@ export declare const authModule: Elysia<"/v1", {
41
41
  route: string;
42
42
  request: Request;
43
43
  store: {};
44
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
44
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
45
45
  readonly 100: "Continue";
46
46
  readonly 101: "Switching Protocols";
47
47
  readonly 102: "Processing";
@@ -215,7 +215,7 @@ export declare const authModule: Elysia<"/v1", {
215
215
  route: string;
216
216
  request: Request;
217
217
  store: {};
218
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
218
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
219
219
  readonly 100: "Continue";
220
220
  readonly 101: "Switching Protocols";
221
221
  readonly 102: "Processing";
@@ -1,8 +1,9 @@
1
1
  import { UserRole } from '@vestcards/shared';
2
2
  import { type BetterAuthOptions } from 'better-auth';
3
3
  export declare const auth: import("better-auth").Auth<{
4
- plugins: [{
4
+ plugins: ({
5
5
  id: "open-api";
6
+ version: string;
6
7
  endpoints: {
7
8
  generateOpenAPISchema: import("better-call").StrictEndpoint<"/open-api/generate-schema", {
8
9
  method: "GET";
@@ -52,8 +53,9 @@ export declare const auth: import("better-auth").Auth<{
52
53
  }, Response>;
53
54
  };
54
55
  options: NoInfer<import("better-auth/plugins").OpenAPIOptions>;
55
- }, {
56
+ } | {
56
57
  id: "expo";
58
+ version: string;
57
59
  init: (ctx: import("better-auth").AuthContext) => {
58
60
  options: {
59
61
  trustedOrigins: string[];
@@ -71,10 +73,10 @@ export declare const auth: import("better-auth").Auth<{
71
73
  endpoints: {
72
74
  expoAuthorizationProxy: import("better-call").StrictEndpoint<"/expo-authorization-proxy", {
73
75
  method: "GET";
74
- query: import("better-auth").ZodObject<{
75
- authorizationURL: import("better-auth").ZodString;
76
- oauthState: import("better-auth").ZodOptional<import("better-auth").ZodString>;
77
- }, import("better-auth").$strip>;
76
+ query: import("zod").ZodObject<{
77
+ authorizationURL: import("zod").ZodString;
78
+ oauthState: import("zod").ZodOptional<import("zod").ZodString>;
79
+ }, import("zod/v4/core").$strip>;
78
80
  metadata: {
79
81
  readonly scope: "server";
80
82
  };
@@ -94,8 +96,27 @@ export declare const auth: import("better-auth").Auth<{
94
96
  }>;
95
97
  };
96
98
  options: import("@better-auth/expo").ExpoOptions | undefined;
97
- }, {
99
+ } | {
100
+ id: "bearer";
101
+ version: string;
102
+ hooks: {
103
+ before: {
104
+ matcher(context: import("better-auth").HookEndpointContext): boolean;
105
+ handler: (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
106
+ context: {
107
+ headers: Headers;
108
+ };
109
+ } | undefined>;
110
+ }[];
111
+ after: {
112
+ matcher(context: import("better-auth").HookEndpointContext): true;
113
+ handler: (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>;
114
+ }[];
115
+ };
116
+ options: import("better-auth/plugins").BearerOptions | undefined;
117
+ } | {
98
118
  id: "custom-session";
119
+ version: string;
99
120
  hooks: {
100
121
  after: {
101
122
  matcher: (ctx: import("better-auth").HookEndpointContext) => boolean;
@@ -130,10 +151,10 @@ export declare const auth: import("better-auth").Auth<{
130
151
  endpoints: {
131
152
  getSession: import("better-call").StrictEndpoint<"/get-session", {
132
153
  method: "GET";
133
- query: import("better-auth").ZodOptional<import("better-auth").ZodObject<{
134
- disableCookieCache: import("better-auth").ZodOptional<import("better-auth").ZodUnion<[import("better-auth").ZodBoolean, import("better-auth").ZodPipe<import("better-auth").ZodString, import("better-auth").ZodTransform<boolean, string>>]>>;
135
- disableRefresh: import("better-auth").ZodOptional<import("better-auth").ZodBoolean>;
136
- }, import("better-auth").$strip>>;
154
+ query: import("zod").ZodOptional<import("zod").ZodObject<{
155
+ disableCookieCache: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodBoolean, import("zod").ZodPipe<import("zod").ZodString, import("zod").ZodTransform<boolean, string>>]>>;
156
+ disableRefresh: import("zod").ZodOptional<import("zod").ZodBoolean>;
157
+ }, import("zod/v4/core").$strip>>;
137
158
  metadata: {
138
159
  CUSTOM_SESSION: boolean;
139
160
  openapi: {
@@ -213,15 +234,15 @@ export declare const auth: import("better-auth").Auth<{
213
234
  };
214
235
  };
215
236
  options: import("better-auth/plugins").CustomSessionPluginOptions | undefined;
216
- }];
237
+ })[];
217
238
  baseURL: string;
218
239
  basePath: string;
219
240
  database: (options: BetterAuthOptions) => import("better-auth").DBAdapter<BetterAuthOptions>;
220
241
  secondaryStorage: import("better-auth").SecondaryStorage | undefined;
221
242
  emailAndPassword: {
222
243
  enabled: true;
223
- autoSignIn: false;
224
- requireEmailVerification: boolean;
244
+ autoSignIn: true;
245
+ requireEmailVerification: false;
225
246
  minPasswordLength: number;
226
247
  maxPasswordLength: number;
227
248
  password: {
@@ -268,6 +289,10 @@ export declare const auth: import("better-auth").Auth<{
268
289
  google: {
269
290
  clientId: string;
270
291
  clientSecret: string;
292
+ mapProfileToUser: (profile: import("better-auth").GoogleProfile) => {
293
+ name: string;
294
+ surname: string;
295
+ };
271
296
  };
272
297
  apple: {
273
298
  clientId: string;
@@ -318,16 +343,41 @@ export declare const auth: import("better-auth").Auth<{
318
343
  }>;
319
344
  };
320
345
  };
346
+ session: {
347
+ create: {
348
+ before: (session: {
349
+ id: string;
350
+ createdAt: Date;
351
+ updatedAt: Date;
352
+ userId: string;
353
+ expiresAt: Date;
354
+ token: string;
355
+ ipAddress?: string | null | undefined;
356
+ userAgent?: string | null | undefined;
357
+ } & Record<string, unknown>) => Promise<{
358
+ data: {
359
+ id: string;
360
+ createdAt: Date;
361
+ updatedAt: Date;
362
+ userId: string;
363
+ expiresAt: Date;
364
+ token: string;
365
+ ipAddress?: string | null | undefined;
366
+ userAgent?: string | null | undefined;
367
+ } & Record<string, unknown>;
368
+ }>;
369
+ };
370
+ };
321
371
  };
322
372
  logger: {
323
- log(level: "info" | "debug" | "warn" | "error", message: string, ...args: any[]): void;
373
+ log(level: "error" | "warn" | "info" | "debug", message: string, ...args: any[]): void;
324
374
  };
325
375
  advanced: {
326
376
  useSecureCookies: boolean;
327
377
  disableOriginCheck: true;
328
378
  cookiePrefix: string;
329
379
  defaultCookieAttributes: {
330
- sameSite: "none" | "lax";
380
+ sameSite: "lax" | "none";
331
381
  secure: boolean;
332
382
  };
333
383
  database: {
@@ -335,5 +385,8 @@ export declare const auth: import("better-auth").Auth<{
335
385
  };
336
386
  };
337
387
  trustedOrigins: string[];
388
+ hooks: {
389
+ before: (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>;
390
+ };
338
391
  }>;
339
392
  export type Auth = typeof auth;
@@ -1,4 +1,5 @@
1
1
  import type { BetterAuthOptions } from 'better-auth';
2
+ export declare function assertCredentialAccount(userId: string): Promise<void>;
2
3
  type SendVerificationEmail = NonNullable<BetterAuthOptions['emailVerification']>['sendVerificationEmail'];
3
4
  export declare const sendVerificationEmail: SendVerificationEmail;
4
5
  type SendResetPassword = NonNullable<BetterAuthOptions['emailAndPassword']>['sendResetPassword'];
@@ -42,7 +42,7 @@ export declare const cardModule: Elysia<"/v1/card", {
42
42
  route: string;
43
43
  request: Request;
44
44
  store: {};
45
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
45
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
46
46
  readonly 100: "Continue";
47
47
  readonly 101: "Switching Protocols";
48
48
  readonly 102: "Processing";
@@ -216,7 +216,7 @@ export declare const cardModule: Elysia<"/v1/card", {
216
216
  route: string;
217
217
  request: Request;
218
218
  store: {};
219
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
219
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
220
220
  readonly 100: "Continue";
221
221
  readonly 101: "Switching Protocols";
222
222
  readonly 102: "Processing";
@@ -392,11 +392,11 @@ export declare const cardModule: Elysia<"/v1/card", {
392
392
  headers: {};
393
393
  response: {
394
394
  200: {
395
+ status: "not-reviewed" | "card-updated" | "demand-rejected" | "card-removed";
395
396
  type: string;
396
397
  createdAt: Date;
397
398
  updatedAt: Date;
398
399
  userId: string;
399
- status: "not-reviewed" | "card-updated" | "demand-rejected" | "card-removed";
400
400
  cardId: string;
401
401
  content: string;
402
402
  } | null;
@@ -445,6 +445,95 @@ export declare const cardModule: Elysia<"/v1/card", {
445
445
  };
446
446
  };
447
447
  };
448
+ } & {
449
+ v1: {
450
+ card: {
451
+ suspend: {
452
+ post: {
453
+ body: {
454
+ cardId: string;
455
+ };
456
+ params: {};
457
+ query: {};
458
+ headers: {};
459
+ response: {
460
+ 200: {
461
+ success: boolean;
462
+ };
463
+ 422: {
464
+ type: "validation";
465
+ on: string;
466
+ summary?: string;
467
+ message?: string;
468
+ found?: unknown;
469
+ property?: string;
470
+ expected?: string;
471
+ };
472
+ };
473
+ };
474
+ };
475
+ };
476
+ };
477
+ } & {
478
+ v1: {
479
+ card: {
480
+ suspend: {
481
+ delete: {
482
+ body: {};
483
+ params: {};
484
+ query: {
485
+ cardId: string;
486
+ };
487
+ headers: {};
488
+ response: {
489
+ 200: {
490
+ success: boolean;
491
+ };
492
+ 422: {
493
+ type: "validation";
494
+ on: string;
495
+ summary?: string;
496
+ message?: string;
497
+ found?: unknown;
498
+ property?: string;
499
+ expected?: string;
500
+ };
501
+ };
502
+ };
503
+ };
504
+ };
505
+ };
506
+ } & {
507
+ v1: {
508
+ card: {
509
+ "user-state": {
510
+ get: {
511
+ body: {};
512
+ params: {};
513
+ query: {
514
+ deckId: string;
515
+ };
516
+ headers: {};
517
+ response: {
518
+ 200: {
519
+ cardId: string;
520
+ suspended: boolean;
521
+ toReview: boolean;
522
+ }[];
523
+ 422: {
524
+ type: "validation";
525
+ on: string;
526
+ summary?: string;
527
+ message?: string;
528
+ found?: unknown;
529
+ property?: string;
530
+ expected?: string;
531
+ };
532
+ };
533
+ };
534
+ };
535
+ };
536
+ };
448
537
  }, {
449
538
  derive: {};
450
539
  resolve: {};
@@ -1,4 +1,9 @@
1
1
  export declare namespace CardModel {
2
+ /**
3
+ * Whether a card counts as "to review" in the deck view.
4
+ * Uses end-of-day cutoff to match StudyService.getReviewCards behaviour.
5
+ */
6
+ function isCardToReview(state: string, suspended: boolean, due: Date | null, now?: Date): boolean;
2
7
  const reportBody: import("@sinclair/typebox").TObject<{
3
8
  cardId: import("@sinclair/typebox").TString;
4
9
  content: import("@sinclair/typebox").TString;
@@ -9,4 +14,16 @@ export declare namespace CardModel {
9
14
  cardId: import("@sinclair/typebox").TString;
10
15
  }>;
11
16
  type ReportQuery = typeof reportQuery.static;
17
+ const suspendBody: import("@sinclair/typebox").TObject<{
18
+ cardId: import("@sinclair/typebox").TString;
19
+ }>;
20
+ type SuspendBody = typeof suspendBody.static;
21
+ const suspendQuery: import("@sinclair/typebox").TObject<{
22
+ cardId: import("@sinclair/typebox").TString;
23
+ }>;
24
+ type SuspendQuery = typeof suspendQuery.static;
25
+ const userStateQuery: import("@sinclair/typebox").TObject<{
26
+ deckId: import("@sinclair/typebox").TString;
27
+ }>;
28
+ type UserStateQuery = typeof userStateQuery.static;
12
29
  }
@@ -1,6 +1,13 @@
1
1
  import type { CardDemand } from '@vestcards/db-core';
2
- import type { CardModel } from './model';
2
+ import { CardModel } from './model';
3
3
  export declare abstract class CardService {
4
4
  static getReport(userId: string, cardId: string): Promise<CardDemand | null>;
5
+ static suspendCard(userId: string, cardId: string): Promise<boolean>;
6
+ static unsuspendCard(userId: string, cardId: string): Promise<boolean>;
7
+ static getUserState(userId: string, deckId: string): Promise<{
8
+ cardId: string;
9
+ suspended: boolean;
10
+ toReview: boolean;
11
+ }[]>;
5
12
  static reportCard(userId: string, body: CardModel.ReportBody): Promise<void>;
6
13
  }
@@ -42,7 +42,7 @@ export declare const deckModule: Elysia<"/v1/decks", {
42
42
  route: string;
43
43
  request: Request;
44
44
  store: {};
45
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
45
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
46
46
  readonly 100: "Continue";
47
47
  readonly 101: "Switching Protocols";
48
48
  readonly 102: "Processing";
@@ -216,7 +216,7 @@ export declare const deckModule: Elysia<"/v1/decks", {
216
216
  route: string;
217
217
  request: Request;
218
218
  store: {};
219
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
219
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
220
220
  readonly 100: "Continue";
221
221
  readonly 101: "Switching Protocols";
222
222
  readonly 102: "Processing";
@@ -42,7 +42,7 @@ export declare const libraryModule: Elysia<"/v1/library", {
42
42
  route: string;
43
43
  request: Request;
44
44
  store: {};
45
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
45
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
46
46
  readonly 100: "Continue";
47
47
  readonly 101: "Switching Protocols";
48
48
  readonly 102: "Processing";
@@ -216,7 +216,7 @@ export declare const libraryModule: Elysia<"/v1/library", {
216
216
  route: string;
217
217
  request: Request;
218
218
  store: {};
219
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
219
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
220
220
  readonly 100: "Continue";
221
221
  readonly 101: "Switching Protocols";
222
222
  readonly 102: "Processing";
@@ -42,7 +42,7 @@ export declare const studyModule: Elysia<"/v1/study", {
42
42
  route: string;
43
43
  request: Request;
44
44
  store: {};
45
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
45
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
46
46
  readonly 100: "Continue";
47
47
  readonly 101: "Switching Protocols";
48
48
  readonly 102: "Processing";
@@ -216,7 +216,7 @@ export declare const studyModule: Elysia<"/v1/study", {
216
216
  route: string;
217
217
  request: Request;
218
218
  store: {};
219
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
219
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
220
220
  readonly 100: "Continue";
221
221
  readonly 101: "Switching Protocols";
222
222
  readonly 102: "Processing";
@@ -9,11 +9,11 @@ export declare abstract class StudyService {
9
9
  static getReviewCards(userId: string, type: StudyType, id?: string, maxToFetch?: number): Promise<import("@vestcards/shared").ISessionCard[]>;
10
10
  static getNewCards(userId: string, allocatedNewForToday: number, type: StudyType, id?: string): Promise<import("@vestcards/shared").ISessionCard[]>;
11
11
  static getUserDeckStudy(userId: string, deckId: string): Promise<{
12
- suspended: boolean;
13
12
  id: string;
14
- createdAt: Date;
15
- userId: string;
16
13
  deckId: string;
14
+ userId: string;
15
+ suspended: boolean;
16
+ createdAt: Date;
17
17
  }>;
18
18
  static getCardReview(userId: string, cardId: string): Promise<CardReview>;
19
19
  static gradeCard(userId: string, input: StudyModel.GradeCardBody): Promise<void>;
@@ -42,7 +42,7 @@ export declare const topicModule: Elysia<"/v1/topics", {
42
42
  route: string;
43
43
  request: Request;
44
44
  store: {};
45
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
45
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
46
46
  readonly 100: "Continue";
47
47
  readonly 101: "Switching Protocols";
48
48
  readonly 102: "Processing";
@@ -216,7 +216,7 @@ export declare const topicModule: Elysia<"/v1/topics", {
216
216
  route: string;
217
217
  request: Request;
218
218
  store: {};
219
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
219
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
220
220
  readonly 100: "Continue";
221
221
  readonly 101: "Switching Protocols";
222
222
  readonly 102: "Processing";
@@ -0,0 +1,3 @@
1
+ export declare class InvalidTokenError extends Error {
2
+ constructor();
3
+ }
@@ -42,7 +42,7 @@ export declare const userModule: Elysia<"/v1/user", {
42
42
  route: string;
43
43
  request: Request;
44
44
  store: {};
45
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
45
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
46
46
  readonly 100: "Continue";
47
47
  readonly 101: "Switching Protocols";
48
48
  readonly 102: "Processing";
@@ -216,7 +216,7 @@ export declare const userModule: Elysia<"/v1/user", {
216
216
  route: string;
217
217
  request: Request;
218
218
  store: {};
219
- status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 200 | 400 | 301 | 302 | 303 | 307 | 308 | 100 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 304 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
219
+ status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 400 | 401 | 403 | 404 | 409 | 429 | 500 | 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 402 | 405 | 406 | 407 | 408 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
220
220
  readonly 100: "Continue";
221
221
  readonly 101: "Switching Protocols";
222
222
  readonly 102: "Processing";
@@ -457,6 +457,68 @@ export declare const userModule: Elysia<"/v1/user", {
457
457
  };
458
458
  };
459
459
  };
460
+ } & {
461
+ v1: {
462
+ user: {
463
+ account: {
464
+ "delete-request": {
465
+ post: {
466
+ body: {
467
+ email: string;
468
+ };
469
+ params: {};
470
+ query: {};
471
+ headers: {};
472
+ response: {
473
+ 200: {
474
+ success: boolean;
475
+ };
476
+ 422: {
477
+ type: "validation";
478
+ on: string;
479
+ summary?: string;
480
+ message?: string;
481
+ found?: unknown;
482
+ property?: string;
483
+ expected?: string;
484
+ };
485
+ };
486
+ };
487
+ };
488
+ };
489
+ };
490
+ };
491
+ } & {
492
+ v1: {
493
+ user: {
494
+ account: {
495
+ "confirm-delete": {
496
+ post: {
497
+ body: {
498
+ token: string;
499
+ };
500
+ params: {};
501
+ query: {};
502
+ headers: {};
503
+ response: {
504
+ 200: {
505
+ success: boolean;
506
+ };
507
+ 422: {
508
+ type: "validation";
509
+ on: string;
510
+ summary?: string;
511
+ message?: string;
512
+ found?: unknown;
513
+ property?: string;
514
+ expected?: string;
515
+ };
516
+ };
517
+ };
518
+ };
519
+ };
520
+ };
521
+ };
460
522
  } & {
461
523
  v1: {
462
524
  user: {
@@ -482,8 +544,8 @@ export declare const userModule: Elysia<"/v1/user", {
482
544
  "complete-profile": {
483
545
  post: {
484
546
  body: {
485
- dayTimeReminder?: string | undefined;
486
547
  university?: number | undefined;
548
+ dayTimeReminder?: string | undefined;
487
549
  course?: number | undefined;
488
550
  goal: string;
489
551
  hoursStudied: string;
@@ -15,6 +15,12 @@ export declare namespace TopicModel {
15
15
  }
16
16
  }
17
17
  export declare namespace UserModel {
18
+ const deleteRequestBody: import("@sinclair/typebox").TObject<{
19
+ email: import("@sinclair/typebox").TString;
20
+ }>;
21
+ const confirmDeleteBody: import("@sinclair/typebox").TObject<{
22
+ token: import("@sinclair/typebox").TString;
23
+ }>;
18
24
  const updateSettingsBody: import("@sinclair/typebox").TObject<{
19
25
  learnDailyLimit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
20
26
  university: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TInteger, import("@sinclair/typebox").TNull]>>;
@@ -1,5 +1,6 @@
1
1
  import { MembershipStatus } from '@vestcards/shared';
2
2
  export declare abstract class UserService {
3
+ private static getUserById;
3
4
  static getLearnDailyLimit(userId: string): Promise<number>;
4
5
  static getProfile(userId: string): Promise<{
5
6
  id: string;
@@ -23,7 +24,10 @@ export declare abstract class UserService {
23
24
  course?: number;
24
25
  dayTimeReminder?: string;
25
26
  }): Promise<void>;
27
+ private static sendDeletionEmail;
26
28
  static deleteAccount(userId: string): Promise<void>;
29
+ static requestDeletion(email: string): Promise<void>;
30
+ static confirmDeletion(token: string): Promise<void>;
27
31
  static getMembership(userId: string): Promise<{
28
32
  status: MembershipStatus;
29
33
  expiresAt: Date | null;
@@ -125,6 +125,7 @@ export declare function createCardReview(data: {
125
125
  lapses?: number;
126
126
  last_review?: Date | null;
127
127
  }): Promise<{
128
+ suspended: boolean;
128
129
  id: string;
129
130
  createdAt: Date;
130
131
  cardId: string;
@@ -27,5 +27,5 @@ export declare const paginateResults: <T, TOtherData = {}>(data: T[], { size, to
27
27
  size: number;
28
28
  total: number;
29
29
  }, aggregatedData?: TOtherData) => Paginated<T, TOtherData>;
30
- export { paginationModel, searchModel, sortModel };
31
30
  export type { Paginated, Pagination, Search, Sort };
31
+ export { paginationModel, searchModel, sortModel };
@@ -331,6 +331,23 @@ export declare const sessionCardSelect: {
331
331
  identity: undefined;
332
332
  generated: undefined;
333
333
  }, {}, {}>;
334
+ suspended: import("drizzle-orm/pg-core").PgColumn<{
335
+ name: "suspended";
336
+ tableName: "card_review";
337
+ dataType: "boolean";
338
+ columnType: "PgBoolean";
339
+ data: boolean;
340
+ driverParam: boolean;
341
+ notNull: true;
342
+ hasDefault: true;
343
+ isPrimaryKey: false;
344
+ isAutoincrement: false;
345
+ hasRuntimeDefault: false;
346
+ enumValues: undefined;
347
+ baseColumn: never;
348
+ identity: undefined;
349
+ generated: undefined;
350
+ }, {}, {}>;
334
351
  createdAt: import("drizzle-orm/pg-core").PgColumn<{
335
352
  name: "created_at";
336
353
  tableName: "card_review";
@@ -336,6 +336,66 @@ export declare const session: import("drizzle-orm/pg-core").PgTableWithColumns<{
336
336
  identity: undefined;
337
337
  generated: undefined;
338
338
  }, {}, {}>;
339
+ entitlements: import("drizzle-orm/pg-core").PgColumn<{
340
+ name: "entitlements";
341
+ tableName: "session";
342
+ dataType: "array";
343
+ columnType: "PgArray";
344
+ data: string[];
345
+ driverParam: string | string[];
346
+ notNull: true;
347
+ hasDefault: true;
348
+ isPrimaryKey: false;
349
+ isAutoincrement: false;
350
+ hasRuntimeDefault: false;
351
+ enumValues: [string, ...string[]];
352
+ baseColumn: import("drizzle-orm").Column<{
353
+ name: "entitlements";
354
+ tableName: "session";
355
+ dataType: "string";
356
+ columnType: "PgText";
357
+ data: string;
358
+ driverParam: string;
359
+ notNull: false;
360
+ hasDefault: false;
361
+ isPrimaryKey: false;
362
+ isAutoincrement: false;
363
+ hasRuntimeDefault: false;
364
+ enumValues: [string, ...string[]];
365
+ baseColumn: never;
366
+ identity: undefined;
367
+ generated: undefined;
368
+ }, {}, {}>;
369
+ identity: undefined;
370
+ generated: undefined;
371
+ }, {}, {
372
+ baseBuilder: import("drizzle-orm/pg-core").PgColumnBuilder<{
373
+ name: "entitlements";
374
+ dataType: "string";
375
+ columnType: "PgText";
376
+ data: string;
377
+ enumValues: [string, ...string[]];
378
+ driverParam: string;
379
+ }, {}, {}, import("drizzle-orm").ColumnBuilderExtraConfig>;
380
+ size: undefined;
381
+ }>;
382
+ completedProfile: import("drizzle-orm/pg-core").PgColumn<{
383
+ name: "completed_profile";
384
+ tableName: "session";
385
+ dataType: "boolean";
386
+ columnType: "PgBoolean";
387
+ data: boolean;
388
+ driverParam: boolean;
389
+ notNull: true;
390
+ hasDefault: true;
391
+ isPrimaryKey: false;
392
+ isAutoincrement: false;
393
+ hasRuntimeDefault: false;
394
+ enumValues: undefined;
395
+ baseColumn: never;
396
+ identity: undefined;
397
+ generated: undefined;
398
+ }, {}, {}>;
339
399
  };
340
400
  dialect: "pg";
341
401
  }>;
@@ -920,6 +920,23 @@ export declare const cardReviews: import("drizzle-orm/pg-core").PgTableWithColum
920
920
  identity: undefined;
921
921
  generated: undefined;
922
922
  }, {}, {}>;
923
+ suspended: import("drizzle-orm/pg-core").PgColumn<{
924
+ name: "suspended";
925
+ tableName: "card_review";
926
+ dataType: "boolean";
927
+ columnType: "PgBoolean";
928
+ data: boolean;
929
+ driverParam: boolean;
930
+ notNull: true;
931
+ hasDefault: true;
932
+ isPrimaryKey: false;
933
+ isAutoincrement: false;
934
+ hasRuntimeDefault: false;
935
+ enumValues: undefined;
936
+ baseColumn: never;
937
+ identity: undefined;
938
+ generated: undefined;
939
+ }, {}, {}>;
923
940
  userDeckStudyId: import("drizzle-orm/pg-core").PgColumn<{
924
941
  name: "user_deck_study_id";
925
942
  tableName: "card_review";
@@ -1,3 +1,4 @@
1
+ export * from '../views/deck';
1
2
  export * from './auth';
2
3
  export * from './blog';
3
4
  export * from './data';
@@ -0,0 +1,8 @@
1
+ export interface EmailDeleteAccountRequestValues {
2
+ userName: string;
3
+ confirmUrl: string;
4
+ }
5
+ export declare const EMAILDeleteAccountRequest: ({ userName, confirmUrl }: EmailDeleteAccountRequestValues) => {
6
+ subject: string;
7
+ html: string;
8
+ };
@@ -1 +1 @@
1
- export declare const EMAILFooter = "\n <div class=\"mt\">\n <img src=\"https://storage.googleapis.com/vestcards-public-bucket/logos/logoIconPrimary.png\" width=\"35\" height=\"25\" alt=\"Logo VestCards\" title=\"Logo VestCards\" style=\"display: block;\">\n <p class=\"text-gray\">\n <a href=\"https://vestcards.com.br\" style=\"color: gray !important;\">Vestcards</a>, 2025. Todos os direitos reservados.\n </p>\n </div>\n";
1
+ export declare const EMAILFooter: string;
@@ -2,6 +2,7 @@ import { type EmailAccountDeletionValues } from './accountDeletion';
2
2
  import { type EmailAdminPurchaseAlertValues } from './adminPurchaseAlert';
3
3
  import { type EmailCardDemandValues } from './cardDemand';
4
4
  import { type EmailCardDemandActionValues } from './cardDemandAction';
5
+ import { type EmailDeleteAccountRequestValues } from './deleteAccountRequest';
5
6
  import { type EmailConfirmAccountValues } from './emailVerification';
6
7
  import { type EmailForgotPasswordValues } from './forgotPassword';
7
8
  import { type EmailPurchaseConfirmationValues } from './purchaseConfirmation';
@@ -19,6 +20,7 @@ export interface EmailTemplateFunctions {
19
20
  PurchaseConfirmation: (data: EmailPurchaseConfirmationValues) => EmailTemplateType;
20
21
  AdminPurchaseAlert: (data: EmailAdminPurchaseAlertValues) => EmailTemplateType;
21
22
  AccountDeletion: (data: EmailAccountDeletionValues) => EmailTemplateType;
23
+ DeleteAccountRequest: (data: EmailDeleteAccountRequestValues) => EmailTemplateType;
22
24
  CardDemand: (data: EmailCardDemandValues) => EmailTemplateType;
23
25
  CardDemandAction: (data: EmailCardDemandActionValues) => EmailTemplateType;
24
26
  }
@@ -0,0 +1,5 @@
1
+ export declare const FSRS_RETENTION = 0.9;
2
+ export declare const MAX_CARDS_TO_FETCH = 50;
3
+ export declare const MAX_LEARN_PER_DAY = 200;
4
+ export declare const MAX_NEW_PER_DECK_DAY = 10;
5
+ export declare const THRESHOLD_CARDS_FOR_REFETCH = 10;
@@ -0,0 +1,13 @@
1
+ import { type Card as FSRSCard } from 'ts-fsrs';
2
+ import { type ReviewRating } from '../types/fsrs';
3
+ import type { ICardReview, IReviewLog } from '../types/study';
4
+ export declare const gradeCard: (card: ICardReview, rating: ReviewRating, durationInSeconds: number) => {
5
+ nextCard: ICardReview;
6
+ reviewLog: IReviewLog;
7
+ };
8
+ /**
9
+ * Give a {@link ICardReview}, returns the review {@link Date} for each {@link ReviewRating}.
10
+ */
11
+ export declare function getReviewDateForEachRating(card: ICardReview): Record<ReviewRating, Date>;
12
+ export declare function mergeFsrsCard(fsrsCard: FSRSCard, card: ICardReview): ICardReview;
13
+ export declare function newCardReview(userDeckStudyId: string, cardId: string): ICardReview;
@@ -0,0 +1,4 @@
1
+ export * from './config';
2
+ export * from './fsrs';
3
+ export * from './session-manager';
4
+ export * from './utils';
@@ -0,0 +1,25 @@
1
+ import type { ReviewRating } from '../types/fsrs';
2
+ import type { ISessionCard, ISessionData } from '../types/study';
3
+ export declare const RECENTLY_REVIEWED_SET_SIZE = 5;
4
+ export declare const defaultSessionData: ISessionData;
5
+ export interface SessionProgress {
6
+ reviewsCompleted: number;
7
+ correctGrades: number;
8
+ }
9
+ /**
10
+ * Encapsulates the stateful logic shared across platforms for a flashcard study session:
11
+ * - Recently-reviewed set (prevents immediate card repetition)
12
+ * - Progress counters (total reviews, correct grades)
13
+ * - Next card selection (delegates to getNextCardFromSession)
14
+ *
15
+ * Usage: hold an instance in a ref (React/RN), call nextCard() on each render
16
+ * and onRate() whenever the user grades a card.
17
+ */
18
+ export declare class FlashcardSessionManager {
19
+ private recentlyReviewed;
20
+ private _reviewsCompleted;
21
+ private _correctGrades;
22
+ getProgress(): SessionProgress;
23
+ nextCard(data: ISessionData): ISessionCard | undefined;
24
+ onRate(cardId: string, rating: ReviewRating): SessionProgress;
25
+ }
@@ -0,0 +1,26 @@
1
+ import type { ReviewRating } from '../types/fsrs';
2
+ import type { ISessionCard, ISessionData } from '../types/study';
3
+ export declare function getNextCardFromSession(data: ISessionData, recentlyReviewed?: Set<string>): ISessionCard | undefined;
4
+ /**
5
+ * Remove a card from session data without grading it (e.g. suspend + skip).
6
+ * Properly decrements the matching stats bucket and total.
7
+ */
8
+ export declare function skipCardFromSessionData(data: ISessionData, cardId: string): ISessionData;
9
+ /**
10
+ * Computes the next session data after grading a card.
11
+ *
12
+ * Simulates the card grading and if the next review is within ~10 minutes,
13
+ * keeps the card in the session and updates the respective counter.
14
+ *
15
+ * If the card's state is `New`, then the card exists in `newCards`.
16
+ * If the card is any other state, then the card exists in `reviewCards`.
17
+ *
18
+ * @param grade The grade given to the card
19
+ * @param data The current session data
20
+ * @param cardId The id of the card that was graded
21
+ */
22
+ export declare function removeCardFromSessionData(grade: ReviewRating, data: ISessionData, cardId: string): ISessionData;
23
+ /**
24
+ * Gets the card from the session data.
25
+ */
26
+ export declare function getSessionCard(sessionData: ISessionData, cardId: string): ISessionCard | undefined;
@@ -8,4 +8,4 @@ declare const borderRadius: {
8
8
  button: string;
9
9
  input: string;
10
10
  };
11
- export { borderWidth, borderRadius };
11
+ export { borderRadius, borderWidth };
@@ -41,7 +41,7 @@ export interface IDeck {
41
41
  subject: Subject;
42
42
  topic?: string;
43
43
  topicIcon?: string | null;
44
- ownerId: string;
44
+ ownerInfo?: IOwnerInfo;
45
45
  }
46
46
  export interface IDeckDetail extends IDeck {
47
47
  subject: Subject;
@@ -50,3 +50,13 @@ export interface IDeckDetail extends IDeck {
50
50
  ownerInfo: IOwnerInfo;
51
51
  cards: ICard[];
52
52
  }
53
+ export interface ICardUserState {
54
+ cardId: string;
55
+ suspended: boolean;
56
+ toReview: boolean;
57
+ }
58
+ export interface ICardMedia {
59
+ id: string;
60
+ side: 'front' | 'back';
61
+ url: string;
62
+ }
@@ -1,5 +1,8 @@
1
1
  import { Entitlement, UserRole } from './user';
2
2
  export declare const PERMISSIONS: {
3
+ readonly APP: {
4
+ readonly ACCESS: "app:access";
5
+ };
3
6
  readonly DECK: {
4
7
  readonly CREATE_OWN: "deck:create:own";
5
8
  readonly CREATE_PUBLIC: "deck:create:public";
@@ -64,6 +67,7 @@ export type Permission = ValueOf<{
64
67
  [K in keyof typeof PERMISSIONS]: ValueOf<(typeof PERMISSIONS)[K]>;
65
68
  }>;
66
69
  export declare const Permission: {
70
+ readonly APP_ACCESS: "app:access";
67
71
  readonly DECK_CREATE_OWN: "deck:create:own";
68
72
  readonly DECK_CREATE_PUBLIC: "deck:create:public";
69
73
  readonly DECK_READ_OWN: "deck:read:own";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vestcards/server-types",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "private": false,
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {
@@ -1,12 +0,0 @@
1
- import { type CardReview, type NewCardReview, type NewReviewLog, type Rating } from '@vestcards/db-core';
2
- import { type Card as FSRSCard } from 'ts-fsrs';
3
- export declare const gradeCard: (card: CardReview, schemaRating: Rating, durationInSeconds: number) => {
4
- nextCard: CardReview;
5
- reviewLog: NewReviewLog;
6
- };
7
- /**
8
- * Give a {@link Card}, returns the review {@link Date} for each {@link Rating}.
9
- */
10
- export declare function getReviewDateForEachRating(card: CardReview | NewCardReview): Record<Rating, Date>;
11
- export declare function mergeFsrsCard(fsrsCard: FSRSCard, card: CardReview): CardReview;
12
- export declare function newCardReview(userDeckStudyId: string, cardId: string): NewCardReview;