@quizbase/client 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -3
- package/dist/index.d.cts +12 -4
- package/dist/index.d.ts +12 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @quizbase/client
|
|
2
2
|
|
|
3
|
-
TypeScript SDK for the [QuizBase API](https://quizbase.runriva.com) — multilingual trivia API
|
|
3
|
+
TypeScript SDK for the [QuizBase API](https://quizbase.runriva.com) — a multilingual trivia API. 1.4M+ blended, deduped questions from 11 open datasets (CC, MIT), English and Polish at launch. Per-record license, author, and source on every response.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@quizbase/client)
|
|
6
6
|
[](https://www.npmjs.com/package/@quizbase/client)
|
|
@@ -28,7 +28,7 @@ const client = createClient({
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
const random = await client.questions.random({ category: 'science-and-nature', lang: 'en' });
|
|
31
|
-
console.log(random.data.
|
|
31
|
+
console.log(random.data[0].text);
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Get a key at [quizbase.runriva.com/dashboard/keys](https://quizbase.runriva.com/dashboard/keys). The free tier is **500 requests/day across all your keys** against full production data — enough to ship a real app. Paid tiers at [/pricing](https://quizbase.runriva.com/pricing).
|
|
@@ -58,6 +58,8 @@ client.report.create({ questionId, kind, comment });
|
|
|
58
58
|
|
|
59
59
|
Full parameter docs: [docs.quizbase.runriva.com/docs](https://quizbase.runriva.com/docs) and the interactive [API Reference](https://quizbase.runriva.com/docs/api-reference).
|
|
60
60
|
|
|
61
|
+
> **Tip:** every question has a stable UUID `id` that never changes. Save it client-side and compose it into multi-language quizzes, daily challenges, anti-cheat, and more — see [Client patterns](#client-patterns-with-stable-ids) below.
|
|
62
|
+
|
|
61
63
|
## Pagination
|
|
62
64
|
|
|
63
65
|
`questions`, `topics`, `tags`, and `subcategories` are cursor-paginated. Use `listAll()` to iterate every item, or `pages()` to iterate page-by-page — both auto-follow `_links.next` and preserve filters across pages.
|
|
@@ -76,6 +78,58 @@ for await (const page of client.topics.pages({ lang: 'en' })) {
|
|
|
76
78
|
|
|
77
79
|
Need manual control? `list()` still exposes `_links.next` and a `cursor` query param.
|
|
78
80
|
|
|
81
|
+
## Client patterns with stable IDs
|
|
82
|
+
|
|
83
|
+
Every question carries a stable UUID v7 `id` that never changes after import. The SDK is intentionally **thin** — no `?seed=`, no `?daily=`, no built-in deduplication. The stable id is the primitive you compose into mechanics. Six patterns cover most real apps:
|
|
84
|
+
|
|
85
|
+
### Same question across languages
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
const en = await client.questions.random({ lang: 'en' });
|
|
89
|
+
const id = en.data[0].id;
|
|
90
|
+
const pl = await client.questions.get(id, { lang: 'pl' });
|
|
91
|
+
const es = await client.questions.get(id, { lang: 'es' });
|
|
92
|
+
// Same canonical question, three languages — UUID is the link.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Don't repeat — exclude seen questions
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
const seen = new Set<string>();
|
|
99
|
+
const batch = await client.questions.random({
|
|
100
|
+
category: 'science-and-nature',
|
|
101
|
+
amount: 20,
|
|
102
|
+
exclude: [...seen]
|
|
103
|
+
});
|
|
104
|
+
batch.data.forEach((q) => seen.add(q.id));
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`exclude` accepts up to 250 UUIDs. For longer histories keep `seen` client-side and filter after the fetch.
|
|
108
|
+
|
|
109
|
+
### Daily challenge — same question for everyone today
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const day = new Date().toISOString().slice(0, 10); // "2026-05-19"
|
|
113
|
+
const idx = [...day].reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 7);
|
|
114
|
+
const pool = await client.questions.list({ category: 'history', limit: 50 });
|
|
115
|
+
const todays = pool.data[Math.abs(idx) % pool.data.length];
|
|
116
|
+
// Persist `todays.id` server-side so retries serve the same question.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Multiplayer sync — both players see the same question
|
|
120
|
+
|
|
121
|
+
Your matchmaker picks one `id` (via `random` or `list`), broadcasts to both clients, and both clients call `questions.get(id, { lang })`. Same UUID, per-player language preference. Zero state on QuizBase — your matchmaker owns the round.
|
|
122
|
+
|
|
123
|
+
### Server-side anti-cheat — never ship `correctAnswer` to the client
|
|
124
|
+
|
|
125
|
+
Use `qb_sk_*` (secret key) from your server to fetch full questions including `correctAnswer`. Forward only `id` + `text` + a shuffled `[correctAnswer, ...incorrectAnswers]` to the client. Validate the submitted answer server-side by re-fetching with the same `id`. Browsers cannot reach `qb_sk_*` — CORS blocks it.
|
|
126
|
+
|
|
127
|
+
### Stable Anki / Quizlet flashcards across updates
|
|
128
|
+
|
|
129
|
+
Save `{id, lang}` as your card key. When the upstream question changes (typo fix, distractor swap, translation refresh), `questions.get(id, { lang })` returns the updated content under the same id — your card auto-updates without re-import. Soft-deleted questions return 404; treat that as "card removed upstream".
|
|
130
|
+
|
|
131
|
+
Full code samples and edge cases at [/docs/api/questions-by-id § What you can do with a stable id](https://quizbase.runriva.com/docs/api/questions-by-id). For MCP agents, the same playbook is exposed as the `client_mechanics_patterns` prompt.
|
|
132
|
+
|
|
79
133
|
## Errors
|
|
80
134
|
|
|
81
135
|
Every non-2xx response throws `QuizbaseError` carrying the parsed [RFC 9457 Problem Details](https://www.rfc-editor.org/rfc/rfc9457):
|
|
@@ -164,7 +218,7 @@ All responses are typed from the OpenAPI spec. Hover over `client.questions.rand
|
|
|
164
218
|
- **GitHub:** [maciejdzierzek/quizbase-sdk-ts](https://github.com/maciejdzierzek/quizbase-sdk-ts)
|
|
165
219
|
- **Issues / feedback:** [GitHub Issues](https://github.com/maciejdzierzek/quizbase-sdk-ts/issues)
|
|
166
220
|
- **Releases:** automated by [release-please](https://github.com/googleapis/release-please) from conventional commits
|
|
167
|
-
- **Drift guard:** the
|
|
221
|
+
- **Drift guard:** every release is verified against the live OpenAPI spec at [quizbase.runriva.com/openapi.json](https://quizbase.runriva.com/openapi.json) — types reflect the current API surface.
|
|
168
222
|
|
|
169
223
|
## License
|
|
170
224
|
|
package/dist/index.d.cts
CHANGED
|
@@ -857,9 +857,10 @@ interface paths {
|
|
|
857
857
|
topic?: string;
|
|
858
858
|
topics_any?: string;
|
|
859
859
|
subcategory?: string;
|
|
860
|
-
|
|
860
|
+
/** @description Quality preset: "high" (default) skips needs_review=true; "all" includes everything */
|
|
861
|
+
quality?: "high" | "all";
|
|
861
862
|
regions?: string;
|
|
862
|
-
source?: "
|
|
863
|
+
source?: "arc" | "creak" | "entityq" | "kqa-pro" | "mintaka" | "mkqa" | "nq-open" | "opentdb" | "opentriviaqa" | "qasc" | "quizbase" | "webq";
|
|
863
864
|
license?: "CC-BY-SA-4.0" | "CC-BY-SA-3.0" | "CC-BY-4.0" | "MIT" | "proprietary";
|
|
864
865
|
count?: "estimate" | "exact" | "none";
|
|
865
866
|
};
|
|
@@ -958,9 +959,10 @@ interface paths {
|
|
|
958
959
|
topic?: string;
|
|
959
960
|
topics_any?: string;
|
|
960
961
|
subcategory?: string;
|
|
961
|
-
|
|
962
|
+
/** @description Quality preset: "high" (default) skips needs_review=true; "all" includes everything */
|
|
963
|
+
quality?: "high" | "all";
|
|
962
964
|
regions?: string;
|
|
963
|
-
source?: "
|
|
965
|
+
source?: "arc" | "creak" | "entityq" | "kqa-pro" | "mintaka" | "mkqa" | "nq-open" | "opentdb" | "opentriviaqa" | "qasc" | "quizbase" | "webq";
|
|
964
966
|
license?: "CC-BY-SA-4.0" | "CC-BY-SA-3.0" | "CC-BY-4.0" | "MIT" | "proprietary";
|
|
965
967
|
exclude?: string;
|
|
966
968
|
};
|
|
@@ -1213,6 +1215,12 @@ interface components {
|
|
|
1213
1215
|
*/
|
|
1214
1216
|
regions: string[];
|
|
1215
1217
|
attribution: components["schemas"]["Attribution"];
|
|
1218
|
+
/**
|
|
1219
|
+
* @description Quality flag. Present only when the client requested non-default content via `?quality=all` (REST) or `quality: "all"` (MCP) — and always on `/api/v1/questions/{id}` deep-link responses. For default `?quality=high` all returned questions are by definition `high`, so the field is omitted to avoid redundancy. `needs_review` = flagged for moderation review (low-quality distractors, trivial answer-in-question patterns).
|
|
1220
|
+
* @example high
|
|
1221
|
+
* @enum {string}
|
|
1222
|
+
*/
|
|
1223
|
+
quality?: "high" | "needs_review";
|
|
1216
1224
|
/**
|
|
1217
1225
|
* Format: uuid
|
|
1218
1226
|
* @description Direct parent (usually English source) when this is a translation.
|
package/dist/index.d.ts
CHANGED
|
@@ -857,9 +857,10 @@ interface paths {
|
|
|
857
857
|
topic?: string;
|
|
858
858
|
topics_any?: string;
|
|
859
859
|
subcategory?: string;
|
|
860
|
-
|
|
860
|
+
/** @description Quality preset: "high" (default) skips needs_review=true; "all" includes everything */
|
|
861
|
+
quality?: "high" | "all";
|
|
861
862
|
regions?: string;
|
|
862
|
-
source?: "
|
|
863
|
+
source?: "arc" | "creak" | "entityq" | "kqa-pro" | "mintaka" | "mkqa" | "nq-open" | "opentdb" | "opentriviaqa" | "qasc" | "quizbase" | "webq";
|
|
863
864
|
license?: "CC-BY-SA-4.0" | "CC-BY-SA-3.0" | "CC-BY-4.0" | "MIT" | "proprietary";
|
|
864
865
|
count?: "estimate" | "exact" | "none";
|
|
865
866
|
};
|
|
@@ -958,9 +959,10 @@ interface paths {
|
|
|
958
959
|
topic?: string;
|
|
959
960
|
topics_any?: string;
|
|
960
961
|
subcategory?: string;
|
|
961
|
-
|
|
962
|
+
/** @description Quality preset: "high" (default) skips needs_review=true; "all" includes everything */
|
|
963
|
+
quality?: "high" | "all";
|
|
962
964
|
regions?: string;
|
|
963
|
-
source?: "
|
|
965
|
+
source?: "arc" | "creak" | "entityq" | "kqa-pro" | "mintaka" | "mkqa" | "nq-open" | "opentdb" | "opentriviaqa" | "qasc" | "quizbase" | "webq";
|
|
964
966
|
license?: "CC-BY-SA-4.0" | "CC-BY-SA-3.0" | "CC-BY-4.0" | "MIT" | "proprietary";
|
|
965
967
|
exclude?: string;
|
|
966
968
|
};
|
|
@@ -1213,6 +1215,12 @@ interface components {
|
|
|
1213
1215
|
*/
|
|
1214
1216
|
regions: string[];
|
|
1215
1217
|
attribution: components["schemas"]["Attribution"];
|
|
1218
|
+
/**
|
|
1219
|
+
* @description Quality flag. Present only when the client requested non-default content via `?quality=all` (REST) or `quality: "all"` (MCP) — and always on `/api/v1/questions/{id}` deep-link responses. For default `?quality=high` all returned questions are by definition `high`, so the field is omitted to avoid redundancy. `needs_review` = flagged for moderation review (low-quality distractors, trivial answer-in-question patterns).
|
|
1220
|
+
* @example high
|
|
1221
|
+
* @enum {string}
|
|
1222
|
+
*/
|
|
1223
|
+
quality?: "high" | "needs_review";
|
|
1216
1224
|
/**
|
|
1217
1225
|
* Format: uuid
|
|
1218
1226
|
* @description Direct parent (usually English source) when this is a translation.
|
package/package.json
CHANGED