@quizpot/quizcore 0.0.1
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/README.md +9 -0
- package/dist/events/client/host/kick-player.d.ts +8 -0
- package/dist/events/client/host/kick-player.d.ts.map +1 -0
- package/dist/events/client/host/kick-player.js +4 -0
- package/dist/events/client/host/next-step.d.ts +5 -0
- package/dist/events/client/host/next-step.d.ts.map +1 -0
- package/dist/events/client/host/next-step.js +3 -0
- package/dist/events/client/host/start-lobby.d.ts +6 -0
- package/dist/events/client/host/start-lobby.d.ts.map +1 -0
- package/dist/events/client/host/start-lobby.js +4 -0
- package/dist/events/client/player/submit-answer.d.ts +9 -0
- package/dist/events/client/player/submit-answer.d.ts.map +1 -0
- package/dist/events/client/player/submit-answer.js +4 -0
- package/dist/events/server/lobby-deleted.d.ts +8 -0
- package/dist/events/server/lobby-deleted.d.ts.map +1 -0
- package/dist/events/server/lobby-deleted.js +4 -0
- package/dist/events/server/lobby-joined.d.ts +14 -0
- package/dist/events/server/lobby-joined.d.ts.map +1 -0
- package/dist/events/server/lobby-joined.js +18 -0
- package/dist/events/server/lobby-status-update.d.ts +32 -0
- package/dist/events/server/lobby-status-update.d.ts.map +1 -0
- package/dist/events/server/lobby-status-update.js +4 -0
- package/dist/events/server/player-answer-result.d.ts +11 -0
- package/dist/events/server/player-answer-result.d.ts.map +1 -0
- package/dist/events/server/player-answer-result.js +4 -0
- package/dist/events/server/player-joined.d.ts +9 -0
- package/dist/events/server/player-joined.d.ts.map +1 -0
- package/dist/events/server/player-joined.js +4 -0
- package/dist/events/server/player-kicked.d.ts +6 -0
- package/dist/events/server/player-kicked.d.ts.map +1 -0
- package/dist/events/server/player-kicked.js +4 -0
- package/dist/events/server/player-left.d.ts +9 -0
- package/dist/events/server/player-left.d.ts.map +1 -0
- package/dist/events/server/player-left.js +4 -0
- package/dist/events/server/player-update.d.ts +9 -0
- package/dist/events/server/player-update.d.ts.map +1 -0
- package/dist/events/server/player-update.js +4 -0
- package/dist/events/server/update-lobby-answers.d.ts +8 -0
- package/dist/events/server/update-lobby-answers.d.ts.map +1 -0
- package/dist/events/server/update-lobby-answers.js +4 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/managers/lobby-manager.d.ts +12 -0
- package/dist/managers/lobby-manager.d.ts.map +1 -0
- package/dist/managers/lobby-manager.js +112 -0
- package/dist/questions/multiple-choice.d.ts +22 -0
- package/dist/questions/multiple-choice.d.ts.map +1 -0
- package/dist/questions/multiple-choice.js +1 -0
- package/dist/questions/short-answer.d.ts +12 -0
- package/dist/questions/short-answer.d.ts.map +1 -0
- package/dist/questions/short-answer.js +1 -0
- package/dist/questions/true-false.d.ts +12 -0
- package/dist/questions/true-false.d.ts.map +1 -0
- package/dist/questions/true-false.js +1 -0
- package/dist/schemas/quizfile.d.ts +87 -0
- package/dist/schemas/quizfile.d.ts.map +1 -0
- package/dist/schemas/quizfile.js +55 -0
- package/dist/slides/comparison.d.ts +9 -0
- package/dist/slides/comparison.d.ts.map +1 -0
- package/dist/slides/comparison.js +7 -0
- package/dist/slides/titleImageTextSlide.d.ts +9 -0
- package/dist/slides/titleImageTextSlide.d.ts.map +1 -0
- package/dist/slides/titleImageTextSlide.js +7 -0
- package/dist/slides/titleSlide.d.ts +8 -0
- package/dist/slides/titleSlide.d.ts.map +1 -0
- package/dist/slides/titleSlide.js +6 -0
- package/dist/types/events.d.ts +16 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +1 -0
- package/dist/types/lobby.d.ts +42 -0
- package/dist/types/lobby.d.ts.map +1 -0
- package/dist/types/lobby.js +10 -0
- package/dist/types/question.d.ts +106 -0
- package/dist/types/question.d.ts.map +1 -0
- package/dist/types/question.js +22 -0
- package/dist/types/questions/multiple-choice.d.ts +51 -0
- package/dist/types/questions/multiple-choice.d.ts.map +1 -0
- package/dist/types/questions/multiple-choice.js +21 -0
- package/dist/types/questions/short-answer.d.ts +34 -0
- package/dist/types/questions/short-answer.d.ts.map +1 -0
- package/dist/types/questions/short-answer.js +11 -0
- package/dist/types/questions/true-false.d.ts +36 -0
- package/dist/types/questions/true-false.d.ts.map +1 -0
- package/dist/types/questions/true-false.js +12 -0
- package/dist/types/quizfile.d.ts +79 -0
- package/dist/types/quizfile.d.ts.map +1 -0
- package/dist/types/quizfile.js +23 -0
- package/dist/types/quizstep.d.ts +73 -0
- package/dist/types/quizstep.d.ts.map +1 -0
- package/dist/types/quizstep.js +7 -0
- package/dist/types/quiztheme.d.ts +7 -0
- package/dist/types/quiztheme.d.ts.map +1 -0
- package/dist/types/quiztheme.js +5 -0
- package/dist/types/slide.d.ts +18 -0
- package/dist/types/slide.d.ts.map +1 -0
- package/dist/types/slide.js +9 -0
- package/dist/types/slides/comparison.d.ts +9 -0
- package/dist/types/slides/comparison.d.ts.map +1 -0
- package/dist/types/slides/comparison.js +7 -0
- package/dist/types/slides/titleImageTextSlide.d.ts +9 -0
- package/dist/types/slides/titleImageTextSlide.d.ts.map +1 -0
- package/dist/types/slides/titleImageTextSlide.js +7 -0
- package/dist/types/slides/titleSlide.d.ts +8 -0
- package/dist/types/slides/titleSlide.d.ts.map +1 -0
- package/dist/types/slides/titleSlide.js +6 -0
- package/dist/util/guards.d.ts +18 -0
- package/dist/util/guards.d.ts.map +1 -0
- package/dist/util/guards.js +15 -0
- package/dist/util/names/additives.json +23 -0
- package/dist/util/names/animals.json +23 -0
- package/dist/util/names/colors.json +14 -0
- package/dist/util/names/names.d.ts +4 -0
- package/dist/util/names/names.d.ts.map +1 -0
- package/dist/util/names/names.js +31 -0
- package/dist/util/sanitizer.d.ts +3 -0
- package/dist/util/sanitizer.d.ts.map +1 -0
- package/dist/util/sanitizer.js +18 -0
- package/dist/util/score.d.ts +11 -0
- package/dist/util/score.d.ts.map +1 -0
- package/dist/util/score.js +33 -0
- package/dist/util/validator.d.ts +14 -0
- package/dist/util/validator.d.ts.map +1 -0
- package/dist/util/validator.js +27 -0
- package/package.json +28 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export type QuizFile = z.infer<typeof QuizFileSchema>;
|
|
3
|
+
export declare const QuizFileSchema: z.ZodObject<{
|
|
4
|
+
id: z.ZodUUID;
|
|
5
|
+
version: z.ZodLiteral<2>;
|
|
6
|
+
title: z.ZodString;
|
|
7
|
+
description: z.ZodOptional<z.ZodString>;
|
|
8
|
+
theme: z.ZodObject<{
|
|
9
|
+
color: z.ZodString;
|
|
10
|
+
background: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
language: z.ZodString;
|
|
13
|
+
steps: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
14
|
+
type: z.ZodLiteral<"question">;
|
|
15
|
+
data: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
16
|
+
question: z.ZodString;
|
|
17
|
+
imageHash: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
18
|
+
displayTime: z.ZodNumber;
|
|
19
|
+
timeLimit: z.ZodNumber;
|
|
20
|
+
points: z.ZodEnum<{
|
|
21
|
+
normalPoints: "normalPoints";
|
|
22
|
+
doublePoints: "doublePoints";
|
|
23
|
+
noPoints: "noPoints";
|
|
24
|
+
}>;
|
|
25
|
+
type: z.ZodLiteral<"multiple-choice">;
|
|
26
|
+
choices: z.ZodArray<z.ZodObject<{
|
|
27
|
+
text: z.ZodString;
|
|
28
|
+
correct: z.ZodBoolean;
|
|
29
|
+
}, z.core.$strip>>;
|
|
30
|
+
matchAll: z.ZodBoolean;
|
|
31
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
32
|
+
question: z.ZodString;
|
|
33
|
+
imageHash: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
34
|
+
displayTime: z.ZodNumber;
|
|
35
|
+
timeLimit: z.ZodNumber;
|
|
36
|
+
points: z.ZodEnum<{
|
|
37
|
+
normalPoints: "normalPoints";
|
|
38
|
+
doublePoints: "doublePoints";
|
|
39
|
+
noPoints: "noPoints";
|
|
40
|
+
}>;
|
|
41
|
+
type: z.ZodLiteral<"true-false">;
|
|
42
|
+
answer: z.ZodBoolean;
|
|
43
|
+
labels: z.ZodArray<z.ZodString>;
|
|
44
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
45
|
+
question: z.ZodString;
|
|
46
|
+
imageHash: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
47
|
+
displayTime: z.ZodNumber;
|
|
48
|
+
timeLimit: z.ZodNumber;
|
|
49
|
+
points: z.ZodEnum<{
|
|
50
|
+
normalPoints: "normalPoints";
|
|
51
|
+
doublePoints: "doublePoints";
|
|
52
|
+
noPoints: "noPoints";
|
|
53
|
+
}>;
|
|
54
|
+
type: z.ZodLiteral<"short-answer">;
|
|
55
|
+
answers: z.ZodArray<z.ZodString>;
|
|
56
|
+
}, z.core.$strip>], "type">;
|
|
57
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
58
|
+
type: z.ZodLiteral<"slide">;
|
|
59
|
+
data: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
60
|
+
slideType: z.ZodLiteral<"title">;
|
|
61
|
+
title: z.ZodString;
|
|
62
|
+
subtitle: z.ZodOptional<z.ZodString>;
|
|
63
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
64
|
+
slideType: z.ZodLiteral<"titleImageText">;
|
|
65
|
+
title: z.ZodString;
|
|
66
|
+
imageHash: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
67
|
+
text: z.ZodString;
|
|
68
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
69
|
+
slideType: z.ZodLiteral<"comparison">;
|
|
70
|
+
title: z.ZodString;
|
|
71
|
+
left: z.ZodString;
|
|
72
|
+
right: z.ZodString;
|
|
73
|
+
}, z.core.$strip>], "slideType">;
|
|
74
|
+
}, z.core.$strip>], "type">>;
|
|
75
|
+
images: z.ZodRecord<z.ZodCustomStringFormat<"sha256_hex">, z.ZodString>;
|
|
76
|
+
updatedAt: z.ZodISODateTime;
|
|
77
|
+
createdAt: z.ZodISODateTime;
|
|
78
|
+
}, z.core.$strip>;
|
|
79
|
+
//# sourceMappingURL=quizfile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quizfile.d.ts","sourceRoot":"","sources":["../../src/types/quizfile.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AAIpB,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0BzB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
import { QuizThemeSchema } from "./quiztheme";
|
|
3
|
+
import { QuizStepSchema } from "./quizstep";
|
|
4
|
+
export const QuizFileSchema = z.object({
|
|
5
|
+
id: z.uuid(),
|
|
6
|
+
version: z.literal(2),
|
|
7
|
+
title: z.string()
|
|
8
|
+
.min(1, "Title must be atleast 1 character long")
|
|
9
|
+
.max(64, "Title can't be longer than 64 characters"),
|
|
10
|
+
description: z.string()
|
|
11
|
+
.max(255, "Description can't be longer than 256 characters")
|
|
12
|
+
.optional(),
|
|
13
|
+
theme: QuizThemeSchema,
|
|
14
|
+
language: z.string()
|
|
15
|
+
.length(2, "Language must be a 2-letter ISO 639-1 code"),
|
|
16
|
+
steps: z.array(QuizStepSchema)
|
|
17
|
+
.min(1, "Quiz must have at least 1 step"),
|
|
18
|
+
images: z.record(z.hash("sha256", { error: "Invalid image hash" }), z.string().refine((val) => {
|
|
19
|
+
return val.startsWith("http") || val.startsWith("data:image/");
|
|
20
|
+
}, "Image must be a valid URL or Base64 data string")),
|
|
21
|
+
updatedAt: z.iso.datetime(),
|
|
22
|
+
createdAt: z.iso.datetime(),
|
|
23
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
import { Question } from "./question";
|
|
3
|
+
import { Slide } from "./slide";
|
|
4
|
+
export type QuizStep = {
|
|
5
|
+
type: "question";
|
|
6
|
+
data: Question;
|
|
7
|
+
} | {
|
|
8
|
+
type: "slide";
|
|
9
|
+
data: Slide;
|
|
10
|
+
};
|
|
11
|
+
export declare const QuizStepSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
12
|
+
type: z.ZodLiteral<"question">;
|
|
13
|
+
data: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
14
|
+
question: z.ZodString;
|
|
15
|
+
imageHash: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
16
|
+
displayTime: z.ZodNumber;
|
|
17
|
+
timeLimit: z.ZodNumber;
|
|
18
|
+
points: z.ZodEnum<{
|
|
19
|
+
normalPoints: "normalPoints";
|
|
20
|
+
doublePoints: "doublePoints";
|
|
21
|
+
noPoints: "noPoints";
|
|
22
|
+
}>;
|
|
23
|
+
type: z.ZodLiteral<"multiple-choice">;
|
|
24
|
+
choices: z.ZodArray<z.ZodObject<{
|
|
25
|
+
text: z.ZodString;
|
|
26
|
+
correct: z.ZodBoolean;
|
|
27
|
+
}, z.core.$strip>>;
|
|
28
|
+
matchAll: z.ZodBoolean;
|
|
29
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
30
|
+
question: z.ZodString;
|
|
31
|
+
imageHash: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
32
|
+
displayTime: z.ZodNumber;
|
|
33
|
+
timeLimit: z.ZodNumber;
|
|
34
|
+
points: z.ZodEnum<{
|
|
35
|
+
normalPoints: "normalPoints";
|
|
36
|
+
doublePoints: "doublePoints";
|
|
37
|
+
noPoints: "noPoints";
|
|
38
|
+
}>;
|
|
39
|
+
type: z.ZodLiteral<"true-false">;
|
|
40
|
+
answer: z.ZodBoolean;
|
|
41
|
+
labels: z.ZodArray<z.ZodString>;
|
|
42
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
43
|
+
question: z.ZodString;
|
|
44
|
+
imageHash: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
45
|
+
displayTime: z.ZodNumber;
|
|
46
|
+
timeLimit: z.ZodNumber;
|
|
47
|
+
points: z.ZodEnum<{
|
|
48
|
+
normalPoints: "normalPoints";
|
|
49
|
+
doublePoints: "doublePoints";
|
|
50
|
+
noPoints: "noPoints";
|
|
51
|
+
}>;
|
|
52
|
+
type: z.ZodLiteral<"short-answer">;
|
|
53
|
+
answers: z.ZodArray<z.ZodString>;
|
|
54
|
+
}, z.core.$strip>], "type">;
|
|
55
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
56
|
+
type: z.ZodLiteral<"slide">;
|
|
57
|
+
data: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
58
|
+
slideType: z.ZodLiteral<"title">;
|
|
59
|
+
title: z.ZodString;
|
|
60
|
+
subtitle: z.ZodOptional<z.ZodString>;
|
|
61
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
62
|
+
slideType: z.ZodLiteral<"titleImageText">;
|
|
63
|
+
title: z.ZodString;
|
|
64
|
+
imageHash: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
65
|
+
text: z.ZodString;
|
|
66
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
67
|
+
slideType: z.ZodLiteral<"comparison">;
|
|
68
|
+
title: z.ZodString;
|
|
69
|
+
left: z.ZodString;
|
|
70
|
+
right: z.ZodString;
|
|
71
|
+
}, z.core.$strip>], "slideType">;
|
|
72
|
+
}, z.core.$strip>], "type">;
|
|
73
|
+
//# sourceMappingURL=quizstep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quizstep.d.ts","sourceRoot":"","sources":["../../src/types/quizstep.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAkB,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,KAAK,EAAe,MAAM,SAAS,CAAC;AAE7C,MAAM,MAAM,QAAQ,GAChB;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;CAChB,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,KAAK,CAAC;CACb,CAAC;AAEN,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAGzB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
import { QuestionSchema } from "./question";
|
|
3
|
+
import { SlideSchema } from "./slide";
|
|
4
|
+
export const QuizStepSchema = z.discriminatedUnion("type", [
|
|
5
|
+
z.object({ type: z.literal("question"), data: QuestionSchema }),
|
|
6
|
+
z.object({ type: z.literal("slide"), data: SlideSchema }),
|
|
7
|
+
]);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export type QuizTheme = z.infer<typeof QuizThemeSchema>;
|
|
3
|
+
export declare const QuizThemeSchema: z.ZodObject<{
|
|
4
|
+
color: z.ZodString;
|
|
5
|
+
background: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
//# sourceMappingURL=quiztheme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quiztheme.d.ts","sourceRoot":"","sources":["../../src/types/quiztheme.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,eAAe;;;iBAM1B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export const QuizThemeSchema = z.object({
|
|
3
|
+
color: z.string().regex(/^#[0-9a-fA-F]{6}$/, { message: 'Invalid color format. Must be a 7-character hex code (e.g., #RRGGBB).' }),
|
|
4
|
+
background: z.hash("sha256", { error: "Invalid background hash" }).optional(),
|
|
5
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export type Slide = z.infer<typeof SlideSchema>;
|
|
3
|
+
export declare const SlideSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
4
|
+
slideType: z.ZodLiteral<"title">;
|
|
5
|
+
title: z.ZodString;
|
|
6
|
+
subtitle: z.ZodOptional<z.ZodString>;
|
|
7
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
8
|
+
slideType: z.ZodLiteral<"titleImageText">;
|
|
9
|
+
title: z.ZodString;
|
|
10
|
+
imageHash: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
11
|
+
text: z.ZodString;
|
|
12
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
13
|
+
slideType: z.ZodLiteral<"comparison">;
|
|
14
|
+
title: z.ZodString;
|
|
15
|
+
left: z.ZodString;
|
|
16
|
+
right: z.ZodString;
|
|
17
|
+
}, z.core.$strip>], "slideType">;
|
|
18
|
+
//# sourceMappingURL=slide.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slide.d.ts","sourceRoot":"","sources":["../../src/types/slide.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AAKpB,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;gCAItB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
import { TitleSlideLayoutSchema } from "./slides/titleSlide";
|
|
3
|
+
import { TitleImageTextSlideLayoutSchema } from "./slides/titleImageTextSlide";
|
|
4
|
+
import { ComparisonSlideLayoutSchema } from "./slides/comparison";
|
|
5
|
+
export const SlideSchema = z.discriminatedUnion("slideType", [
|
|
6
|
+
TitleSlideLayoutSchema,
|
|
7
|
+
TitleImageTextSlideLayoutSchema,
|
|
8
|
+
ComparisonSlideLayoutSchema
|
|
9
|
+
]);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export declare const ComparisonSlideLayoutSchema: z.ZodObject<{
|
|
3
|
+
slideType: z.ZodLiteral<"comparison">;
|
|
4
|
+
title: z.ZodString;
|
|
5
|
+
left: z.ZodString;
|
|
6
|
+
right: z.ZodString;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export type ComparisonSlideLayout = z.infer<typeof ComparisonSlideLayoutSchema>;
|
|
9
|
+
//# sourceMappingURL=comparison.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comparison.d.ts","sourceRoot":"","sources":["../../../src/types/slides/comparison.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,eAAO,MAAM,2BAA2B;;;;;iBAKtC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export declare const TitleImageTextSlideLayoutSchema: z.ZodObject<{
|
|
3
|
+
slideType: z.ZodLiteral<"titleImageText">;
|
|
4
|
+
title: z.ZodString;
|
|
5
|
+
imageHash: z.ZodOptional<z.ZodCustomStringFormat<"sha256_hex">>;
|
|
6
|
+
text: z.ZodString;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export type TitleImageTextSlideLayout = z.infer<typeof TitleImageTextSlideLayoutSchema>;
|
|
9
|
+
//# sourceMappingURL=titleImageTextSlide.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"titleImageTextSlide.d.ts","sourceRoot":"","sources":["../../../src/types/slides/titleImageTextSlide.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,eAAO,MAAM,+BAA+B;;;;;iBAK1C,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export declare const TitleSlideLayoutSchema: z.ZodObject<{
|
|
3
|
+
slideType: z.ZodLiteral<"title">;
|
|
4
|
+
title: z.ZodString;
|
|
5
|
+
subtitle: z.ZodOptional<z.ZodString>;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
export type TitleSlideLayout = z.infer<typeof TitleSlideLayoutSchema>;
|
|
8
|
+
//# sourceMappingURL=titleSlide.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"titleSlide.d.ts","sourceRoot":"","sources":["../../../src/types/slides/titleSlide.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,eAAO,MAAM,sBAAsB;;;;iBAIjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Question } from "../types/question";
|
|
2
|
+
import { MultipleChoiceQuestion } from "../types/questions/multiple-choice";
|
|
3
|
+
import { ShortAnswerQuestion } from "../types/questions/short-answer";
|
|
4
|
+
import { TrueFalseQuestion } from "../types/questions/true-false";
|
|
5
|
+
import { QuizStep } from "../types/quizstep";
|
|
6
|
+
import { Slide } from "../types/slide";
|
|
7
|
+
export declare const isQuestion: (step: QuizStep) => step is {
|
|
8
|
+
type: "question";
|
|
9
|
+
data: Question;
|
|
10
|
+
};
|
|
11
|
+
export declare const isSlide: (step: QuizStep) => step is {
|
|
12
|
+
type: "slide";
|
|
13
|
+
data: Slide;
|
|
14
|
+
};
|
|
15
|
+
export declare const isMultipleChoice: (data: Question) => data is MultipleChoiceQuestion;
|
|
16
|
+
export declare const isTrueFalse: (data: Question) => data is TrueFalseQuestion;
|
|
17
|
+
export declare const isShortAnswer: (data: Question) => data is ShortAnswerQuestion;
|
|
18
|
+
//# sourceMappingURL=guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../src/util/guards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,eAAO,MAAM,UAAU,GAAI,MAAM,QAAQ,KAAG,IAAI,IAAI;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAErF,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,MAAM,QAAQ,KAAG,IAAI,IAAI;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAE5E,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,MAAM,QAAQ,KAAG,IAAI,IAAI,sBAEzD,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,MAAM,QAAQ,KAAG,IAAI,IAAI,iBAEpD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,QAAQ,KAAG,IAAI,IAAI,mBAEtD,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const isQuestion = (step) => {
|
|
2
|
+
return step.type === "question";
|
|
3
|
+
};
|
|
4
|
+
export const isSlide = (step) => {
|
|
5
|
+
return step.type === "slide";
|
|
6
|
+
};
|
|
7
|
+
export const isMultipleChoice = (data) => {
|
|
8
|
+
return data.type === "multiple-choice";
|
|
9
|
+
};
|
|
10
|
+
export const isTrueFalse = (data) => {
|
|
11
|
+
return data.type === "true-false";
|
|
12
|
+
};
|
|
13
|
+
export const isShortAnswer = (data) => {
|
|
14
|
+
return data.type === "short-answer";
|
|
15
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[
|
|
2
|
+
"Funny",
|
|
3
|
+
"Happy",
|
|
4
|
+
"Sad",
|
|
5
|
+
"Angry",
|
|
6
|
+
"Scary",
|
|
7
|
+
"Serious",
|
|
8
|
+
"Cautious",
|
|
9
|
+
"Joyful",
|
|
10
|
+
"Broken",
|
|
11
|
+
"Smart",
|
|
12
|
+
"Shy",
|
|
13
|
+
"Silly",
|
|
14
|
+
"Lazy",
|
|
15
|
+
"Cheerful",
|
|
16
|
+
"Calm",
|
|
17
|
+
"Sleepy",
|
|
18
|
+
"Tired",
|
|
19
|
+
"Lonely",
|
|
20
|
+
"Crazy",
|
|
21
|
+
"Mad",
|
|
22
|
+
"Gentle"
|
|
23
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[
|
|
2
|
+
"Dog",
|
|
3
|
+
"Cat",
|
|
4
|
+
"Rabbit",
|
|
5
|
+
"Lion",
|
|
6
|
+
"Tiger",
|
|
7
|
+
"Bear",
|
|
8
|
+
"Wolf",
|
|
9
|
+
"Fox",
|
|
10
|
+
"Panda",
|
|
11
|
+
"Elephant",
|
|
12
|
+
"Gorilla",
|
|
13
|
+
"Giraffe",
|
|
14
|
+
"Hippo",
|
|
15
|
+
"Rhino",
|
|
16
|
+
"Zebra",
|
|
17
|
+
"Crocodile",
|
|
18
|
+
"Alligator",
|
|
19
|
+
"Octopus",
|
|
20
|
+
"Butterfly",
|
|
21
|
+
"Bee",
|
|
22
|
+
"Ant"
|
|
23
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.d.ts","sourceRoot":"","sources":["../../../src/util/names/names.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,eAAO,MAAM,YAAY,QAAO,MAM/B,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,EAAE,KAAG,MAwBtD,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import animals from "./animals.json";
|
|
2
|
+
import additives from "./additives.json";
|
|
3
|
+
import colors from "./colors.json";
|
|
4
|
+
export const generateName = () => {
|
|
5
|
+
const animal = animals[Math.floor(Math.random() * animals.length)];
|
|
6
|
+
const additive = additives[Math.floor(Math.random() * additives.length)];
|
|
7
|
+
const color = colors[Math.floor(Math.random() * colors.length)];
|
|
8
|
+
return `${color}${additive}${animal}`;
|
|
9
|
+
};
|
|
10
|
+
export const generateUniqueName = (players) => {
|
|
11
|
+
const maxPossible = animals.length * additives.length * colors.length;
|
|
12
|
+
if (players.length >= maxPossible) {
|
|
13
|
+
throw new Error("No unique names available");
|
|
14
|
+
}
|
|
15
|
+
const existingNames = new Set(players.map((p) => p.name));
|
|
16
|
+
for (let i = 0; i < 100; i++) {
|
|
17
|
+
const candidate = generateName();
|
|
18
|
+
if (!existingNames.has(candidate))
|
|
19
|
+
return candidate;
|
|
20
|
+
}
|
|
21
|
+
for (const c of colors) {
|
|
22
|
+
for (const ad of additives) {
|
|
23
|
+
for (const an of animals) {
|
|
24
|
+
const candidate = `${c}${ad}${an}`;
|
|
25
|
+
if (!existingNames.has(candidate))
|
|
26
|
+
return candidate;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
throw new Error("No unique names available"); // Fallback
|
|
31
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../../src/util/sanitizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG3D,eAAO,MAAM,gBAAgB,GAAI,UAAU,QAAQ,KAAG,YAmBrD,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { isMultipleChoice, isShortAnswer, isTrueFalse } from "./guards";
|
|
2
|
+
export const sanitizeQuestion = (question) => {
|
|
3
|
+
if (isMultipleChoice(question)) {
|
|
4
|
+
return {
|
|
5
|
+
...question,
|
|
6
|
+
choices: question.choices.map(({ text }) => ({ text })),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
if (isTrueFalse(question)) {
|
|
10
|
+
const { answer, ...sanitized } = question;
|
|
11
|
+
return sanitized;
|
|
12
|
+
}
|
|
13
|
+
if (isShortAnswer(question)) {
|
|
14
|
+
const { answers, ...sanitized } = question;
|
|
15
|
+
return sanitized;
|
|
16
|
+
}
|
|
17
|
+
throw new Error("Invalid question type");
|
|
18
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Answer } from "./validator";
|
|
2
|
+
import { QuizFile } from "../types/quizfile";
|
|
3
|
+
import { Question } from "../types/question";
|
|
4
|
+
export declare const calculateScore: (player: {
|
|
5
|
+
score: number;
|
|
6
|
+
streak: number;
|
|
7
|
+
}, question: Question, answer: Answer, quiz: QuizFile) => {
|
|
8
|
+
newScore: number;
|
|
9
|
+
pointsAwarded: number;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/util/score.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAK7C,eAAO,MAAM,cAAc,GACzB,QAAQ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACzC,UAAU,QAAQ,EAClB,QAAQ,MAAM,EACd,MAAM,QAAQ,KACb;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAmC3C,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const BASE_SCORE = 500;
|
|
2
|
+
const TIME_BONUS_MAX = 500;
|
|
3
|
+
export const calculateScore = (player, question, answer, quiz) => {
|
|
4
|
+
if (!answer.isCorrect)
|
|
5
|
+
return { newScore: player.score, pointsAwarded: 0 };
|
|
6
|
+
const multipliers = {
|
|
7
|
+
noPoints: 0,
|
|
8
|
+
normalPoints: 1,
|
|
9
|
+
doublePoints: 2,
|
|
10
|
+
};
|
|
11
|
+
const pointMultiplier = multipliers[question.points] ?? 1;
|
|
12
|
+
if (pointMultiplier === 0)
|
|
13
|
+
return { newScore: player.score, pointsAwarded: 0 };
|
|
14
|
+
let timeBonus = 0;
|
|
15
|
+
if (question.timeLimit > 0) {
|
|
16
|
+
const timeLimitMs = question.timeLimit * 1000;
|
|
17
|
+
const timeTaken = Math.max(0, Math.min(answer.timeTaken, timeLimitMs));
|
|
18
|
+
const timeRemainingRatio = 1 - (timeTaken / timeLimitMs);
|
|
19
|
+
timeBonus = TIME_BONUS_MAX * timeRemainingRatio;
|
|
20
|
+
}
|
|
21
|
+
let questionScore = (BASE_SCORE + timeBonus) * pointMultiplier;
|
|
22
|
+
if (player.streak >= 2) {
|
|
23
|
+
const totalQuestions = quiz.steps.filter(s => s.type === "question").length;
|
|
24
|
+
const dynamicCap = Math.min(1.2 + Math.max(0, totalQuestions - 5) * 0.02, 1.5);
|
|
25
|
+
const streakMultiplier = Math.min(1 + (player.streak - 1) * 0.05, dynamicCap);
|
|
26
|
+
questionScore *= streakMultiplier;
|
|
27
|
+
}
|
|
28
|
+
const finalPoints = Math.trunc(questionScore);
|
|
29
|
+
return {
|
|
30
|
+
newScore: player.score + finalPoints,
|
|
31
|
+
pointsAwarded: finalPoints
|
|
32
|
+
};
|
|
33
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ShortAnswerQuestionAnswer } from "../types/questions/short-answer";
|
|
2
|
+
import { TrueFalseQuestionAnswer } from "../types/questions/true-false";
|
|
3
|
+
import { MultipleChoiceQuestionAnswer } from "../types/questions/multiple-choice";
|
|
4
|
+
import { Question } from "../types/question";
|
|
5
|
+
export type SubmittedAnswer = MultipleChoiceQuestionAnswer | TrueFalseQuestionAnswer | ShortAnswerQuestionAnswer;
|
|
6
|
+
export interface Answer {
|
|
7
|
+
playerId: string;
|
|
8
|
+
submission: SubmittedAnswer;
|
|
9
|
+
timeTaken: number;
|
|
10
|
+
isCorrect: boolean;
|
|
11
|
+
pointsAwarded: number;
|
|
12
|
+
}
|
|
13
|
+
export declare const isCorrect: (question: Question, submission: SubmittedAnswer) => boolean;
|
|
14
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/util/validator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,4BAA4B,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,MAAM,MAAM,eAAe,GACvB,4BAA4B,GAC5B,uBAAuB,GACvB,yBAAyB,CAAC;AAE9B,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,eAAe,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,SAAS,GAAI,UAAU,QAAQ,EAAE,YAAY,eAAe,KAAG,OA+B3E,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { isMultipleChoice, isShortAnswer, isTrueFalse } from "../util/guards";
|
|
2
|
+
;
|
|
3
|
+
export const isCorrect = (question, submission) => {
|
|
4
|
+
if (isMultipleChoice(question) && submission.type === "multiple-choice") {
|
|
5
|
+
if (question.matchAll) {
|
|
6
|
+
const correctIndices = question.choices
|
|
7
|
+
.map((c, i) => (c.correct ? i : -1))
|
|
8
|
+
.filter((i) => i !== -1);
|
|
9
|
+
return (submission.choices.length === correctIndices.length &&
|
|
10
|
+
submission.choices.every((index) => correctIndices.includes(index)));
|
|
11
|
+
}
|
|
12
|
+
if (submission.choices.length === 0)
|
|
13
|
+
return false;
|
|
14
|
+
return submission.choices.every(index => {
|
|
15
|
+
const choice = question.choices[index];
|
|
16
|
+
return choice ? choice.correct : false;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (isTrueFalse(question) && submission.type === "true-false") {
|
|
20
|
+
return question.answer === submission.answer;
|
|
21
|
+
}
|
|
22
|
+
if (isShortAnswer(question) && submission.type === "short-answer") {
|
|
23
|
+
const playerAns = submission.answer.trim().toLowerCase();
|
|
24
|
+
return question.answers.some(ans => ans.trim().toLowerCase() === playerAns);
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@quizpot/quizcore",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Core library for Quizpot",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"watch": "tsc --watch",
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"prepare": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js",
|
|
19
|
+
"require": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"typescript": "^5.9.3"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"zod": "^4.3.6"
|
|
27
|
+
}
|
|
28
|
+
}
|