@tinyweb_dev/oe-exam-sdk 0.1.20 → 0.1.24
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 +4 -5
- package/dist/api/result-review.types.d.ts +1 -0
- package/dist/components/exams/ExamPreviewDialog.d.ts +6 -7
- package/dist/components/exams/ExamPreviewDialog.js +1 -1
- package/dist/components/exams/ExamPreviewPartContent.d.ts +18 -0
- package/dist/components/exams/ExamPreviewPartContent.js +1 -0
- package/dist/components/exams/ExamPreviewSidebar.d.ts +17 -0
- package/dist/components/exams/ExamPreviewSidebar.js +1 -0
- package/dist/components/exams/exam-preview.types.d.ts +34 -0
- package/dist/components/exams/exam-preview.types.js +1 -0
- package/dist/components/exams/index.d.ts +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversChooseBestAnswerRenderer.js +1 -1
- package/dist/components/exams/take/components/question-renderers/MoversListenAndWriteRenderer.js +1 -1
- package/dist/components/exams/take/components/question-renderers/MoversWordFillStructuredFormRenderer.js +1 -1
- package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.js +1 -1
- package/dist/components/exams/take/exam-taking.utils.d.ts +13 -0
- package/dist/components/exams/take/exam-taking.utils.js +1 -1
- package/dist/components/exams/take/types.d.ts +3 -0
- package/dist/components/exams/take/utils/question-transformers.d.ts +16 -1
- package/dist/components/exams/take/utils/question-transformers.js +1 -1
- package/dist/components/questions/_shared/types/word-fill-structured-form.type.d.ts +25 -0
- package/dist/components/questions/_shared/utils/parseFillBlankStem.d.ts +30 -0
- package/dist/components/questions/_shared/utils/parseFillBlankStem.js +1 -0
- package/dist/components/questions/index.d.ts +1 -0
- package/dist/components/questions/index.js +1 -1
- package/dist/components/questions/question-bank/EditQuestionBankDialog.d.ts +2 -0
- package/dist/components/questions/question-bank/EditQuestionBankDialog.js +1 -0
- package/dist/components/questions/question-bank/QuestionEditorRenderer.d.ts +23 -0
- package/dist/components/questions/question-bank/QuestionEditorRenderer.js +1 -0
- package/dist/components/questions/question-bank/difficulty.d.ts +15 -0
- package/dist/components/questions/question-bank/difficulty.js +1 -0
- package/dist/components/questions/question-bank/editor-adapters/choice-adapters.d.ts +5 -0
- package/dist/components/questions/question-bank/editor-adapters/choice-adapters.js +1 -0
- package/dist/components/questions/question-bank/editor-adapters/index.d.ts +5 -0
- package/dist/components/questions/question-bank/editor-adapters/index.js +1 -0
- package/dist/components/questions/question-bank/editor-adapters/media-adapters.d.ts +6 -0
- package/dist/components/questions/question-bank/editor-adapters/media-adapters.js +1 -0
- package/dist/components/questions/question-bank/editor-adapters/types.d.ts +1 -0
- package/dist/components/questions/question-bank/editor-adapters/types.js +1 -0
- package/dist/components/questions/question-bank/editor-adapters/unsupported-fallback.d.ts +8 -0
- package/dist/components/questions/question-bank/editor-adapters/unsupported-fallback.js +1 -0
- package/dist/components/questions/question-bank/editor-adapters/writing-adapters.d.ts +5 -0
- package/dist/components/questions/question-bank/editor-adapters/writing-adapters.js +1 -0
- package/dist/components/questions/question-bank/index.d.ts +4 -0
- package/dist/components/questions/question-bank/index.js +1 -0
- package/dist/components/questions/question-bank/types.d.ts +59 -0
- package/dist/components/questions/question-bank/types.js +1 -0
- package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +1 -1
- package/dist/components/questions/types/choose-the-correct-answer/index.d.ts +1 -0
- package/dist/components/questions/types/choose-the-correct-answer/index.js +1 -1
- package/dist/components/questions/types/choose-the-correct-answer/normalize.d.ts +27 -0
- package/dist/components/questions/types/choose-the-correct-answer/normalize.js +1 -0
- package/dist/components/questions/types/choose-the-correct-answer/register.js +1 -1
- package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +1 -1
- package/dist/components/questions/types/fill-in-blank/register.js +1 -1
- package/dist/components/questions/types/fill-in-blank/transform.js +1 -1
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.d.ts +1 -1
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -1
- package/dist/components/questions/types/word-fill-structured-form/transform.js +1 -1
- package/dist/components/questions/viewer/QuestionViewer.js +1 -1
- package/dist/components/results/review-data.js +1 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleAudioPlayer.d.ts +2 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleAudioPlayer.js +1 -1
- package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/shared/lib/i18n/messages/en/admin.d.ts +11 -4
- package/dist/shared/lib/i18n/messages/en/admin.js +1 -1
- package/dist/shared/lib/i18n/messages/en.d.ts +11 -4
- package/dist/shared/lib/i18n/messages/vi/admin.d.ts +11 -4
- package/dist/shared/lib/i18n/messages/vi/admin.js +1 -1
- package/dist/shared/lib/i18n/messages/vi.d.ts +11 -4
- package/package.json +163 -163
- package/dist/mcp/config.d.ts +0 -12
- package/dist/mcp/config.js +0 -1
- package/dist/mcp/http-client.d.ts +0 -6
- package/dist/mcp/http-client.js +0 -1
- package/dist/mcp/index.d.ts +0 -6
- package/dist/mcp/index.js +0 -2
- package/dist/mcp/tools/_helpers.d.ts +0 -4
- package/dist/mcp/tools/_helpers.js +0 -1
- package/dist/mcp/tools/exams.d.ts +0 -2
- package/dist/mcp/tools/exams.js +0 -1
- package/dist/mcp/tools/index.d.ts +0 -2
- package/dist/mcp/tools/index.js +0 -1
- package/dist/mcp/tools/results.d.ts +0 -2
- package/dist/mcp/tools/results.js +0 -1
|
@@ -275,6 +275,12 @@ declare const vi: {
|
|
|
275
275
|
readonly 'admin.questionBank.dialog.edit.save': "Lưu thay đổi";
|
|
276
276
|
readonly 'admin.questionBank.dialog.edit.codeError': "Vui lòng nhập mã câu hỏi";
|
|
277
277
|
readonly 'admin.questionBank.dialog.edit.titleError': "Vui lòng nhập tiêu đề";
|
|
278
|
+
readonly 'admin.questionBank.dialog.edit.loading': "Đang tải...";
|
|
279
|
+
readonly 'admin.questionBank.dialog.edit.unsupportedNote': "Lưu ý:";
|
|
280
|
+
readonly 'admin.questionBank.dialog.edit.unsupportedType': "Loại câu hỏi \"{type}\" chưa hỗ trợ chỉnh sửa trực tiếp trong giao diện này. Vui lòng sử dụng trang tạo đề thi để chỉnh sửa câu hỏi này.";
|
|
281
|
+
readonly 'admin.questionBank.dialog.edit.contentLabel': "Nội dung câu hỏi";
|
|
282
|
+
readonly 'admin.questionBank.dialog.edit.answerLabel': "Đáp án đúng";
|
|
283
|
+
readonly 'admin.questionBank.dialog.edit.explanationLabel': "Giải thích";
|
|
278
284
|
readonly 'admin.questionBank.dialog.delete.title': "Xác nhận xóa câu hỏi";
|
|
279
285
|
readonly 'admin.questionBank.dialog.delete.message': "Bạn có chắc chắn muốn xóa câu hỏi";
|
|
280
286
|
readonly 'admin.questionBank.dialog.delete.warning': "Hành động này không thể hoàn tác.";
|
|
@@ -1544,9 +1550,6 @@ declare const vi: {
|
|
|
1544
1550
|
readonly 'admin.exams.shuffle.info3': "Các câu hỏi trong cùng 1 Part được xáo trộn ngẫu nhiên";
|
|
1545
1551
|
readonly 'admin.exams.shuffle.info4': "Các đề thi con được liên kết với đề thi cha để quản lý";
|
|
1546
1552
|
readonly 'admin.exams.shuffle.countLabel': "Số lượng đề thi con muốn tạo";
|
|
1547
|
-
readonly 'admin.exams.shuffle.strategyLabel': "Lựa chọn xử lý đề thi cũ";
|
|
1548
|
-
readonly 'admin.exams.shuffle.keepOld': "Giữ lại các đề thi cũ và thêm đề mới";
|
|
1549
|
-
readonly 'admin.exams.shuffle.replaceAll': "Tạo bộ đề mới hoàn toàn";
|
|
1550
1553
|
readonly 'admin.exams.shuffle.existingVariants': "Đề thi đã có ({count})";
|
|
1551
1554
|
readonly 'admin.exams.shuffle.deleteAll': "Xóa tất cả ({count})";
|
|
1552
1555
|
readonly 'admin.exams.shuffle.loading': "Đang tải...";
|
|
@@ -1637,21 +1640,25 @@ declare const vi: {
|
|
|
1637
1640
|
readonly 'admin.exams.preview.totalPoints': "Tổng điểm:";
|
|
1638
1641
|
readonly 'admin.exams.preview.progress': "Tiến độ";
|
|
1639
1642
|
readonly 'admin.exams.preview.loading': "Đang tải...";
|
|
1640
|
-
readonly 'admin.exams.preview.questionNavigation': "Điều hướng
|
|
1643
|
+
readonly 'admin.exams.preview.questionNavigation': "Điều hướng Part";
|
|
1641
1644
|
readonly 'admin.exams.preview.all': "Tất cả";
|
|
1642
1645
|
readonly 'admin.exams.preview.allQuestions': "Tất cả {count} câu hỏi";
|
|
1643
1646
|
readonly 'admin.exams.preview.partQuestions': "Part {part}: {count} câu";
|
|
1644
1647
|
readonly 'admin.exams.preview.collapse': "Thu gọn";
|
|
1645
1648
|
readonly 'admin.exams.preview.detail': "Chi tiết";
|
|
1646
1649
|
readonly 'admin.exams.preview.questionIndex': "Câu hỏi {index} / {total}";
|
|
1650
|
+
readonly 'admin.exams.preview.partIndex': "Part {index} / {total}";
|
|
1647
1651
|
readonly 'admin.exams.preview.noQuestions': "Chưa có câu hỏi";
|
|
1648
1652
|
readonly 'admin.exams.preview.loadingQuestions': "Đang tải câu hỏi...";
|
|
1649
1653
|
readonly 'admin.exams.preview.retry': "Thử lại";
|
|
1650
1654
|
readonly 'admin.exams.preview.examNoQuestions': "Đề thi này chưa có câu hỏi nào.";
|
|
1651
1655
|
readonly 'admin.exams.preview.prevQuestion': "Câu trước";
|
|
1656
|
+
readonly 'admin.exams.preview.prevPart': "Part trước";
|
|
1652
1657
|
readonly 'admin.exams.preview.prev': "Trước";
|
|
1653
1658
|
readonly 'admin.exams.preview.nextQuestion': "Câu tiếp theo";
|
|
1659
|
+
readonly 'admin.exams.preview.nextPart': "Part tiếp theo";
|
|
1654
1660
|
readonly 'admin.exams.preview.next': "Tiếp";
|
|
1661
|
+
readonly 'admin.exams.preview.questionLabel': "Câu {number}";
|
|
1655
1662
|
readonly 'admin.exams.preview.footerNote': "Đây là chế độ xem trước để kiểm tra bố cục và nội dung đề thi.";
|
|
1656
1663
|
readonly 'admin.exams.preview.close': "Đóng";
|
|
1657
1664
|
readonly 'admin.exams.preview.loadError': "Không thể tải câu hỏi. Vui lòng thử lại.";
|
package/package.json
CHANGED
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@tinyweb_dev/oe-exam-sdk",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Reusable OceanEdu question components.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"module": "./dist/index.js",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"bin": {
|
|
10
|
-
"oe-exam-mcp": "./dist/mcp/index.js"
|
|
11
|
-
},
|
|
12
|
-
"files": [
|
|
13
|
-
"dist",
|
|
14
|
-
"README.md"
|
|
15
|
-
],
|
|
16
|
-
"sideEffects": [
|
|
17
|
-
"**/*.css"
|
|
18
|
-
],
|
|
19
|
-
"scripts": {
|
|
20
|
-
"clean": "rm -rf dist",
|
|
21
|
-
"build:compile": "tsc -p tsconfig.build.json",
|
|
22
|
-
"build:alias": "tsc-alias -p tsconfig.build.json",
|
|
23
|
-
"build:ts": "npm run build:compile && npm run build:assets && npm run build:alias",
|
|
24
|
-
"build:assets": "for d in cambridge-yle english-certification summer-sky; do [ -d src/components/themes/$d/assets ] && cp -R src/components/themes/$d/assets dist/components/themes/$d/ || true; done; [ -d src/components/shared/audio/assets ] && cp -R src/components/shared/audio/assets dist/components/shared/audio/ || true; [ -d src/components/results/report/assets ] && mkdir -p dist/components/results/report && cp -R src/components/results/report/assets dist/components/results/report/ || true; (cd src && find . -name '*.module.css' -exec cp --parents {} ../dist/ \\;); cp src/global.d.ts dist/global.d.ts",
|
|
25
|
-
"minify:js": "find dist -name '*.js' -type f -exec sh -c 'for f do terser \"$f\" --compress directives=false --mangle --module --comments false --output \"$f\"; done' sh {} +",
|
|
26
|
-
"build": "npm run clean && npm run build:ts && npm run minify:js",
|
|
27
|
-
"pack:local": "npm pack",
|
|
28
|
-
"release": "npm run release:patch",
|
|
29
|
-
"release:patch": "npm version patch --no-git-tag-version && npm run release:push",
|
|
30
|
-
"release:minor": "npm version minor --no-git-tag-version && npm run release:push",
|
|
31
|
-
"release:major": "npm version major --no-git-tag-version && npm run release:push",
|
|
32
|
-
"release:push": "npm run build && npm pack --dry-run && VERSION=$(node -p \"require('./package.json').version\") && git add package.json package-lock.json && git commit -m \"chore(sdk): release v$VERSION\" && git tag \"sdk-v$VERSION\" && git push origin HEAD && git push origin \"sdk-v$VERSION\"",
|
|
33
|
-
"prepack": "npm run build"
|
|
34
|
-
},
|
|
35
|
-
"exports": {
|
|
36
|
-
".": {
|
|
37
|
-
"types": "./dist/index.d.ts",
|
|
38
|
-
"import": "./dist/index.js"
|
|
39
|
-
},
|
|
40
|
-
"./api": {
|
|
41
|
-
"types": "./dist/api/index.d.ts",
|
|
42
|
-
"import": "./dist/api/index.js"
|
|
43
|
-
},
|
|
44
|
-
"./components": {
|
|
45
|
-
"types": "./dist/components/index.d.ts",
|
|
46
|
-
"import": "./dist/components/index.js"
|
|
47
|
-
},
|
|
48
|
-
"./mcp": {
|
|
49
|
-
"types": "./dist/mcp/index.d.ts",
|
|
50
|
-
"import": "./dist/mcp/index.js"
|
|
51
|
-
},
|
|
52
|
-
"./components/exams": {
|
|
53
|
-
"types": "./dist/components/exams/index.d.ts",
|
|
54
|
-
"import": "./dist/components/exams/index.js"
|
|
55
|
-
},
|
|
56
|
-
"./components/exams/take": {
|
|
57
|
-
"types": "./dist/components/exams/take/index.d.ts",
|
|
58
|
-
"import": "./dist/components/exams/take/index.js"
|
|
59
|
-
},
|
|
60
|
-
"./components/exams/entry": {
|
|
61
|
-
"types": "./dist/components/exams/entry/index.d.ts",
|
|
62
|
-
"import": "./dist/components/exams/entry/index.js"
|
|
63
|
-
},
|
|
64
|
-
"./components/exams/rooms": {
|
|
65
|
-
"types": "./dist/components/exams/rooms/index.d.ts",
|
|
66
|
-
"import": "./dist/components/exams/rooms/index.js"
|
|
67
|
-
},
|
|
68
|
-
"./components/questions": {
|
|
69
|
-
"types": "./dist/components/questions/index.d.ts",
|
|
70
|
-
"import": "./dist/components/questions/index.js"
|
|
71
|
-
},
|
|
72
|
-
"./components/themes": {
|
|
73
|
-
"types": "./dist/components/themes/index.d.ts",
|
|
74
|
-
"import": "./dist/components/themes/index.js"
|
|
75
|
-
},
|
|
76
|
-
"./components/results": {
|
|
77
|
-
"types": "./dist/components/results/index.d.ts",
|
|
78
|
-
"import": "./dist/components/results/index.js"
|
|
79
|
-
},
|
|
80
|
-
"./components/questions/*": {
|
|
81
|
-
"types": "./dist/components/questions/*.d.ts",
|
|
82
|
-
"import": "./dist/components/questions/*.js"
|
|
83
|
-
},
|
|
84
|
-
"./shared": {
|
|
85
|
-
"types": "./dist/shared/index.d.ts",
|
|
86
|
-
"import": "./dist/shared/index.js"
|
|
87
|
-
},
|
|
88
|
-
"./*": {
|
|
89
|
-
"types": "./dist/components/questions/*.d.ts",
|
|
90
|
-
"import": "./dist/components/questions/*.js"
|
|
91
|
-
},
|
|
92
|
-
"./package.json": "./package.json"
|
|
93
|
-
},
|
|
94
|
-
"publishConfig": {
|
|
95
|
-
"access": "public"
|
|
96
|
-
},
|
|
97
|
-
"peerDependencies": {
|
|
98
|
-
"next": ">=15",
|
|
99
|
-
"react": ">=19",
|
|
100
|
-
"react-dom": ">=19"
|
|
101
|
-
},
|
|
102
|
-
"devDependencies": {
|
|
103
|
-
"@types/node": "^25.9.3",
|
|
104
|
-
"terser": "^5.48.0",
|
|
105
|
-
"tsc-alias": "^1.8.17",
|
|
106
|
-
"typescript": "~5.9.2"
|
|
107
|
-
},
|
|
108
|
-
"dependencies": {
|
|
109
|
-
"@dnd-kit/core": "^6.3.1",
|
|
110
|
-
"@dnd-kit/sortable": "^10.0.0",
|
|
111
|
-
"@dnd-kit/utilities": "^3.2.2",
|
|
112
|
-
"@fortawesome/free-solid-svg-icons": "^7.3.1",
|
|
113
|
-
"@fortawesome/react-fontawesome": "^3.3.1",
|
|
114
|
-
"@hookform/resolvers": "^5.2.2",
|
|
115
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
116
|
-
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
117
|
-
"@radix-ui/react-avatar": "^1.1.10",
|
|
118
|
-
"@radix-ui/react-checkbox": "^1.3.3",
|
|
119
|
-
"@radix-ui/react-collapsible": "^1.1.12",
|
|
120
|
-
"@radix-ui/react-dialog": "^1.1.15",
|
|
121
|
-
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
122
|
-
"@radix-ui/react-hover-card": "^1.1.15",
|
|
123
|
-
"@radix-ui/react-label": "^2.1.7",
|
|
124
|
-
"@radix-ui/react-popover": "^1.1.15",
|
|
125
|
-
"@radix-ui/react-progress": "^1.1.7",
|
|
126
|
-
"@radix-ui/react-radio-group": "^1.3.8",
|
|
127
|
-
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
128
|
-
"@radix-ui/react-select": "^2.2.6",
|
|
129
|
-
"@radix-ui/react-separator": "^1.1.7",
|
|
130
|
-
"@radix-ui/react-slot": "^1.2.3",
|
|
131
|
-
"@radix-ui/react-switch": "^1.2.6",
|
|
132
|
-
"@radix-ui/react-tabs": "^1.1.13",
|
|
133
|
-
"@radix-ui/react-tooltip": "^1.2.8",
|
|
134
|
-
"@tanstack/react-query": "^5.90.2",
|
|
135
|
-
"@tiptap/extension-table": "^3.22.3",
|
|
136
|
-
"@tiptap/extension-table-cell": "^3.22.3",
|
|
137
|
-
"@tiptap/extension-table-header": "^3.22.3",
|
|
138
|
-
"@tiptap/extension-table-row": "^3.22.3",
|
|
139
|
-
"@tiptap/extension-text-align": "^3.22.3",
|
|
140
|
-
"@tiptap/pm": "^3.22.3",
|
|
141
|
-
"@tiptap/react": "^3.22.3",
|
|
142
|
-
"@tiptap/starter-kit": "^3.22.3",
|
|
143
|
-
"@types/qrcode": "^1.5.6",
|
|
144
|
-
"@xyflow/react": "^12.8.6",
|
|
145
|
-
"axios": "^1.12.2",
|
|
146
|
-
"class-variance-authority": "^0.7.1",
|
|
147
|
-
"clsx": "^2.1.1",
|
|
148
|
-
"cmdk": "^1.1.1",
|
|
149
|
-
"date-fns": "^4.1.0",
|
|
150
|
-
"embla-carousel-react": "^8.6.0",
|
|
151
|
-
"howler": "^2.2.4",
|
|
152
|
-
"lucide-react": "^0.544.0",
|
|
153
|
-
"qrcode": "^1.5.4",
|
|
154
|
-
"radix-ui": "^1.4.3",
|
|
155
|
-
"react-day-picker": "^9.14.0",
|
|
156
|
-
"react-hook-form": "^7.65.0",
|
|
157
|
-
"sonner": "^2.0.7",
|
|
158
|
-
"tailwind-merge": "^3.3.1",
|
|
159
|
-
"vaul": "^1.1.2",
|
|
160
|
-
"zod": "^4.1.11",
|
|
161
|
-
"zustand": "^5.0.8"
|
|
162
|
-
}
|
|
163
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@tinyweb_dev/oe-exam-sdk",
|
|
3
|
+
"version": "0.1.24",
|
|
4
|
+
"description": "Reusable OceanEdu question components.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"oe-exam-mcp": "./dist/mcp/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"sideEffects": [
|
|
17
|
+
"**/*.css"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"clean": "rm -rf dist",
|
|
21
|
+
"build:compile": "tsc -p tsconfig.build.json",
|
|
22
|
+
"build:alias": "tsc-alias -p tsconfig.build.json",
|
|
23
|
+
"build:ts": "npm run build:compile && npm run build:assets && npm run build:alias",
|
|
24
|
+
"build:assets": "for d in cambridge-yle english-certification summer-sky; do [ -d src/components/themes/$d/assets ] && cp -R src/components/themes/$d/assets dist/components/themes/$d/ || true; done; [ -d src/components/shared/audio/assets ] && cp -R src/components/shared/audio/assets dist/components/shared/audio/ || true; [ -d src/components/results/report/assets ] && mkdir -p dist/components/results/report && cp -R src/components/results/report/assets dist/components/results/report/ || true; (cd src && find . -name '*.module.css' -exec cp --parents {} ../dist/ \\;); cp src/global.d.ts dist/global.d.ts",
|
|
25
|
+
"minify:js": "find dist -name '*.js' -type f -exec sh -c 'for f do terser \"$f\" --compress directives=false --mangle --module --comments false --output \"$f\"; done' sh {} +",
|
|
26
|
+
"build": "npm run clean && npm run build:ts && npm run minify:js",
|
|
27
|
+
"pack:local": "npm pack",
|
|
28
|
+
"release": "npm run release:patch",
|
|
29
|
+
"release:patch": "npm version patch --no-git-tag-version && npm run release:push",
|
|
30
|
+
"release:minor": "npm version minor --no-git-tag-version && npm run release:push",
|
|
31
|
+
"release:major": "npm version major --no-git-tag-version && npm run release:push",
|
|
32
|
+
"release:push": "npm run build && npm pack --dry-run && VERSION=$(node -p \"require('./package.json').version\") && git add package.json package-lock.json && git commit -m \"chore(sdk): release v$VERSION\" && git tag \"sdk-v$VERSION\" && git push origin HEAD && git push origin \"sdk-v$VERSION\"",
|
|
33
|
+
"prepack": "npm run build"
|
|
34
|
+
},
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"import": "./dist/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./api": {
|
|
41
|
+
"types": "./dist/api/index.d.ts",
|
|
42
|
+
"import": "./dist/api/index.js"
|
|
43
|
+
},
|
|
44
|
+
"./components": {
|
|
45
|
+
"types": "./dist/components/index.d.ts",
|
|
46
|
+
"import": "./dist/components/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./mcp": {
|
|
49
|
+
"types": "./dist/mcp/index.d.ts",
|
|
50
|
+
"import": "./dist/mcp/index.js"
|
|
51
|
+
},
|
|
52
|
+
"./components/exams": {
|
|
53
|
+
"types": "./dist/components/exams/index.d.ts",
|
|
54
|
+
"import": "./dist/components/exams/index.js"
|
|
55
|
+
},
|
|
56
|
+
"./components/exams/take": {
|
|
57
|
+
"types": "./dist/components/exams/take/index.d.ts",
|
|
58
|
+
"import": "./dist/components/exams/take/index.js"
|
|
59
|
+
},
|
|
60
|
+
"./components/exams/entry": {
|
|
61
|
+
"types": "./dist/components/exams/entry/index.d.ts",
|
|
62
|
+
"import": "./dist/components/exams/entry/index.js"
|
|
63
|
+
},
|
|
64
|
+
"./components/exams/rooms": {
|
|
65
|
+
"types": "./dist/components/exams/rooms/index.d.ts",
|
|
66
|
+
"import": "./dist/components/exams/rooms/index.js"
|
|
67
|
+
},
|
|
68
|
+
"./components/questions": {
|
|
69
|
+
"types": "./dist/components/questions/index.d.ts",
|
|
70
|
+
"import": "./dist/components/questions/index.js"
|
|
71
|
+
},
|
|
72
|
+
"./components/themes": {
|
|
73
|
+
"types": "./dist/components/themes/index.d.ts",
|
|
74
|
+
"import": "./dist/components/themes/index.js"
|
|
75
|
+
},
|
|
76
|
+
"./components/results": {
|
|
77
|
+
"types": "./dist/components/results/index.d.ts",
|
|
78
|
+
"import": "./dist/components/results/index.js"
|
|
79
|
+
},
|
|
80
|
+
"./components/questions/*": {
|
|
81
|
+
"types": "./dist/components/questions/*.d.ts",
|
|
82
|
+
"import": "./dist/components/questions/*.js"
|
|
83
|
+
},
|
|
84
|
+
"./shared": {
|
|
85
|
+
"types": "./dist/shared/index.d.ts",
|
|
86
|
+
"import": "./dist/shared/index.js"
|
|
87
|
+
},
|
|
88
|
+
"./*": {
|
|
89
|
+
"types": "./dist/components/questions/*.d.ts",
|
|
90
|
+
"import": "./dist/components/questions/*.js"
|
|
91
|
+
},
|
|
92
|
+
"./package.json": "./package.json"
|
|
93
|
+
},
|
|
94
|
+
"publishConfig": {
|
|
95
|
+
"access": "public"
|
|
96
|
+
},
|
|
97
|
+
"peerDependencies": {
|
|
98
|
+
"next": ">=15",
|
|
99
|
+
"react": ">=19",
|
|
100
|
+
"react-dom": ">=19"
|
|
101
|
+
},
|
|
102
|
+
"devDependencies": {
|
|
103
|
+
"@types/node": "^25.9.3",
|
|
104
|
+
"terser": "^5.48.0",
|
|
105
|
+
"tsc-alias": "^1.8.17",
|
|
106
|
+
"typescript": "~5.9.2"
|
|
107
|
+
},
|
|
108
|
+
"dependencies": {
|
|
109
|
+
"@dnd-kit/core": "^6.3.1",
|
|
110
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
111
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
112
|
+
"@fortawesome/free-solid-svg-icons": "^7.3.1",
|
|
113
|
+
"@fortawesome/react-fontawesome": "^3.3.1",
|
|
114
|
+
"@hookform/resolvers": "^5.2.2",
|
|
115
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
116
|
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
117
|
+
"@radix-ui/react-avatar": "^1.1.10",
|
|
118
|
+
"@radix-ui/react-checkbox": "^1.3.3",
|
|
119
|
+
"@radix-ui/react-collapsible": "^1.1.12",
|
|
120
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
121
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
122
|
+
"@radix-ui/react-hover-card": "^1.1.15",
|
|
123
|
+
"@radix-ui/react-label": "^2.1.7",
|
|
124
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
125
|
+
"@radix-ui/react-progress": "^1.1.7",
|
|
126
|
+
"@radix-ui/react-radio-group": "^1.3.8",
|
|
127
|
+
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
128
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
129
|
+
"@radix-ui/react-separator": "^1.1.7",
|
|
130
|
+
"@radix-ui/react-slot": "^1.2.3",
|
|
131
|
+
"@radix-ui/react-switch": "^1.2.6",
|
|
132
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
133
|
+
"@radix-ui/react-tooltip": "^1.2.8",
|
|
134
|
+
"@tanstack/react-query": "^5.90.2",
|
|
135
|
+
"@tiptap/extension-table": "^3.22.3",
|
|
136
|
+
"@tiptap/extension-table-cell": "^3.22.3",
|
|
137
|
+
"@tiptap/extension-table-header": "^3.22.3",
|
|
138
|
+
"@tiptap/extension-table-row": "^3.22.3",
|
|
139
|
+
"@tiptap/extension-text-align": "^3.22.3",
|
|
140
|
+
"@tiptap/pm": "^3.22.3",
|
|
141
|
+
"@tiptap/react": "^3.22.3",
|
|
142
|
+
"@tiptap/starter-kit": "^3.22.3",
|
|
143
|
+
"@types/qrcode": "^1.5.6",
|
|
144
|
+
"@xyflow/react": "^12.8.6",
|
|
145
|
+
"axios": "^1.12.2",
|
|
146
|
+
"class-variance-authority": "^0.7.1",
|
|
147
|
+
"clsx": "^2.1.1",
|
|
148
|
+
"cmdk": "^1.1.1",
|
|
149
|
+
"date-fns": "^4.1.0",
|
|
150
|
+
"embla-carousel-react": "^8.6.0",
|
|
151
|
+
"howler": "^2.2.4",
|
|
152
|
+
"lucide-react": "^0.544.0",
|
|
153
|
+
"qrcode": "^1.5.4",
|
|
154
|
+
"radix-ui": "^1.4.3",
|
|
155
|
+
"react-day-picker": "^9.14.0",
|
|
156
|
+
"react-hook-form": "^7.65.0",
|
|
157
|
+
"sonner": "^2.0.7",
|
|
158
|
+
"tailwind-merge": "^3.3.1",
|
|
159
|
+
"vaul": "^1.1.2",
|
|
160
|
+
"zod": "^4.1.11",
|
|
161
|
+
"zustand": "^5.0.8"
|
|
162
|
+
}
|
|
163
|
+
}
|
package/dist/mcp/config.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
declare const schema: z.ZodObject<{
|
|
3
|
-
OE_API_URL: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
4
|
-
OE_API_TOKEN: z.ZodString;
|
|
5
|
-
OE_HTTP_TIMEOUT_MS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
6
|
-
}, z.core.$strip>;
|
|
7
|
-
export type McpConfig = z.infer<typeof schema> & {
|
|
8
|
-
packageName: string;
|
|
9
|
-
packageVersion: string;
|
|
10
|
-
};
|
|
11
|
-
export declare function loadMcpConfig(): McpConfig;
|
|
12
|
-
export {};
|
package/dist/mcp/config.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{readFileSync as e}from"node:fs";import{dirname as r,join as o}from"node:path";import{fileURLToPath as n}from"node:url";import{z as t}from"zod";const s=function(){try{const t=r(n(import.meta.url));return JSON.parse(e(o(t,"..","..","package.json"),"utf8"))}catch{return{name:"@tinyweb_dev/oe-exam-sdk",version:"0.0.0"}}}(),a=t.object({OE_API_URL:t.string().url().transform(e=>e.replace(/\/+$/,"")),OE_API_TOKEN:t.string().min(1),OE_HTTP_TIMEOUT_MS:t.coerce.number().int().positive().default(15e3)});let i=null;export function loadMcpConfig(){if(i)return i;const e=a.safeParse(process.env);if(!e.success){const r=e.error.issues.map(e=>` • ${e.path.join(".")||"<root>"}: ${e.message}`).join("\n");console.error(`\n[oe-exam-mcp] Configuration error:\n${r}\n\nRequired: OE_API_URL and OE_API_TOKEN.\n`),process.exit(1)}return i={...e.data,packageName:s.name,packageVersion:s.version},i}
|
package/dist/mcp/http-client.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{ErrorCode as t,McpError as o}from"@modelcontextprotocol/sdk/types.js";import{loadMcpConfig as r}from"./config.js";export async function mcpRequest(n){const s=r(),a=new AbortController,i=setTimeout(()=>a.abort(),s.OE_HTTP_TIMEOUT_MS);try{const r=await fetch(`${s.OE_API_URL}${n.url}`,{method:n.method,signal:a.signal,headers:{Accept:"application/json","Content-Type":"application/json",...e(s.OE_API_TOKEN)},body:void 0===n.body?void 0:JSON.stringify(n.body)}),i=await r.text(),c=i?JSON.parse(i):void 0;if(!r.ok){const e=function(t){if(!t||"object"!=typeof t)return;const o=t.message;return Array.isArray(o)?o.join("; "):"string"==typeof o?o:void 0}(c)??r.statusText,s=400===r.status||404===r.status||422===r.status?t.InvalidParams:t.InternalError;throw new o(s,`[${n.method} ${n.url}] ${r.status}: ${e}`)}return c}catch(r){if(r instanceof o)throw r;throw new o(t.InternalError,r instanceof Error?r.message:"Unknown HTTP error")}finally{clearTimeout(i)}}function e(t){return t?t.startsWith("oeexam_")?{"X-API-Key":t}:{Authorization:`Bearer ${t}`}:{}}
|
package/dist/mcp/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
export declare function startOeExamMcpServer(): Promise<void>;
|
|
3
|
-
export { loadMcpConfig } from './config.js';
|
|
4
|
-
export { registerAllMcpTools } from './tools/index.js';
|
|
5
|
-
export { registerExamTools } from './tools/exams.js';
|
|
6
|
-
export { registerResultTools } from './tools/results.js';
|
package/dist/mcp/index.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{McpServer as e}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as o}from"@modelcontextprotocol/sdk/server/stdio.js";import{loadMcpConfig as r}from"./config.js";import{registerAllMcpTools as s}from"./tools/index.js";export async function startOeExamMcpServer(){const t=r(),a=new e({name:t.packageName,version:t.packageVersion},{capabilities:{tools:{},logging:{}},instructions:"OE Exam MCP server. Use exam_json_template_generate then exam_create_from_json to create an exam, and exam_result_get to view a result review."});s(a),await a.connect(new o);const c=async()=>{await a.close().catch(e=>console.error("[oe-exam-mcp] server.close failed",e)),process.exit(0)};process.on("SIGINT",()=>{c()}),process.on("SIGTERM",()=>{c()})}import.meta.url===`file://${process.argv[1]}`&&startOeExamMcpServer().catch(e=>{console.error("[oe-exam-mcp] Fatal startup error",e),process.exit(1)});export{loadMcpConfig}from"./config.js";export{registerAllMcpTools}from"./tools/index.js";export{registerExamTools}from"./tools/exams.js";export{registerResultTools}from"./tools/results.js";
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
-
export declare function buildToolResult<T>(value: T): CallToolResult;
|
|
3
|
-
export declare function wrapHandler<TInput extends Record<string, unknown>>(toolName: string, fn: (input: TInput) => Promise<CallToolResult>): (input: TInput) => Promise<CallToolResult>;
|
|
4
|
-
export declare function unwrapData<T>(value: unknown): T;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{ErrorCode as t,McpError as r}from"@modelcontextprotocol/sdk/types.js";export function buildToolResult(t){return{content:[{type:"text",text:"string"==typeof t?t:JSON.stringify(t,null,2)}],...t&&"object"==typeof t?{structuredContent:t}:{}}}export function wrapHandler(e,o){return async n=>{try{return await o(n)}catch(o){if(o instanceof r)throw o;throw console.error(`[oe-exam-mcp] ${e} failed`,o),new r(t.InternalError,o instanceof Error?o.message:"Unknown error")}}}export function unwrapData(t){return t&&"object"==typeof t&&"data"in t?t.data:t}
|
package/dist/mcp/tools/exams.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{mkdir as e,writeFile as t}from"node:fs/promises";import{dirname as n,resolve as i}from"node:path";import{z as a}from"zod";import{mcpRequest as o}from"../http-client.js";import{buildToolResult as r,unwrapData as s,wrapHandler as l}from"./_helpers.js";const p=a.record(a.string(),a.unknown()).describe("Full API question payload or short form: { question, options, answer, points?, partId?, partNo? }."),u=(a.record(a.string(),a.unknown()).describe("Part payload: { name?, partId?, questions: [...] }."),a.record(a.string(),a.unknown()).describe("Template payload accepted by PATCH /manage/exams/:id/template.")),m=a.enum(["PRE_A1","A1","A2","B1","B2","C1","C2"]);export function registerExamTools(g){g.registerTool("exam_templates_search",{title:"Search exam templates",description:"Search available OE Exam templates. Use this before exam_create_with_questions to choose examTemplateId.",inputSchema:{search:a.string().optional().describe("Template name keyword."),page:a.number().int().positive().default(1).describe("1-based page number."),limit:a.number().int().positive().max(50).default(9).describe("Page size sent as API size.")}},l("exam_templates_search",async e=>{const t=new URLSearchParams({page:String(e.page??1),size:String(e.limit??9)});e.search&&t.set("filter",`name:like:${e.search}`);const n=await o({method:"GET",url:`/api/v1/exam-templates?${t}`});return r({templates:k(n)})})),g.registerTool("exam_template_get",{title:"Get exam template",description:"Get one OE Exam template by id. The returned templatePayload can be passed as template to exam_create_with_questions.",inputSchema:{id:a.string().min(1).describe("Template id from exam_templates_search.")}},l("exam_template_get",async e=>{const t=s(await o({method:"GET",url:`/api/v1/exam-templates/${encodeURIComponent(String(e.id))}`}));return r({template:t,templatePayload:P(t)})})),g.registerTool("exam_question_template_get",{title:"Get question payload template",description:"Return easy-to-fill question JSON templates for exam_create_with_questions. Use this before creating questions if you need the expected shape.",inputSchema:{templateId:a.string().min(1).optional().describe("Template id. If provided, generate question payloads from template.parts."),type:a.string().default("CHOOSE_THE_CORRECT_ANSWER").describe("Fallback question type when templateId is omitted."),count:a.number().int().positive().max(100).default(1).describe("Fallback count when templateId is omitted."),partId:a.union([a.string(),a.number()]).default(1),partNo:a.number().int().positive().default(1),skill:a.string().default("READING")}},l("exam_question_template_get",async e=>{const t="string"==typeof e.templateId?s(await o({method:"GET",url:`/api/v1/exam-templates/${encodeURIComponent(e.templateId)}`})):void 0;return r({usage:"Pass questions directly into exam_create_with_questions.questions. Fill content/correctAnswer for each generated API-format payload.",templateId:t?.id,questions:t?b(t):S(e)})})),g.registerTool("exam_json_template_generate",{title:"Get exam JSON template",description:"Generate a user-friendly examJson skeleton from templateTitle or templateId. Edit this JSON, then pass it to exam_create_from_json.",inputSchema:{templateTitle:a.string().optional().describe("Template title to search, e.g. Achievers 2026 Round 1."),templateId:a.string().optional().describe("Exact template id. Preferred when known."),name:a.string().optional().describe("Exam name to put in the JSON."),examLevel:m.optional().describe("Optional exam level for the generated JSON."),difficulty:a.enum(["EASY","MEDIUM","HARD"]).optional().describe("Optional difficulty for the generated JSON."),durationMinutes:a.number().int().positive().optional().describe("Optional duration for the generated JSON.")}},l("exam_json_template_generate",async a=>{const o=await f({templateId:a.templateId,templateTitle:a.templateTitle}),s=function(e,t){const n=Array.isArray(e.parts)?e.parts.filter(c):[];return{name:v(t.name,`${e.title??e.name??"OE Exam"} Draft`),templateId:e.id,templateTitle:e.title??e.name,totalScore:O(e.totalScore??e.total_questions,y(n)),examLevel:_(t.examLevel)??_(e.examLevel??e.exam_level??e.level)??"A1",difficulty:E(t.difficulty)??"MEDIUM",durationMinutes:O(t.durationMinutes,45),isComplete:!1,isActive:!1,parts:n.map((e,t)=>function(e,t){const n=O(e.startIndex,0),i=O(e.questionCount,O(e.endIndex,n)-n+1);return{id:e.id??t+1,name:e.name??`Part ${t+1}`,questionType:v(e.questionType,"CHOOSE_THE_CORRECT_ANSWER"),skill:v(e.skill,"READING"),questions:Array.from({length:Math.max(i,0)},(t,i)=>function(e,t){const n=v(e.questionType,"CHOOSE_THE_CORRECT_ANSWER"),i=(Array.isArray(e.defaultValue)&&e.defaultValue.length>0?e.defaultValue:Array.from({length:O(e.optionCount,4)},(e,t)=>String.fromCharCode(65+t))).map(String);return n.includes("FILL")||n.includes("WRITE")?{question:`Question ${t}`,answer:""}:n.includes("SPEAK")?{prompt:`Question ${t}`,expectedAnswer:""}:{question:`Question ${t}`,options:i,answer:i[0]??"A"}}(e,n+i+1))}}(e,t))}}(o,a),l=JSON.stringify(s,null,2),p=i(`${u=String(a.name??o.title??o.name??"exam"),u.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,80)||"exam"}.json`);var u;return await e(n(p),{recursive:!0}),await t(p,`${l}\n`,"utf8"),r({usage:"Edit filePath, then call exam_create_from_json with the edited JSON string.",templateId:o.id,templateTitle:o.title??o.name,filePath:p,examJson:s,examJsonString:l})})),g.registerTool("exam_create_from_json",{title:"Create exam from JSON",description:"Create an exam from a user-friendly JSON payload grouped by parts. Searches template by title, patches template, maps questions to template.parts, then creates questions.",inputSchema:{examJson:a.string().optional().describe("JSON string with { name, templateTitle/templateId, parts: [{ questions: [...] }] }. Use this for copy/paste."),exam:a.record(a.string(),a.unknown()).optional().describe("Same payload as object if the client supports object arguments.")}},l("exam_create_from_json",async e=>{const t=function(e,t){if(c(t))return t;if("string"!=typeof e||!e.trim())throw new Error("examJson or exam is required");const n=JSON.parse(e);if(!c(n))throw new Error("examJson must be a JSON object");return n}(e.examJson,e.exam),n=await f(t),i=function(e,t){const n=Array.isArray(t.parts)?t.parts.filter(c):[],i=Array.isArray(e.parts)?e.parts.filter(c):[{questions:e.questions}];return i.flatMap((e,t)=>{const i=function(e,t,n){const i=A(e.partId??e.id),a=A(e.name);return t.find(e=>String(e.id)===i)??t.find(e=>"string"==typeof e.name&&e.name===a)??t[n]??{id:n+1,questionType:"CHOOSE_THE_CORRECT_ANSWER",skill:"READING",optionCount:4}}(e,n,t);return(Array.isArray(e.questions)?e.questions.filter(c):[]).map((e,n)=>function(e,t,n,i){const a=O(t.startIndex,0),o=w({questionType:v(e.questionType??e.type??t.questionType,"CHOOSE_THE_CORRECT_ANSWER"),questionNumber:O(e.questionNumber,a+i+1),partId:String(e.partId??t.id??n+1),partNo:O(e.partNo,n+1),sectionId:R(e.sectionId??t.sectionId),skill:v(e.questionSkillType??e.skill??t.skill,"READING"),optionCount:O(t.optionCount,4),defaultValue:Array.isArray(t.defaultValue)?t.defaultValue:void 0});return q(function(e){const t=c(e.content)?{...e.content}:{};"string"==typeof e.question&&(t.question=e.question);"string"==typeof e.text&&(t.question=e.text);Array.isArray(e.options)&&(t.optionType=t.optionType??"text",t.options=e.options);return d({...e,content:c(t)?t:e.content,correctAnswer:void 0===e.answer&&void 0===e.expectedAnswer?e.correctAnswer:x(e.questionType,e.answer??e.expectedAnswer,t.options)})}({...o,...e}),i)}(e,i,t,n))})}(t,n),a=function(e,t,n){return{exam:d({name:v(e.name,"New OE Exam"),code:A(e.code)??h(v(e.name,"New OE Exam")),totalScore:O(e.totalScore,n.length||100),description:A(e.description)??A(e.templateTitle)??"",isComplete:T(e.isComplete,!1),isActive:T(e.isActive,!1),examTemplateId:t,examLevel:_(e.examLevel),difficulty:E(e.difficulty),durationMinutes:R(e.durationMinutes)})}}(t,n.id,i),l=s(await o({method:"POST",url:"/api/v1/manage/exams",body:a.exam}));await o({method:"PATCH",url:`/api/v1/manage/exams/${encodeURIComponent(l.id)}/template`,body:{template:P(n)}});const p=0===i.length?null:await o({method:"POST",url:"/api/v1/manage/questions/batch",body:{examId:l.id,questions:i}});return r({exam:l,templateId:n.id,questions:p,generatedQuestionCount:i.length})})),g.registerTool("exam_create_with_questions",{title:"Create exam with questions",description:"Create an exam, optionally patch template, then bulk create questions via /api/v1/manage/questions/batch. If you do not know examTemplateId/template, call exam_templates_search then exam_template_get first.",inputSchema:{name:a.string().min(1),code:a.string().min(1).optional(),examLevel:m.optional().describe("Valid exam level only: PRE_A1, A1, A2, B1, B2, C1, C2. Do not use template title/id here."),difficulty:a.enum(["EASY","MEDIUM","HARD"]).optional(),totalScore:a.number().nonnegative().optional(),durationMinutes:a.number().int().positive().optional(),description:a.string().optional(),isComplete:a.boolean().optional(),isActive:a.boolean().optional(),examTemplateId:a.string().min(1).optional(),template:u.optional(),questions:a.array(p).default([])}},l("exam_create_with_questions",async e=>{const{template:t,questions:n,...i}=e,a=s(await o({method:"POST",url:"/api/v1/manage/exams",body:d(i)})),l=c(t)?t:await async function(e){if("string"!=typeof e||!e)return;const t=s(await o({method:"GET",url:`/api/v1/exam-templates/${encodeURIComponent(e)}`}));return P(t)}(i.examTemplateId);c(l)&&await o({method:"PATCH",url:`/api/v1/manage/exams/${encodeURIComponent(a.id)}/template`,body:{template:l}});const p=n.map(q),u=0===p.length?null:await o({method:"POST",url:"/api/v1/manage/questions/batch",body:{examId:a.id,questions:p}});return r({exam:a,questions:u})}))}function d(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}function c(e){return Boolean(e&&"object"==typeof e&&!Array.isArray(e)&&Object.keys(e).length>0)}async function f(e){const t=A(e.templateId);if(t)return s(await o({method:"GET",url:`/api/v1/exam-templates/${encodeURIComponent(t)}`}));const n=A(e.templateTitle);if(!n)throw new Error("templateTitle or templateId is required");const i=new URLSearchParams({page:"1",size:"10",filter:`name:like:${n}`}),a=k(await o({method:"GET",url:`/api/v1/exam-templates?${i}`})),r=a.find(e=>(e.title??e.name)===n),l=r??a[0];if(!l?.id)throw new Error(`No exam template found for title: ${n}`);return s(await o({method:"GET",url:`/api/v1/exam-templates/${encodeURIComponent(l.id)}`}))}function y(e){return e.reduce((e,t)=>e+O(t.questionCount,0),0)}function x(e,t,n){if(void 0===t)return;const i=String(e??"");return i.includes("FILL")||i.includes("WRITE")?{answers:[String(t)]}:i.includes("SPEAK")?{expectedAnswer:String(t)}:{answer:g(t,n)}}function g(e,t){if("string"==typeof e&&Array.isArray(t)){const n=t.map(String).findIndex(t=>t===e);if(n>=0)return n}return I(e)}function h(e){return e.toUpperCase().replace(/[^A-Z0-9]+/g,"_").replace(/^_|_$/g,"").slice(0,40)||"OE_EXAM"}function A(e){return"string"==typeof e&&e?e:void 0}function T(e,t){return"boolean"==typeof e?e:t}function _(e){return"string"==typeof e&&m.safeParse(e).success?e:void 0}function E(e){return"string"==typeof e&&["EASY","MEDIUM","HARD"].includes(e)?e:void 0}function q(e,t){if(e.questionType)return d({...e,partId:void 0===e.partId?void 0:String(e.partId),partNo:e.partNo??1,questionNumber:e.questionNumber??t+1,points:e.points??1,addToQuestionBank:e.addToQuestionBank??!1,isExample:e.isExample??!1});const n=Array.isArray(e.options)?e.options:["A","B","C","D"];return d({questionType:e.type??"CHOOSE_THE_CORRECT_ANSWER",content:e.content??{question:String(e.question??e.text??`Question ${t+1}`),optionType:"text",options:n},correctAnswer:e.correctAnswer??{answer:I(e.answer??e.correctAnswerIndex??0)},points:e.points??1,explanation:e.explanation??"",questionNumber:e.questionNumber??t+1,partId:String(e.partId??1),partNo:e.partNo??1,sectionId:e.sectionId,questionSkillType:e.questionSkillType??e.skill??"READING",addToQuestionBank:e.addToQuestionBank??!1,isExample:e.isExample??!1})}function I(e){if("number"==typeof e)return e;if("string"==typeof e&&/^[A-E]$/i.test(e))return e.toUpperCase().charCodeAt(0)-65;const t=Number(e);return Number.isFinite(t)?t:0}function S(e){return Array.from({length:Number(e.count??1)},(t,n)=>w({questionType:String(e.type??"CHOOSE_THE_CORRECT_ANSWER"),questionNumber:n+1,partId:String(e.partId??1),partNo:Number(e.partNo??1),skill:String(e.skill??"READING")}))}function b(e){return(Array.isArray(e.parts)?e.parts.filter(c):[]).flatMap((e,t)=>{const n=O(e.startIndex,0),i=O(e.questionCount,O(e.endIndex,n)-n+1);return Array.from({length:Math.max(i,0)},(i,a)=>w({questionType:v(e.questionType,"CHOOSE_THE_CORRECT_ANSWER"),questionNumber:n+a+1,partId:String(e.id??t+1),partNo:t+1,sectionId:R(e.sectionId),skill:v(e.skill,"READING"),optionCount:O(e.optionCount,4),defaultValue:Array.isArray(e.defaultValue)?e.defaultValue:void 0}))})}function w(e){return d({questionType:e.questionType,content:C(e.questionType,e.questionNumber,e.optionCount,e.defaultValue),correctAnswer:N(e.questionType),points:1,explanation:"",questionNumber:e.questionNumber,partId:e.partId,partNo:e.partNo,sectionId:e.sectionId,questionSkillType:e.skill,addToQuestionBank:!1,isExample:!1})}function C(e,t,n=4,i){const a=(i?.length?i:Array.from({length:n},(e,t)=>String.fromCharCode(65+t))).map(String);return e.includes("FILL")||e.includes("WRITE")?{question:`Question ${t}`,text:""}:e.includes("SPEAK")?{prompt:`Question ${t}`}:e.includes("LISTEN")?{question:`Question ${t}`,audioUrl:"",optionType:"text",options:a}:{question:`Question ${t}`,optionType:"text",options:a}}function N(e){return e.includes("FILL")||e.includes("WRITE")?{answers:[""]}:e.includes("SPEAK")?{expectedAnswer:""}:{answer:0}}function v(e,t){return"string"==typeof e&&e?e:t}function O(e,t){const n=Number(e);return Number.isFinite(n)?n:t}function R(e){const t=Number(e);return Number.isFinite(t)?t:void 0}function k(e){const t=s(e);return Array.isArray(t)?t:t&&"object"==typeof t&&"data"in t&&Array.isArray(t.data)?t.data:[]}function P(e){const t=Array.isArray(e.parts)?e.parts:[];return d({id:e.id,title:e.title??e.name,subTitle:e.subTitle??e.sub_title??"",theme:e.theme,totalQuestions:e.totalQuestions??e.total_questions,totalParts:e.totalParts??e.total_parts??t.length,description:e.description??"",examLevel:e.examLevel??e.exam_level??e.level??"",type:e.type??null,parts:t})}
|
package/dist/mcp/tools/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{registerExamTools as o}from"./exams.js";import{registerResultTools as r}from"./results.js";export function registerAllMcpTools(s){o(s),r(s)}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{z as t}from"zod";import{mcpRequest as e}from"../http-client.js";import{buildToolResult as n,wrapHandler as o}from"./_helpers.js";export function registerResultTools(r){r.registerTool("exam_result_get",{title:"Get exam result review",description:"Fetch student exam result review by attemptId. Optional token supports public result review links.",inputSchema:{attemptId:t.string().min(1),token:t.string().min(1).optional(),includeAttempt:t.boolean().default(!0)}},o("exam_result_get",async({attemptId:t,token:o,includeAttempt:r})=>{const i=o?`?token=${encodeURIComponent(String(o))}`:"",s=await e({method:"GET",url:`/api/v1/student/results/${encodeURIComponent(String(t))}${i}`}),l=!1===r?null:await e({method:"GET",url:`/api/v1/student/attempts/${encodeURIComponent(String(t))}${i}`});return n({result:s,attempt:l})}))}
|