@vestcards/server-types 1.2.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.
- package/dist/apps/server/src/app.d.ts +152 -1
- package/dist/apps/server/src/libs/mappers.d.ts +5 -0
- package/dist/apps/server/src/modules/auth/lib.d.ts +18 -14
- package/dist/apps/server/src/modules/card/index.d.ts +90 -1
- package/dist/apps/server/src/modules/card/model.d.ts +17 -0
- package/dist/apps/server/src/modules/card/service.d.ts +8 -1
- package/dist/apps/server/src/modules/study/service.d.ts +3 -3
- package/dist/apps/server/src/modules/user/errors.d.ts +3 -0
- package/dist/apps/server/src/modules/user/index.d.ts +62 -0
- package/dist/apps/server/src/modules/user/model.d.ts +6 -0
- package/dist/apps/server/src/modules/user/service.d.ts +4 -0
- package/dist/apps/server/src/tests/helpers/fixtures.d.ts +1 -0
- package/dist/apps/server/src/utils/api.d.ts +1 -1
- package/dist/apps/server/src/utils/select.d.ts +17 -0
- package/dist/packages/db-core/src/schema/auth.d.ts +60 -0
- package/dist/packages/db-core/src/schema/deck.d.ts +17 -0
- package/dist/packages/db-core/src/schema/index.d.ts +1 -0
- package/dist/packages/email-core/src/templates/deleteAccountRequest.d.ts +8 -0
- package/dist/packages/email-core/src/templates/footer.d.ts +1 -1
- package/dist/packages/email-core/src/templates/index.d.ts +2 -0
- package/dist/packages/shared/src/spaced-repetition/config.d.ts +5 -0
- package/dist/packages/shared/src/spaced-repetition/fsrs.d.ts +13 -0
- package/dist/packages/shared/src/spaced-repetition/index.d.ts +4 -0
- package/dist/packages/shared/src/spaced-repetition/session-manager.d.ts +25 -0
- package/dist/packages/shared/src/spaced-repetition/utils.d.ts +26 -0
- package/dist/packages/shared/src/theme/tokens/border.d.ts +1 -1
- package/dist/packages/shared/src/types/deck.d.ts +10 -0
- package/package.json +1 -1
- package/dist/apps/server/src/modules/study/lib/fsrs.d.ts +0 -12
- /package/dist/apps/server/src/modules/study/{lib/constants.d.ts → constants.d.ts} +0 -0
|
@@ -455,8 +455,8 @@ declare const app: Elysia<"", {
|
|
|
455
455
|
createdAt: Date;
|
|
456
456
|
updatedAt: Date;
|
|
457
457
|
userId: string;
|
|
458
|
-
content: string;
|
|
459
458
|
cardId: string;
|
|
459
|
+
content: string;
|
|
460
460
|
} | null;
|
|
461
461
|
422: {
|
|
462
462
|
type: "validation";
|
|
@@ -479,7 +479,36 @@ declare const app: Elysia<"", {
|
|
|
479
479
|
post: {
|
|
480
480
|
body: {
|
|
481
481
|
type: string;
|
|
482
|
+
cardId: string;
|
|
482
483
|
content: string;
|
|
484
|
+
};
|
|
485
|
+
params: {};
|
|
486
|
+
query: {};
|
|
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
|
+
suspend: {
|
|
510
|
+
post: {
|
|
511
|
+
body: {
|
|
483
512
|
cardId: string;
|
|
484
513
|
};
|
|
485
514
|
params: {};
|
|
@@ -503,6 +532,66 @@ declare const app: Elysia<"", {
|
|
|
503
532
|
};
|
|
504
533
|
};
|
|
505
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: {
|
|
@@ -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;
|
|
@@ -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("
|
|
75
|
-
authorizationURL: import("
|
|
76
|
-
oauthState: import("
|
|
77
|
-
}, import("
|
|
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,9 @@ export declare const auth: import("better-auth").Auth<{
|
|
|
94
96
|
}>;
|
|
95
97
|
};
|
|
96
98
|
options: import("@better-auth/expo").ExpoOptions | undefined;
|
|
97
|
-
}
|
|
99
|
+
} | {
|
|
98
100
|
id: "bearer";
|
|
101
|
+
version: string;
|
|
99
102
|
hooks: {
|
|
100
103
|
before: {
|
|
101
104
|
matcher(context: import("better-auth").HookEndpointContext): boolean;
|
|
@@ -111,8 +114,9 @@ export declare const auth: import("better-auth").Auth<{
|
|
|
111
114
|
}[];
|
|
112
115
|
};
|
|
113
116
|
options: import("better-auth/plugins").BearerOptions | undefined;
|
|
114
|
-
}
|
|
117
|
+
} | {
|
|
115
118
|
id: "custom-session";
|
|
119
|
+
version: string;
|
|
116
120
|
hooks: {
|
|
117
121
|
after: {
|
|
118
122
|
matcher: (ctx: import("better-auth").HookEndpointContext) => boolean;
|
|
@@ -147,10 +151,10 @@ export declare const auth: import("better-auth").Auth<{
|
|
|
147
151
|
endpoints: {
|
|
148
152
|
getSession: import("better-call").StrictEndpoint<"/get-session", {
|
|
149
153
|
method: "GET";
|
|
150
|
-
query: import("
|
|
151
|
-
disableCookieCache: import("
|
|
152
|
-
disableRefresh: import("
|
|
153
|
-
}, import("
|
|
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>>;
|
|
154
158
|
metadata: {
|
|
155
159
|
CUSTOM_SESSION: boolean;
|
|
156
160
|
openapi: {
|
|
@@ -230,11 +234,11 @@ export declare const auth: import("better-auth").Auth<{
|
|
|
230
234
|
};
|
|
231
235
|
};
|
|
232
236
|
options: import("better-auth/plugins").CustomSessionPluginOptions | undefined;
|
|
233
|
-
}];
|
|
237
|
+
})[];
|
|
234
238
|
baseURL: string;
|
|
235
239
|
basePath: string;
|
|
236
240
|
database: (options: BetterAuthOptions) => import("better-auth").DBAdapter<BetterAuthOptions>;
|
|
237
|
-
secondaryStorage: import("better-auth").SecondaryStorage;
|
|
241
|
+
secondaryStorage: import("better-auth").SecondaryStorage | undefined;
|
|
238
242
|
emailAndPassword: {
|
|
239
243
|
enabled: true;
|
|
240
244
|
autoSignIn: true;
|
|
@@ -397,8 +397,8 @@ export declare const cardModule: Elysia<"/v1/card", {
|
|
|
397
397
|
createdAt: Date;
|
|
398
398
|
updatedAt: Date;
|
|
399
399
|
userId: string;
|
|
400
|
-
content: string;
|
|
401
400
|
cardId: string;
|
|
401
|
+
content: string;
|
|
402
402
|
} | null;
|
|
403
403
|
422: {
|
|
404
404
|
type: "validation";
|
|
@@ -421,7 +421,36 @@ export declare const cardModule: Elysia<"/v1/card", {
|
|
|
421
421
|
post: {
|
|
422
422
|
body: {
|
|
423
423
|
type: string;
|
|
424
|
+
cardId: string;
|
|
424
425
|
content: string;
|
|
426
|
+
};
|
|
427
|
+
params: {};
|
|
428
|
+
query: {};
|
|
429
|
+
headers: {};
|
|
430
|
+
response: {
|
|
431
|
+
200: {
|
|
432
|
+
success: boolean;
|
|
433
|
+
};
|
|
434
|
+
422: {
|
|
435
|
+
type: "validation";
|
|
436
|
+
on: string;
|
|
437
|
+
summary?: string;
|
|
438
|
+
message?: string;
|
|
439
|
+
found?: unknown;
|
|
440
|
+
property?: string;
|
|
441
|
+
expected?: string;
|
|
442
|
+
};
|
|
443
|
+
};
|
|
444
|
+
};
|
|
445
|
+
};
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
} & {
|
|
449
|
+
v1: {
|
|
450
|
+
card: {
|
|
451
|
+
suspend: {
|
|
452
|
+
post: {
|
|
453
|
+
body: {
|
|
425
454
|
cardId: string;
|
|
426
455
|
};
|
|
427
456
|
params: {};
|
|
@@ -445,6 +474,66 @@ export declare const cardModule: Elysia<"/v1/card", {
|
|
|
445
474
|
};
|
|
446
475
|
};
|
|
447
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
|
|
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
|
}
|
|
@@ -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>;
|
|
@@ -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: {
|
|
@@ -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;
|
|
@@ -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 +1 @@
|
|
|
1
|
-
export declare const EMAILFooter
|
|
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,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,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;
|
|
@@ -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
|
+
}
|
package/package.json
CHANGED
|
@@ -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;
|
|
File without changes
|