@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.
Files changed (125) hide show
  1. package/README.md +9 -0
  2. package/dist/events/client/host/kick-player.d.ts +8 -0
  3. package/dist/events/client/host/kick-player.d.ts.map +1 -0
  4. package/dist/events/client/host/kick-player.js +4 -0
  5. package/dist/events/client/host/next-step.d.ts +5 -0
  6. package/dist/events/client/host/next-step.d.ts.map +1 -0
  7. package/dist/events/client/host/next-step.js +3 -0
  8. package/dist/events/client/host/start-lobby.d.ts +6 -0
  9. package/dist/events/client/host/start-lobby.d.ts.map +1 -0
  10. package/dist/events/client/host/start-lobby.js +4 -0
  11. package/dist/events/client/player/submit-answer.d.ts +9 -0
  12. package/dist/events/client/player/submit-answer.d.ts.map +1 -0
  13. package/dist/events/client/player/submit-answer.js +4 -0
  14. package/dist/events/server/lobby-deleted.d.ts +8 -0
  15. package/dist/events/server/lobby-deleted.d.ts.map +1 -0
  16. package/dist/events/server/lobby-deleted.js +4 -0
  17. package/dist/events/server/lobby-joined.d.ts +14 -0
  18. package/dist/events/server/lobby-joined.d.ts.map +1 -0
  19. package/dist/events/server/lobby-joined.js +18 -0
  20. package/dist/events/server/lobby-status-update.d.ts +32 -0
  21. package/dist/events/server/lobby-status-update.d.ts.map +1 -0
  22. package/dist/events/server/lobby-status-update.js +4 -0
  23. package/dist/events/server/player-answer-result.d.ts +11 -0
  24. package/dist/events/server/player-answer-result.d.ts.map +1 -0
  25. package/dist/events/server/player-answer-result.js +4 -0
  26. package/dist/events/server/player-joined.d.ts +9 -0
  27. package/dist/events/server/player-joined.d.ts.map +1 -0
  28. package/dist/events/server/player-joined.js +4 -0
  29. package/dist/events/server/player-kicked.d.ts +6 -0
  30. package/dist/events/server/player-kicked.d.ts.map +1 -0
  31. package/dist/events/server/player-kicked.js +4 -0
  32. package/dist/events/server/player-left.d.ts +9 -0
  33. package/dist/events/server/player-left.d.ts.map +1 -0
  34. package/dist/events/server/player-left.js +4 -0
  35. package/dist/events/server/player-update.d.ts +9 -0
  36. package/dist/events/server/player-update.d.ts.map +1 -0
  37. package/dist/events/server/player-update.js +4 -0
  38. package/dist/events/server/update-lobby-answers.d.ts +8 -0
  39. package/dist/events/server/update-lobby-answers.d.ts.map +1 -0
  40. package/dist/events/server/update-lobby-answers.js +4 -0
  41. package/dist/index.d.ts +26 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +25 -0
  44. package/dist/managers/lobby-manager.d.ts +12 -0
  45. package/dist/managers/lobby-manager.d.ts.map +1 -0
  46. package/dist/managers/lobby-manager.js +112 -0
  47. package/dist/questions/multiple-choice.d.ts +22 -0
  48. package/dist/questions/multiple-choice.d.ts.map +1 -0
  49. package/dist/questions/multiple-choice.js +1 -0
  50. package/dist/questions/short-answer.d.ts +12 -0
  51. package/dist/questions/short-answer.d.ts.map +1 -0
  52. package/dist/questions/short-answer.js +1 -0
  53. package/dist/questions/true-false.d.ts +12 -0
  54. package/dist/questions/true-false.d.ts.map +1 -0
  55. package/dist/questions/true-false.js +1 -0
  56. package/dist/schemas/quizfile.d.ts +87 -0
  57. package/dist/schemas/quizfile.d.ts.map +1 -0
  58. package/dist/schemas/quizfile.js +55 -0
  59. package/dist/slides/comparison.d.ts +9 -0
  60. package/dist/slides/comparison.d.ts.map +1 -0
  61. package/dist/slides/comparison.js +7 -0
  62. package/dist/slides/titleImageTextSlide.d.ts +9 -0
  63. package/dist/slides/titleImageTextSlide.d.ts.map +1 -0
  64. package/dist/slides/titleImageTextSlide.js +7 -0
  65. package/dist/slides/titleSlide.d.ts +8 -0
  66. package/dist/slides/titleSlide.d.ts.map +1 -0
  67. package/dist/slides/titleSlide.js +6 -0
  68. package/dist/types/events.d.ts +16 -0
  69. package/dist/types/events.d.ts.map +1 -0
  70. package/dist/types/events.js +1 -0
  71. package/dist/types/lobby.d.ts +42 -0
  72. package/dist/types/lobby.d.ts.map +1 -0
  73. package/dist/types/lobby.js +10 -0
  74. package/dist/types/question.d.ts +106 -0
  75. package/dist/types/question.d.ts.map +1 -0
  76. package/dist/types/question.js +22 -0
  77. package/dist/types/questions/multiple-choice.d.ts +51 -0
  78. package/dist/types/questions/multiple-choice.d.ts.map +1 -0
  79. package/dist/types/questions/multiple-choice.js +21 -0
  80. package/dist/types/questions/short-answer.d.ts +34 -0
  81. package/dist/types/questions/short-answer.d.ts.map +1 -0
  82. package/dist/types/questions/short-answer.js +11 -0
  83. package/dist/types/questions/true-false.d.ts +36 -0
  84. package/dist/types/questions/true-false.d.ts.map +1 -0
  85. package/dist/types/questions/true-false.js +12 -0
  86. package/dist/types/quizfile.d.ts +79 -0
  87. package/dist/types/quizfile.d.ts.map +1 -0
  88. package/dist/types/quizfile.js +23 -0
  89. package/dist/types/quizstep.d.ts +73 -0
  90. package/dist/types/quizstep.d.ts.map +1 -0
  91. package/dist/types/quizstep.js +7 -0
  92. package/dist/types/quiztheme.d.ts +7 -0
  93. package/dist/types/quiztheme.d.ts.map +1 -0
  94. package/dist/types/quiztheme.js +5 -0
  95. package/dist/types/slide.d.ts +18 -0
  96. package/dist/types/slide.d.ts.map +1 -0
  97. package/dist/types/slide.js +9 -0
  98. package/dist/types/slides/comparison.d.ts +9 -0
  99. package/dist/types/slides/comparison.d.ts.map +1 -0
  100. package/dist/types/slides/comparison.js +7 -0
  101. package/dist/types/slides/titleImageTextSlide.d.ts +9 -0
  102. package/dist/types/slides/titleImageTextSlide.d.ts.map +1 -0
  103. package/dist/types/slides/titleImageTextSlide.js +7 -0
  104. package/dist/types/slides/titleSlide.d.ts +8 -0
  105. package/dist/types/slides/titleSlide.d.ts.map +1 -0
  106. package/dist/types/slides/titleSlide.js +6 -0
  107. package/dist/util/guards.d.ts +18 -0
  108. package/dist/util/guards.d.ts.map +1 -0
  109. package/dist/util/guards.js +15 -0
  110. package/dist/util/names/additives.json +23 -0
  111. package/dist/util/names/animals.json +23 -0
  112. package/dist/util/names/colors.json +14 -0
  113. package/dist/util/names/names.d.ts +4 -0
  114. package/dist/util/names/names.d.ts.map +1 -0
  115. package/dist/util/names/names.js +31 -0
  116. package/dist/util/sanitizer.d.ts +3 -0
  117. package/dist/util/sanitizer.d.ts.map +1 -0
  118. package/dist/util/sanitizer.js +18 -0
  119. package/dist/util/score.d.ts +11 -0
  120. package/dist/util/score.d.ts.map +1 -0
  121. package/dist/util/score.js +33 -0
  122. package/dist/util/validator.d.ts +14 -0
  123. package/dist/util/validator.d.ts.map +1 -0
  124. package/dist/util/validator.js +27 -0
  125. 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,7 @@
1
+ import z from "zod";
2
+ export const ComparisonSlideLayoutSchema = z.object({
3
+ slideType: z.literal("comparison"),
4
+ title: z.string(),
5
+ left: z.string(),
6
+ right: z.string(),
7
+ });
@@ -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,7 @@
1
+ import z from "zod";
2
+ export const TitleImageTextSlideLayoutSchema = z.object({
3
+ slideType: z.literal("titleImageText"),
4
+ title: z.string(),
5
+ imageHash: z.hash("sha256", { error: "Invalid image hash" }).optional(),
6
+ text: z.string(),
7
+ });
@@ -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,6 @@
1
+ import z from "zod";
2
+ export const TitleSlideLayoutSchema = z.object({
3
+ slideType: z.literal("title"),
4
+ title: z.string(),
5
+ subtitle: z.string().optional(),
6
+ });
@@ -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,14 @@
1
+ [
2
+ "Red",
3
+ "Blue",
4
+ "Green",
5
+ "Yellow",
6
+ "Purple",
7
+ "Orange",
8
+ "Pink",
9
+ "Brown",
10
+ "Black",
11
+ "White",
12
+ "Gray",
13
+ "Cyan"
14
+ ]
@@ -0,0 +1,4 @@
1
+ import { Player } from "../../types/lobby";
2
+ export declare const generateName: () => string;
3
+ export declare const generateUniqueName: (players: Player[]) => string;
4
+ //# sourceMappingURL=names.d.ts.map
@@ -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,3 @@
1
+ import { Question, SafeQuestion } from "../types/question";
2
+ export declare const sanitizeQuestion: (question: Question) => SafeQuestion;
3
+ //# sourceMappingURL=sanitizer.d.ts.map
@@ -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
+ }