@jukasdrj/bookstrack-api-client 1.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,374 @@
1
+ # @bookstrack/api-client
2
+
3
+ **Official TypeScript SDK for BooksTrack API**
4
+
5
+ Auto-generated from OpenAPI specification using `openapi-typescript` + `openapi-fetch`.
6
+
7
+ ## Features
8
+
9
+ - **Type-Safe** - Full TypeScript support with auto-generated types
10
+ - **Lightweight** - ~2KB gzipped client (tree-shakable)
11
+ - **Modern** - Uses native `fetch` API (works in browser, Node.js, Cloudflare Workers)
12
+ - **Auto-Generated** - Always in sync with API contract via OpenAPI spec
13
+
14
+ ---
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @bookstrack/api-client
20
+ ```
21
+
22
+ **Note:** This package is published to GitHub Packages. Ensure your `.npmrc` is configured:
23
+
24
+ ```
25
+ @bookstrack:registry=https://npm.pkg.github.com
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Quick Start
31
+
32
+ ### Basic Usage
33
+
34
+ ```typescript
35
+ import { createBooksTrackClient } from '@bookstrack/api-client'
36
+
37
+ const client = createBooksTrackClient({
38
+ baseUrl: 'https://api.oooefam.net'
39
+ })
40
+
41
+ // Search by ISBN
42
+ const { data, error } = await client.GET('/v1/search/isbn', {
43
+ params: { query: { isbn: '9780439708180' } }
44
+ })
45
+
46
+ if (error) {
47
+ console.error('API Error:', error)
48
+ } else {
49
+ console.log('Book:', data.data)
50
+ }
51
+ ```
52
+
53
+ ### Advanced Usage
54
+
55
+ #### Custom Headers (Authentication)
56
+
57
+ ```typescript
58
+ const client = createBooksTrackClient({
59
+ baseUrl: 'https://api.oooefam.net',
60
+ headers: {
61
+ 'Authorization': 'Bearer YOUR_TOKEN'
62
+ }
63
+ })
64
+ ```
65
+
66
+ #### POST Requests (Batch Enrichment)
67
+
68
+ ```typescript
69
+ const { data, error } = await client.POST('/v1/enrich/batch', {
70
+ body: {
71
+ workIds: ['OL123W', 'OL456W'],
72
+ force: false
73
+ }
74
+ })
75
+
76
+ if (error) {
77
+ console.error('Failed to enrich:', error)
78
+ } else {
79
+ console.log('Job ID:', data.data.jobId)
80
+ }
81
+ ```
82
+
83
+ #### WebSocket Progress Tracking
84
+
85
+ ```typescript
86
+ // Start batch job
87
+ const { data: job } = await client.POST('/v1/enrich/batch', {
88
+ body: { workIds: [...] }
89
+ })
90
+
91
+ const jobId = job.data.jobId
92
+
93
+ // Connect to WebSocket
94
+ const ws = new WebSocket(`wss://api.oooefam.net/ws/progress?jobId=${jobId}`)
95
+
96
+ ws.onmessage = (event) => {
97
+ const progress = JSON.parse(event.data)
98
+ console.log(`Progress: ${progress.progress * 100}%`)
99
+ }
100
+ ```
101
+
102
+ #### Polling Job Status (Fallback)
103
+
104
+ ```typescript
105
+ const { data } = await client.GET('/v1/jobs/{jobId}/status', {
106
+ params: { path: { jobId: 'job-uuid' } }
107
+ })
108
+
109
+ console.log('Job Status:', data.data.status)
110
+ console.log('Progress:', data.data.progress)
111
+ ```
112
+
113
+ ---
114
+
115
+ ## API Reference
116
+
117
+ ### Client Creation
118
+
119
+ ```typescript
120
+ createBooksTrackClient(options?: {
121
+ baseUrl?: string
122
+ headers?: HeadersInit
123
+ credentials?: RequestCredentials
124
+ })
125
+ ```
126
+
127
+ ### Available Endpoints
128
+
129
+ All endpoints are fully typed. Use TypeScript autocomplete to explore:
130
+
131
+ - `GET /health` - Health check
132
+ - `GET /v1/search/isbn` - Search by ISBN
133
+ - `GET /v1/search/title` - Search by title
134
+ - `POST /v1/enrich/batch` - Batch enrichment
135
+ - `POST /v2/import/workflow` - CSV import workflow
136
+ - `GET /v1/jobs/{jobId}/status` - Job status polling
137
+ - `GET /ws/progress` - WebSocket progress (upgrade)
138
+
139
+ ### Response Format
140
+
141
+ All API responses follow the canonical `ResponseEnvelope` format:
142
+
143
+ **Success:**
144
+ ```typescript
145
+ {
146
+ success: true,
147
+ data: { /* canonical book object */ },
148
+ metadata: {
149
+ source: 'google_books',
150
+ cached: true,
151
+ timestamp: '2025-01-10T12:00:00Z'
152
+ }
153
+ }
154
+ ```
155
+
156
+ **Error:**
157
+ ```typescript
158
+ {
159
+ success: false,
160
+ error: {
161
+ code: 'RATE_LIMIT_EXCEEDED',
162
+ message: 'Too many requests',
163
+ statusCode: 429,
164
+ retryable: true,
165
+ retryAfterMs: 60000
166
+ }
167
+ }
168
+ ```
169
+
170
+ ---
171
+
172
+ ## Error Handling
173
+
174
+ ### Circuit Breaker Errors
175
+
176
+ The API uses circuit breakers for external providers. Handle these gracefully:
177
+
178
+ ```typescript
179
+ const { data, error } = await client.GET('/v1/search/isbn', {
180
+ params: { query: { isbn: '...' } }
181
+ })
182
+
183
+ if (error) {
184
+ if (error.code === 'CIRCUIT_OPEN') {
185
+ // Provider is temporarily unavailable
186
+ console.warn('Provider down, try again in 60s')
187
+ } else if (error.retryable) {
188
+ // Safe to retry after retryAfterMs
189
+ setTimeout(() => retry(), error.retryAfterMs)
190
+ }
191
+ }
192
+ ```
193
+
194
+ ### Common Error Codes
195
+
196
+ - `MISSING_ISBN` - Required parameter missing
197
+ - `RATE_LIMIT_EXCEEDED` - Too many requests
198
+ - `CIRCUIT_OPEN` - External provider circuit breaker open
199
+ - `NOT_FOUND` - Book not found
200
+ - `API_ERROR` - External API failure
201
+ - `INTERNAL_ERROR` - Server error
202
+
203
+ ---
204
+
205
+ ## Development
206
+
207
+ ### Generating Types
208
+
209
+ The SDK is auto-generated from `docs/openapi.yaml`:
210
+
211
+ ```bash
212
+ npm run generate
213
+ ```
214
+
215
+ This creates `src/schema.ts` with all API types.
216
+
217
+ ### Building
218
+
219
+ ```bash
220
+ npm run build
221
+ ```
222
+
223
+ Output: `dist/index.js` and `dist/index.d.ts`
224
+
225
+ ### Publishing (Automated via CI/CD)
226
+
227
+ Publishing is handled automatically by GitHub Actions when:
228
+ - Pushing to `main` branch
229
+ - Creating a new release/tag
230
+
231
+ Manual publish:
232
+ ```bash
233
+ npm run prepublishOnly
234
+ npm publish
235
+ ```
236
+
237
+ ---
238
+
239
+ ## Framework Examples
240
+
241
+ ### React (with React Query)
242
+
243
+ ```typescript
244
+ import { useQuery } from '@tanstack/react-query'
245
+ import { client } from '@bookstrack/api-client'
246
+
247
+ function BookSearch({ isbn }: { isbn: string }) {
248
+ const { data, error, isLoading } = useQuery({
249
+ queryKey: ['book', isbn],
250
+ queryFn: async () => {
251
+ const res = await client.GET('/v1/search/isbn', {
252
+ params: { query: { isbn } }
253
+ })
254
+ if (res.error) throw new Error(res.error.message)
255
+ return res.data.data
256
+ }
257
+ })
258
+
259
+ if (isLoading) return <div>Loading...</div>
260
+ if (error) return <div>Error: {error.message}</div>
261
+
262
+ return <div>{data?.title}</div>
263
+ }
264
+ ```
265
+
266
+ ### Vue 3 (with Composition API)
267
+
268
+ ```typescript
269
+ import { ref } from 'vue'
270
+ import { client } from '@bookstrack/api-client'
271
+
272
+ export function useBookSearch(isbn: string) {
273
+ const book = ref(null)
274
+ const error = ref(null)
275
+ const loading = ref(false)
276
+
277
+ async function search() {
278
+ loading.value = true
279
+ const res = await client.GET('/v1/search/isbn', {
280
+ params: { query: { isbn } }
281
+ })
282
+
283
+ if (res.error) {
284
+ error.value = res.error
285
+ } else {
286
+ book.value = res.data.data
287
+ }
288
+ loading.value = false
289
+ }
290
+
291
+ return { book, error, loading, search }
292
+ }
293
+ ```
294
+
295
+ ### Svelte
296
+
297
+ ```typescript
298
+ import { writable } from 'svelte/store'
299
+ import { client } from '@bookstrack/api-client'
300
+
301
+ export function createBookStore() {
302
+ const { subscribe, set, update } = writable({
303
+ book: null,
304
+ loading: false,
305
+ error: null
306
+ })
307
+
308
+ async function searchByISBN(isbn: string) {
309
+ update(s => ({ ...s, loading: true }))
310
+
311
+ const { data, error } = await client.GET('/v1/search/isbn', {
312
+ params: { query: { isbn } }
313
+ })
314
+
315
+ if (error) {
316
+ set({ book: null, loading: false, error })
317
+ } else {
318
+ set({ book: data.data, loading: false, error: null })
319
+ }
320
+ }
321
+
322
+ return { subscribe, searchByISBN }
323
+ }
324
+ ```
325
+
326
+ ---
327
+
328
+ ## Migration from Legacy API
329
+
330
+ If you're migrating from the old `/search/*` endpoints (deprecated March 1, 2026):
331
+
332
+ ### Before (Legacy)
333
+
334
+ ```typescript
335
+ const res = await fetch('https://api.oooefam.net/search/isbn?isbn=123')
336
+ const book = await res.json()
337
+ ```
338
+
339
+ ### After (SDK)
340
+
341
+ ```typescript
342
+ import { client } from '@bookstrack/api-client'
343
+
344
+ const { data } = await client.GET('/v1/search/isbn', {
345
+ params: { query: { isbn: '123' } }
346
+ })
347
+
348
+ const book = data.data
349
+ ```
350
+
351
+ **Key Changes:**
352
+ - All responses now use `ResponseEnvelope` format
353
+ - Success/error discriminator via `success` field
354
+ - Metadata includes source, cache status, timestamp
355
+ - Error responses include structured error codes
356
+
357
+ ---
358
+
359
+ ## Support
360
+
361
+ - **Documentation:** https://github.com/yourusername/bendv3/tree/main/docs
362
+ - **API Contract:** https://github.com/yourusername/bendv3/blob/main/docs/API_CONTRACT.md
363
+ - **Issues:** https://github.com/yourusername/bendv3/issues
364
+
365
+ ---
366
+
367
+ ## License
368
+
369
+ MIT
370
+
371
+ ---
372
+
373
+ **Generated from OpenAPI Spec Version:** (auto-updated on publish)
374
+ **Last Updated:** 2025-11-28
@@ -0,0 +1,45 @@
1
+ import type { paths } from './schema';
2
+ export type { paths, components } from './schema';
3
+ /**
4
+ * Create a type-safe BooksTrack API client
5
+ *
6
+ * @param baseUrl - API base URL (default: https://api.oooefam.net)
7
+ * @param options - Additional fetch options (headers, credentials, etc.)
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { createBooksTrackClient } from '@bookstrack/api-client'
12
+ *
13
+ * const client = createBooksTrackClient({
14
+ * baseUrl: 'https://api.oooefam.net'
15
+ * })
16
+ *
17
+ * // Type-safe API calls
18
+ * const { data, error } = await client.GET('/v1/search/isbn', {
19
+ * params: { query: { isbn: '9780439708180' } }
20
+ * })
21
+ *
22
+ * if (error) {
23
+ * console.error('API Error:', error)
24
+ * } else {
25
+ * console.log('Book:', data.data)
26
+ * }
27
+ * ```
28
+ */
29
+ export declare function createBooksTrackClient(options?: {
30
+ baseUrl?: string;
31
+ headers?: HeadersInit;
32
+ credentials?: RequestCredentials;
33
+ }): import("openapi-fetch").Client<paths, `${string}/${string}`>;
34
+ /**
35
+ * Default client instance for convenience
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * import { client } from '@bookstrack/api-client'
40
+ *
41
+ * const { data } = await client.GET('/health')
42
+ * ```
43
+ */
44
+ export declare const client: import("openapi-fetch").Client<paths, `${string}/${string}`>;
45
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AAErC,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,WAAW,CAAC,EAAE,kBAAkB,CAAA;CACjC,gEAWA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,MAAM,8DAA2B,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,49 @@
1
+ import createClient from 'openapi-fetch';
2
+ /**
3
+ * Create a type-safe BooksTrack API client
4
+ *
5
+ * @param baseUrl - API base URL (default: https://api.oooefam.net)
6
+ * @param options - Additional fetch options (headers, credentials, etc.)
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { createBooksTrackClient } from '@bookstrack/api-client'
11
+ *
12
+ * const client = createBooksTrackClient({
13
+ * baseUrl: 'https://api.oooefam.net'
14
+ * })
15
+ *
16
+ * // Type-safe API calls
17
+ * const { data, error } = await client.GET('/v1/search/isbn', {
18
+ * params: { query: { isbn: '9780439708180' } }
19
+ * })
20
+ *
21
+ * if (error) {
22
+ * console.error('API Error:', error)
23
+ * } else {
24
+ * console.log('Book:', data.data)
25
+ * }
26
+ * ```
27
+ */
28
+ export function createBooksTrackClient(options) {
29
+ const baseUrl = options?.baseUrl || 'https://api.oooefam.net';
30
+ return createClient({
31
+ baseUrl,
32
+ headers: {
33
+ 'Content-Type': 'application/json',
34
+ ...options?.headers
35
+ },
36
+ credentials: options?.credentials
37
+ });
38
+ }
39
+ /**
40
+ * Default client instance for convenience
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * import { client } from '@bookstrack/api-client'
45
+ *
46
+ * const { data } = await client.GET('/health')
47
+ * ```
48
+ */
49
+ export const client = createBooksTrackClient();