@quizbase/client 0.4.0 → 0.4.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 (2) hide show
  1. package/README.md +56 -2
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -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.question);
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 main repo [`tests/api/sdk-contract.spec.ts`](https://github.com/maciejdzierzek/quizbase) verifies the latest published SDK still matches `/openapi.json`
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quizbase/client",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "TypeScript SDK for QuizBase API — typed client, retry, RFC 9457 errors, telemetry hook. Generated from openapi.json.",
5
5
  "license": "MIT",
6
6
  "author": "Maciej Dzierżek",