hibi-client 0.0.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 ADDED
@@ -0,0 +1,40 @@
1
+ # hibi-client
2
+
3
+ Official TypeScript client for the [Hibi](https://github.com/YannickHerrero/hibi) flashcard API.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add hibi-client
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { createHibiClient } from "hibi-client";
15
+
16
+ const client = createHibiClient({
17
+ apiKey: "hibi_...",
18
+ baseUrl: "https://api.hibi.app",
19
+ });
20
+
21
+ // Cards
22
+ const card = await client.cards.create({ /* ... */ });
23
+ const list = await client.cards.list({ limit: 50 });
24
+ await client.cards.update(card.id, { tags: ["anime"] });
25
+ await client.cards.remove(card.id);
26
+
27
+ // Reviews
28
+ const due = await client.reviews.due({ limit: 50 });
29
+ const result = await client.reviews.submit({ cardId: card.id, rating: 3 });
30
+
31
+ // Stats
32
+ const heatmap = await client.stats.heatmap({ year: 2026 });
33
+ const retention = await client.stats.retention();
34
+ ```
35
+
36
+ The surface is intentionally narrow: cards, reviews, stats, account. There is **no dictionary surface** — JMdict and morphological analysis live entirely inside each mining client.
37
+
38
+ ## License
39
+
40
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ var types = require('@hibi/types');
4
+ var zod = require('zod');
5
+
6
+ // src/client.ts
7
+ var PaginatedCardSchema = types.PaginatedSchema(types.CardSchema);
8
+ var DueResponseSchema = zod.z.object({
9
+ items: zod.z.array(
10
+ zod.z.object({ card: types.CardSchema, cardState: types.SubmitReviewResultSchema.shape.cardState })
11
+ )
12
+ });
13
+ function asError(status, body) {
14
+ const err = new Error(`Hibi API error: ${status}`);
15
+ err.status = status;
16
+ err.body = body;
17
+ return err;
18
+ }
19
+ function createHibiClient(config) {
20
+ const fetchImpl = config.fetch ?? fetch;
21
+ const base = config.baseUrl.replace(/\/+$/, "");
22
+ async function request(method, path, schema, init = {}) {
23
+ const url = new URL(`${base}${path}`);
24
+ if (init.query) {
25
+ for (const [k, v] of Object.entries(init.query)) {
26
+ if (v !== void 0) url.searchParams.set(k, String(v));
27
+ }
28
+ }
29
+ const headers = {
30
+ Authorization: `Bearer ${config.apiKey}`
31
+ };
32
+ const requestInit = { method, headers };
33
+ if (init.body !== void 0) {
34
+ headers["Content-Type"] = "application/json";
35
+ requestInit.body = JSON.stringify(init.body);
36
+ }
37
+ const res = await fetchImpl(url.toString(), requestInit);
38
+ if (res.status === 204) return void 0;
39
+ const text = await res.text();
40
+ const body = text ? JSON.parse(text) : null;
41
+ if (!res.ok) throw asError(res.status, body);
42
+ return schema.parse(body);
43
+ }
44
+ return {
45
+ cards: {
46
+ async create(input) {
47
+ const validated = types.CreateCardInputSchema.parse(input);
48
+ return request("POST", "/v1/cards", types.CardSchema, { body: validated });
49
+ },
50
+ async list(query = { limit: 50 }) {
51
+ return request("GET", "/v1/cards", PaginatedCardSchema, {
52
+ query: { limit: query.limit, cursor: query.cursor, tag: query.tag, source: query.source }
53
+ });
54
+ },
55
+ async get(id) {
56
+ return request("GET", `/v1/cards/${id}`, types.CardSchema);
57
+ },
58
+ async update(id, input) {
59
+ const validated = types.UpdateCardInputSchema.parse(input);
60
+ return request("PATCH", `/v1/cards/${id}`, types.CardSchema, { body: validated });
61
+ },
62
+ async remove(id) {
63
+ await request("DELETE", `/v1/cards/${id}`, zod.z.unknown());
64
+ }
65
+ },
66
+ reviews: {
67
+ async due(query = {}) {
68
+ return request("GET", "/v1/reviews/due", DueResponseSchema, {
69
+ query: { limit: query.limit, before: query.before }
70
+ });
71
+ },
72
+ async submit(input) {
73
+ const validated = types.SubmitReviewInputSchema.parse(input);
74
+ return request("POST", "/v1/reviews", types.SubmitReviewResultSchema, { body: validated });
75
+ }
76
+ },
77
+ stats: {
78
+ async heatmap(query) {
79
+ return request("GET", "/v1/stats/heatmap", types.HeatmapResponseSchema, {
80
+ query: { year: query.year }
81
+ });
82
+ },
83
+ async retention() {
84
+ return request("GET", "/v1/stats/retention", types.RetentionResponseSchema);
85
+ },
86
+ async daily(query) {
87
+ return request("GET", "/v1/stats/daily", types.DailyCountResponseSchema, {
88
+ query: { from: query.from, to: query.to }
89
+ });
90
+ }
91
+ }
92
+ };
93
+ }
94
+
95
+ exports.createHibiClient = createHibiClient;
96
+ //# sourceMappingURL=index.cjs.map
97
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"names":["PaginatedSchema","CardSchema","z","SubmitReviewResultSchema","CreateCardInputSchema","UpdateCardInputSchema","SubmitReviewInputSchema","HeatmapResponseSchema","RetentionResponseSchema","DailyCountResponseSchema"],"mappings":"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","file":"index.cjs","sourcesContent":["import {\n CardSchema,\n type CreateCardInput,\n CreateCardInputSchema,\n type DailyCountQuery,\n DailyCountResponseSchema,\n type HeatmapQuery,\n HeatmapResponseSchema,\n type ListCardsQuery,\n PaginatedSchema,\n RetentionResponseSchema,\n type SubmitReviewInput,\n SubmitReviewInputSchema,\n SubmitReviewResultSchema,\n type UpdateCardInput,\n UpdateCardInputSchema,\n} from \"@hibi/types\";\nimport { z } from \"zod\";\n\nexport interface HibiClientConfig {\n apiKey: string;\n baseUrl: string;\n fetch?: typeof fetch;\n}\n\nexport interface HibiClientError extends Error {\n status: number;\n body: unknown;\n}\n\nconst PaginatedCardSchema = PaginatedSchema(CardSchema);\nconst DueResponseSchema = z.object({\n items: z.array(\n z.object({ card: CardSchema, cardState: SubmitReviewResultSchema.shape.cardState }),\n ),\n});\n\nfunction asError(status: number, body: unknown): HibiClientError {\n const err = new Error(`Hibi API error: ${status}`) as HibiClientError;\n err.status = status;\n err.body = body;\n return err;\n}\n\nexport function createHibiClient(config: HibiClientConfig) {\n const fetchImpl = config.fetch ?? fetch;\n const base = config.baseUrl.replace(/\\/+$/, \"\");\n\n async function request<T>(\n method: string,\n path: string,\n schema: z.ZodType<T>,\n init: { body?: unknown; query?: Record<string, string | number | undefined> } = {},\n ): Promise<T> {\n const url = new URL(`${base}${path}`);\n if (init.query) {\n for (const [k, v] of Object.entries(init.query)) {\n if (v !== undefined) url.searchParams.set(k, String(v));\n }\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${config.apiKey}`,\n };\n const requestInit: RequestInit = { method, headers };\n if (init.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n requestInit.body = JSON.stringify(init.body);\n }\n\n const res = await fetchImpl(url.toString(), requestInit);\n\n if (res.status === 204) return undefined as T;\n\n const text = await res.text();\n const body = text ? JSON.parse(text) : null;\n\n if (!res.ok) throw asError(res.status, body);\n return schema.parse(body);\n }\n\n return {\n cards: {\n async create(input: CreateCardInput) {\n const validated = CreateCardInputSchema.parse(input);\n return request(\"POST\", \"/v1/cards\", CardSchema, { body: validated });\n },\n async list(query: ListCardsQuery = { limit: 50 }) {\n return request(\"GET\", \"/v1/cards\", PaginatedCardSchema, {\n query: { limit: query.limit, cursor: query.cursor, tag: query.tag, source: query.source },\n });\n },\n async get(id: string) {\n return request(\"GET\", `/v1/cards/${id}`, CardSchema);\n },\n async update(id: string, input: UpdateCardInput) {\n const validated = UpdateCardInputSchema.parse(input);\n return request(\"PATCH\", `/v1/cards/${id}`, CardSchema, { body: validated });\n },\n async remove(id: string): Promise<void> {\n await request(\"DELETE\", `/v1/cards/${id}`, z.unknown());\n },\n },\n\n reviews: {\n async due(query: { limit?: number; before?: string } = {}) {\n return request(\"GET\", \"/v1/reviews/due\", DueResponseSchema, {\n query: { limit: query.limit, before: query.before },\n });\n },\n async submit(input: SubmitReviewInput) {\n const validated = SubmitReviewInputSchema.parse(input);\n return request(\"POST\", \"/v1/reviews\", SubmitReviewResultSchema, { body: validated });\n },\n },\n\n stats: {\n async heatmap(query: HeatmapQuery) {\n return request(\"GET\", \"/v1/stats/heatmap\", HeatmapResponseSchema, {\n query: { year: query.year },\n });\n },\n async retention() {\n return request(\"GET\", \"/v1/stats/retention\", RetentionResponseSchema);\n },\n async daily(query: DailyCountQuery) {\n return request(\"GET\", \"/v1/stats/daily\", DailyCountResponseSchema, {\n query: { from: query.from, to: query.to },\n });\n },\n },\n };\n}\n\nexport type HibiClient = ReturnType<typeof createHibiClient>;\n"]}
@@ -0,0 +1,225 @@
1
+ import { CreateCardInput, ListCardsQuery, UpdateCardInput, SubmitReviewInput, HeatmapQuery, DailyCountQuery } from '@hibi/types';
2
+ export { Card, CardStateRow, CardStateValue, CreateCardInput, DailyCount, DailyCountResponse, FuriganaPair, HeatmapDay, HeatmapResponse, KanjiEntry, ListCardsQuery, RetentionPoint, RetentionResponse, Review, ReviewRating, SubmitReviewInput, SubmitReviewResult, UpdateCardInput } from '@hibi/types';
3
+
4
+ interface HibiClientConfig {
5
+ apiKey: string;
6
+ baseUrl: string;
7
+ fetch?: typeof fetch;
8
+ }
9
+ interface HibiClientError extends Error {
10
+ status: number;
11
+ body: unknown;
12
+ }
13
+ declare function createHibiClient(config: HibiClientConfig): {
14
+ cards: {
15
+ create(input: CreateCardInput): Promise<{
16
+ id: string;
17
+ userId: string;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ sentence: string;
21
+ focusWord: string;
22
+ focusWordReading: string;
23
+ furigana: {
24
+ base: string;
25
+ reading: string;
26
+ }[];
27
+ english: string;
28
+ glosses: string[];
29
+ grammarNote: string | null;
30
+ kanjiList: {
31
+ kanji: string;
32
+ meaning: string;
33
+ wanikaniLevel: number | null;
34
+ }[];
35
+ imageKey: string | null;
36
+ audioKey: string | null;
37
+ source: string;
38
+ tags: string[];
39
+ }>;
40
+ list(query?: ListCardsQuery): Promise<{
41
+ items: {
42
+ id: string;
43
+ userId: string;
44
+ createdAt: string;
45
+ updatedAt: string;
46
+ sentence: string;
47
+ focusWord: string;
48
+ focusWordReading: string;
49
+ furigana: {
50
+ base: string;
51
+ reading: string;
52
+ }[];
53
+ english: string;
54
+ glosses: string[];
55
+ grammarNote: string | null;
56
+ kanjiList: {
57
+ kanji: string;
58
+ meaning: string;
59
+ wanikaniLevel: number | null;
60
+ }[];
61
+ imageKey: string | null;
62
+ audioKey: string | null;
63
+ source: string;
64
+ tags: string[];
65
+ }[];
66
+ nextCursor: string | null;
67
+ }>;
68
+ get(id: string): Promise<{
69
+ id: string;
70
+ userId: string;
71
+ createdAt: string;
72
+ updatedAt: string;
73
+ sentence: string;
74
+ focusWord: string;
75
+ focusWordReading: string;
76
+ furigana: {
77
+ base: string;
78
+ reading: string;
79
+ }[];
80
+ english: string;
81
+ glosses: string[];
82
+ grammarNote: string | null;
83
+ kanjiList: {
84
+ kanji: string;
85
+ meaning: string;
86
+ wanikaniLevel: number | null;
87
+ }[];
88
+ imageKey: string | null;
89
+ audioKey: string | null;
90
+ source: string;
91
+ tags: string[];
92
+ }>;
93
+ update(id: string, input: UpdateCardInput): Promise<{
94
+ id: string;
95
+ userId: string;
96
+ createdAt: string;
97
+ updatedAt: string;
98
+ sentence: string;
99
+ focusWord: string;
100
+ focusWordReading: string;
101
+ furigana: {
102
+ base: string;
103
+ reading: string;
104
+ }[];
105
+ english: string;
106
+ glosses: string[];
107
+ grammarNote: string | null;
108
+ kanjiList: {
109
+ kanji: string;
110
+ meaning: string;
111
+ wanikaniLevel: number | null;
112
+ }[];
113
+ imageKey: string | null;
114
+ audioKey: string | null;
115
+ source: string;
116
+ tags: string[];
117
+ }>;
118
+ remove(id: string): Promise<void>;
119
+ };
120
+ reviews: {
121
+ due(query?: {
122
+ limit?: number;
123
+ before?: string;
124
+ }): Promise<{
125
+ items: {
126
+ card: {
127
+ id: string;
128
+ userId: string;
129
+ createdAt: string;
130
+ updatedAt: string;
131
+ sentence: string;
132
+ focusWord: string;
133
+ focusWordReading: string;
134
+ furigana: {
135
+ base: string;
136
+ reading: string;
137
+ }[];
138
+ english: string;
139
+ glosses: string[];
140
+ grammarNote: string | null;
141
+ kanjiList: {
142
+ kanji: string;
143
+ meaning: string;
144
+ wanikaniLevel: number | null;
145
+ }[];
146
+ imageKey: string | null;
147
+ audioKey: string | null;
148
+ source: string;
149
+ tags: string[];
150
+ };
151
+ cardState: {
152
+ cardId: string;
153
+ userId: string;
154
+ due: string;
155
+ stability: number;
156
+ difficulty: number;
157
+ elapsedDays: number;
158
+ scheduledDays: number;
159
+ reps: number;
160
+ lapses: number;
161
+ learningSteps: number;
162
+ state: "new" | "learning" | "review" | "relearning";
163
+ lastReview: string | null;
164
+ };
165
+ }[];
166
+ }>;
167
+ submit(input: SubmitReviewInput): Promise<{
168
+ review: {
169
+ id: string;
170
+ userId: string;
171
+ cardId: string;
172
+ rating: 1 | 4 | 2 | 3;
173
+ reviewedAt: string;
174
+ elapsedDays: number;
175
+ scheduledDays: number;
176
+ stateBefore: "new" | "learning" | "review" | "relearning";
177
+ stateAfter: "new" | "learning" | "review" | "relearning";
178
+ };
179
+ cardState: {
180
+ cardId: string;
181
+ userId: string;
182
+ due: string;
183
+ stability: number;
184
+ difficulty: number;
185
+ elapsedDays: number;
186
+ scheduledDays: number;
187
+ reps: number;
188
+ lapses: number;
189
+ learningSteps: number;
190
+ state: "new" | "learning" | "review" | "relearning";
191
+ lastReview: string | null;
192
+ };
193
+ }>;
194
+ };
195
+ stats: {
196
+ heatmap(query: HeatmapQuery): Promise<{
197
+ year: number;
198
+ days: {
199
+ date: string;
200
+ count: number;
201
+ }[];
202
+ }>;
203
+ retention(): Promise<{
204
+ generatedAt: string;
205
+ points: {
206
+ intervalDays: number;
207
+ retention: number;
208
+ sampleSize: number;
209
+ }[];
210
+ }>;
211
+ daily(query: DailyCountQuery): Promise<{
212
+ days: {
213
+ date: string;
214
+ reviews: number;
215
+ again: number;
216
+ hard: number;
217
+ good: number;
218
+ easy: number;
219
+ }[];
220
+ }>;
221
+ };
222
+ };
223
+ type HibiClient = ReturnType<typeof createHibiClient>;
224
+
225
+ export { type HibiClient, type HibiClientConfig, type HibiClientError, createHibiClient };
@@ -0,0 +1,225 @@
1
+ import { CreateCardInput, ListCardsQuery, UpdateCardInput, SubmitReviewInput, HeatmapQuery, DailyCountQuery } from '@hibi/types';
2
+ export { Card, CardStateRow, CardStateValue, CreateCardInput, DailyCount, DailyCountResponse, FuriganaPair, HeatmapDay, HeatmapResponse, KanjiEntry, ListCardsQuery, RetentionPoint, RetentionResponse, Review, ReviewRating, SubmitReviewInput, SubmitReviewResult, UpdateCardInput } from '@hibi/types';
3
+
4
+ interface HibiClientConfig {
5
+ apiKey: string;
6
+ baseUrl: string;
7
+ fetch?: typeof fetch;
8
+ }
9
+ interface HibiClientError extends Error {
10
+ status: number;
11
+ body: unknown;
12
+ }
13
+ declare function createHibiClient(config: HibiClientConfig): {
14
+ cards: {
15
+ create(input: CreateCardInput): Promise<{
16
+ id: string;
17
+ userId: string;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ sentence: string;
21
+ focusWord: string;
22
+ focusWordReading: string;
23
+ furigana: {
24
+ base: string;
25
+ reading: string;
26
+ }[];
27
+ english: string;
28
+ glosses: string[];
29
+ grammarNote: string | null;
30
+ kanjiList: {
31
+ kanji: string;
32
+ meaning: string;
33
+ wanikaniLevel: number | null;
34
+ }[];
35
+ imageKey: string | null;
36
+ audioKey: string | null;
37
+ source: string;
38
+ tags: string[];
39
+ }>;
40
+ list(query?: ListCardsQuery): Promise<{
41
+ items: {
42
+ id: string;
43
+ userId: string;
44
+ createdAt: string;
45
+ updatedAt: string;
46
+ sentence: string;
47
+ focusWord: string;
48
+ focusWordReading: string;
49
+ furigana: {
50
+ base: string;
51
+ reading: string;
52
+ }[];
53
+ english: string;
54
+ glosses: string[];
55
+ grammarNote: string | null;
56
+ kanjiList: {
57
+ kanji: string;
58
+ meaning: string;
59
+ wanikaniLevel: number | null;
60
+ }[];
61
+ imageKey: string | null;
62
+ audioKey: string | null;
63
+ source: string;
64
+ tags: string[];
65
+ }[];
66
+ nextCursor: string | null;
67
+ }>;
68
+ get(id: string): Promise<{
69
+ id: string;
70
+ userId: string;
71
+ createdAt: string;
72
+ updatedAt: string;
73
+ sentence: string;
74
+ focusWord: string;
75
+ focusWordReading: string;
76
+ furigana: {
77
+ base: string;
78
+ reading: string;
79
+ }[];
80
+ english: string;
81
+ glosses: string[];
82
+ grammarNote: string | null;
83
+ kanjiList: {
84
+ kanji: string;
85
+ meaning: string;
86
+ wanikaniLevel: number | null;
87
+ }[];
88
+ imageKey: string | null;
89
+ audioKey: string | null;
90
+ source: string;
91
+ tags: string[];
92
+ }>;
93
+ update(id: string, input: UpdateCardInput): Promise<{
94
+ id: string;
95
+ userId: string;
96
+ createdAt: string;
97
+ updatedAt: string;
98
+ sentence: string;
99
+ focusWord: string;
100
+ focusWordReading: string;
101
+ furigana: {
102
+ base: string;
103
+ reading: string;
104
+ }[];
105
+ english: string;
106
+ glosses: string[];
107
+ grammarNote: string | null;
108
+ kanjiList: {
109
+ kanji: string;
110
+ meaning: string;
111
+ wanikaniLevel: number | null;
112
+ }[];
113
+ imageKey: string | null;
114
+ audioKey: string | null;
115
+ source: string;
116
+ tags: string[];
117
+ }>;
118
+ remove(id: string): Promise<void>;
119
+ };
120
+ reviews: {
121
+ due(query?: {
122
+ limit?: number;
123
+ before?: string;
124
+ }): Promise<{
125
+ items: {
126
+ card: {
127
+ id: string;
128
+ userId: string;
129
+ createdAt: string;
130
+ updatedAt: string;
131
+ sentence: string;
132
+ focusWord: string;
133
+ focusWordReading: string;
134
+ furigana: {
135
+ base: string;
136
+ reading: string;
137
+ }[];
138
+ english: string;
139
+ glosses: string[];
140
+ grammarNote: string | null;
141
+ kanjiList: {
142
+ kanji: string;
143
+ meaning: string;
144
+ wanikaniLevel: number | null;
145
+ }[];
146
+ imageKey: string | null;
147
+ audioKey: string | null;
148
+ source: string;
149
+ tags: string[];
150
+ };
151
+ cardState: {
152
+ cardId: string;
153
+ userId: string;
154
+ due: string;
155
+ stability: number;
156
+ difficulty: number;
157
+ elapsedDays: number;
158
+ scheduledDays: number;
159
+ reps: number;
160
+ lapses: number;
161
+ learningSteps: number;
162
+ state: "new" | "learning" | "review" | "relearning";
163
+ lastReview: string | null;
164
+ };
165
+ }[];
166
+ }>;
167
+ submit(input: SubmitReviewInput): Promise<{
168
+ review: {
169
+ id: string;
170
+ userId: string;
171
+ cardId: string;
172
+ rating: 1 | 4 | 2 | 3;
173
+ reviewedAt: string;
174
+ elapsedDays: number;
175
+ scheduledDays: number;
176
+ stateBefore: "new" | "learning" | "review" | "relearning";
177
+ stateAfter: "new" | "learning" | "review" | "relearning";
178
+ };
179
+ cardState: {
180
+ cardId: string;
181
+ userId: string;
182
+ due: string;
183
+ stability: number;
184
+ difficulty: number;
185
+ elapsedDays: number;
186
+ scheduledDays: number;
187
+ reps: number;
188
+ lapses: number;
189
+ learningSteps: number;
190
+ state: "new" | "learning" | "review" | "relearning";
191
+ lastReview: string | null;
192
+ };
193
+ }>;
194
+ };
195
+ stats: {
196
+ heatmap(query: HeatmapQuery): Promise<{
197
+ year: number;
198
+ days: {
199
+ date: string;
200
+ count: number;
201
+ }[];
202
+ }>;
203
+ retention(): Promise<{
204
+ generatedAt: string;
205
+ points: {
206
+ intervalDays: number;
207
+ retention: number;
208
+ sampleSize: number;
209
+ }[];
210
+ }>;
211
+ daily(query: DailyCountQuery): Promise<{
212
+ days: {
213
+ date: string;
214
+ reviews: number;
215
+ again: number;
216
+ hard: number;
217
+ good: number;
218
+ easy: number;
219
+ }[];
220
+ }>;
221
+ };
222
+ };
223
+ type HibiClient = ReturnType<typeof createHibiClient>;
224
+
225
+ export { type HibiClient, type HibiClientConfig, type HibiClientError, createHibiClient };
package/dist/index.js ADDED
@@ -0,0 +1,95 @@
1
+ import { PaginatedSchema, CardSchema, SubmitReviewResultSchema, DailyCountResponseSchema, HeatmapResponseSchema, SubmitReviewInputSchema, UpdateCardInputSchema, CreateCardInputSchema, RetentionResponseSchema } from '@hibi/types';
2
+ import { z } from 'zod';
3
+
4
+ // src/client.ts
5
+ var PaginatedCardSchema = PaginatedSchema(CardSchema);
6
+ var DueResponseSchema = z.object({
7
+ items: z.array(
8
+ z.object({ card: CardSchema, cardState: SubmitReviewResultSchema.shape.cardState })
9
+ )
10
+ });
11
+ function asError(status, body) {
12
+ const err = new Error(`Hibi API error: ${status}`);
13
+ err.status = status;
14
+ err.body = body;
15
+ return err;
16
+ }
17
+ function createHibiClient(config) {
18
+ const fetchImpl = config.fetch ?? fetch;
19
+ const base = config.baseUrl.replace(/\/+$/, "");
20
+ async function request(method, path, schema, init = {}) {
21
+ const url = new URL(`${base}${path}`);
22
+ if (init.query) {
23
+ for (const [k, v] of Object.entries(init.query)) {
24
+ if (v !== void 0) url.searchParams.set(k, String(v));
25
+ }
26
+ }
27
+ const headers = {
28
+ Authorization: `Bearer ${config.apiKey}`
29
+ };
30
+ const requestInit = { method, headers };
31
+ if (init.body !== void 0) {
32
+ headers["Content-Type"] = "application/json";
33
+ requestInit.body = JSON.stringify(init.body);
34
+ }
35
+ const res = await fetchImpl(url.toString(), requestInit);
36
+ if (res.status === 204) return void 0;
37
+ const text = await res.text();
38
+ const body = text ? JSON.parse(text) : null;
39
+ if (!res.ok) throw asError(res.status, body);
40
+ return schema.parse(body);
41
+ }
42
+ return {
43
+ cards: {
44
+ async create(input) {
45
+ const validated = CreateCardInputSchema.parse(input);
46
+ return request("POST", "/v1/cards", CardSchema, { body: validated });
47
+ },
48
+ async list(query = { limit: 50 }) {
49
+ return request("GET", "/v1/cards", PaginatedCardSchema, {
50
+ query: { limit: query.limit, cursor: query.cursor, tag: query.tag, source: query.source }
51
+ });
52
+ },
53
+ async get(id) {
54
+ return request("GET", `/v1/cards/${id}`, CardSchema);
55
+ },
56
+ async update(id, input) {
57
+ const validated = UpdateCardInputSchema.parse(input);
58
+ return request("PATCH", `/v1/cards/${id}`, CardSchema, { body: validated });
59
+ },
60
+ async remove(id) {
61
+ await request("DELETE", `/v1/cards/${id}`, z.unknown());
62
+ }
63
+ },
64
+ reviews: {
65
+ async due(query = {}) {
66
+ return request("GET", "/v1/reviews/due", DueResponseSchema, {
67
+ query: { limit: query.limit, before: query.before }
68
+ });
69
+ },
70
+ async submit(input) {
71
+ const validated = SubmitReviewInputSchema.parse(input);
72
+ return request("POST", "/v1/reviews", SubmitReviewResultSchema, { body: validated });
73
+ }
74
+ },
75
+ stats: {
76
+ async heatmap(query) {
77
+ return request("GET", "/v1/stats/heatmap", HeatmapResponseSchema, {
78
+ query: { year: query.year }
79
+ });
80
+ },
81
+ async retention() {
82
+ return request("GET", "/v1/stats/retention", RetentionResponseSchema);
83
+ },
84
+ async daily(query) {
85
+ return request("GET", "/v1/stats/daily", DailyCountResponseSchema, {
86
+ query: { from: query.from, to: query.to }
87
+ });
88
+ }
89
+ }
90
+ };
91
+ }
92
+
93
+ export { createHibiClient };
94
+ //# sourceMappingURL=index.js.map
95
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import {\n CardSchema,\n type CreateCardInput,\n CreateCardInputSchema,\n type DailyCountQuery,\n DailyCountResponseSchema,\n type HeatmapQuery,\n HeatmapResponseSchema,\n type ListCardsQuery,\n PaginatedSchema,\n RetentionResponseSchema,\n type SubmitReviewInput,\n SubmitReviewInputSchema,\n SubmitReviewResultSchema,\n type UpdateCardInput,\n UpdateCardInputSchema,\n} from \"@hibi/types\";\nimport { z } from \"zod\";\n\nexport interface HibiClientConfig {\n apiKey: string;\n baseUrl: string;\n fetch?: typeof fetch;\n}\n\nexport interface HibiClientError extends Error {\n status: number;\n body: unknown;\n}\n\nconst PaginatedCardSchema = PaginatedSchema(CardSchema);\nconst DueResponseSchema = z.object({\n items: z.array(\n z.object({ card: CardSchema, cardState: SubmitReviewResultSchema.shape.cardState }),\n ),\n});\n\nfunction asError(status: number, body: unknown): HibiClientError {\n const err = new Error(`Hibi API error: ${status}`) as HibiClientError;\n err.status = status;\n err.body = body;\n return err;\n}\n\nexport function createHibiClient(config: HibiClientConfig) {\n const fetchImpl = config.fetch ?? fetch;\n const base = config.baseUrl.replace(/\\/+$/, \"\");\n\n async function request<T>(\n method: string,\n path: string,\n schema: z.ZodType<T>,\n init: { body?: unknown; query?: Record<string, string | number | undefined> } = {},\n ): Promise<T> {\n const url = new URL(`${base}${path}`);\n if (init.query) {\n for (const [k, v] of Object.entries(init.query)) {\n if (v !== undefined) url.searchParams.set(k, String(v));\n }\n }\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${config.apiKey}`,\n };\n const requestInit: RequestInit = { method, headers };\n if (init.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n requestInit.body = JSON.stringify(init.body);\n }\n\n const res = await fetchImpl(url.toString(), requestInit);\n\n if (res.status === 204) return undefined as T;\n\n const text = await res.text();\n const body = text ? JSON.parse(text) : null;\n\n if (!res.ok) throw asError(res.status, body);\n return schema.parse(body);\n }\n\n return {\n cards: {\n async create(input: CreateCardInput) {\n const validated = CreateCardInputSchema.parse(input);\n return request(\"POST\", \"/v1/cards\", CardSchema, { body: validated });\n },\n async list(query: ListCardsQuery = { limit: 50 }) {\n return request(\"GET\", \"/v1/cards\", PaginatedCardSchema, {\n query: { limit: query.limit, cursor: query.cursor, tag: query.tag, source: query.source },\n });\n },\n async get(id: string) {\n return request(\"GET\", `/v1/cards/${id}`, CardSchema);\n },\n async update(id: string, input: UpdateCardInput) {\n const validated = UpdateCardInputSchema.parse(input);\n return request(\"PATCH\", `/v1/cards/${id}`, CardSchema, { body: validated });\n },\n async remove(id: string): Promise<void> {\n await request(\"DELETE\", `/v1/cards/${id}`, z.unknown());\n },\n },\n\n reviews: {\n async due(query: { limit?: number; before?: string } = {}) {\n return request(\"GET\", \"/v1/reviews/due\", DueResponseSchema, {\n query: { limit: query.limit, before: query.before },\n });\n },\n async submit(input: SubmitReviewInput) {\n const validated = SubmitReviewInputSchema.parse(input);\n return request(\"POST\", \"/v1/reviews\", SubmitReviewResultSchema, { body: validated });\n },\n },\n\n stats: {\n async heatmap(query: HeatmapQuery) {\n return request(\"GET\", \"/v1/stats/heatmap\", HeatmapResponseSchema, {\n query: { year: query.year },\n });\n },\n async retention() {\n return request(\"GET\", \"/v1/stats/retention\", RetentionResponseSchema);\n },\n async daily(query: DailyCountQuery) {\n return request(\"GET\", \"/v1/stats/daily\", DailyCountResponseSchema, {\n query: { from: query.from, to: query.to },\n });\n },\n },\n };\n}\n\nexport type HibiClient = ReturnType<typeof createHibiClient>;\n"]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "hibi-client",
3
+ "version": "0.0.0",
4
+ "description": "Official TypeScript client for the Hibi flashcard API.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public",
23
+ "registry": "https://registry.npmjs.org/"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/YannickHerrero/hibi.git",
28
+ "directory": "packages/api-client"
29
+ },
30
+ "homepage": "https://github.com/YannickHerrero/hibi/tree/master/packages/api-client",
31
+ "bugs": "https://github.com/YannickHerrero/hibi/issues",
32
+ "keywords": [
33
+ "hibi",
34
+ "srs",
35
+ "anki",
36
+ "flashcards",
37
+ "japanese",
38
+ "fsrs",
39
+ "sentence-mining"
40
+ ],
41
+ "author": "yannickhrr",
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "dev": "tsup --watch",
45
+ "typecheck": "tsc --noEmit",
46
+ "test": "vitest run --passWithNoTests"
47
+ },
48
+ "dependencies": {
49
+ "@hibi/types": "workspace:*",
50
+ "zod": "4.4.3"
51
+ },
52
+ "devDependencies": {
53
+ "tsup": "8.5.1",
54
+ "typescript": "6.0.3",
55
+ "vitest": "4.1.5"
56
+ }
57
+ }