@ord-api/ord-api-types 1.0.2

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 (3) hide show
  1. package/README.md +459 -0
  2. package/package.json +24 -0
  3. package/types.ts +3950 -0
package/README.md ADDED
@@ -0,0 +1,459 @@
1
+ # @ord-api/ord-api-types
2
+
3
+ TypeScript types for the ORD API, automatically generated from the OpenAPI specification.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # pnpm (recommended for SvelteKit)
9
+ pnpm add @ord-api/ord-api-types
10
+
11
+ # npm
12
+ npm install @ord-api/ord-api-types
13
+
14
+ # yarn
15
+ yarn add @ord-api/ord-api-types
16
+ ```
17
+
18
+ ## Setup for SvelteKit
19
+
20
+ ### 1. Create Axios Instance
21
+
22
+ ```typescript
23
+ // src/lib/api/client.ts
24
+ import axios from 'axios';
25
+ import { browser } from '$app/environment';
26
+
27
+ export const api = axios.create({
28
+ baseURL: browser ? '' : 'http://localhost:8080', // Use proxy in browser, direct in SSR
29
+ withCredentials: true, // Important for JWT cookies
30
+ });
31
+
32
+ // Optional: Add request/response interceptors
33
+ api.interceptors.response.use(
34
+ (response) => response,
35
+ (error) => {
36
+ if (error.response?.status === 401) {
37
+ // Handle unauthorized
38
+ goto('/login');
39
+ }
40
+ return Promise.reject(error);
41
+ }
42
+ );
43
+ ```
44
+
45
+ ### 2. Configure SvelteKit Proxy (Optional)
46
+
47
+ ```typescript
48
+ // vite.config.ts
49
+ import { sveltekit } from '@sveltejs/kit/vite';
50
+ import { defineConfig } from 'vite';
51
+
52
+ export default defineConfig({
53
+ plugins: [sveltekit()],
54
+ server: {
55
+ proxy: {
56
+ '/api': {
57
+ target: 'http://localhost:8080',
58
+ changeOrigin: true,
59
+ },
60
+ },
61
+ },
62
+ });
63
+ ```
64
+
65
+ ### 3. Export Common Types
66
+
67
+ ```typescript
68
+ // src/lib/types/api-types.ts
69
+ import type { components } from '@ord-api/ord-api-types';
70
+
71
+ // Export enums
72
+ export type LanguageName = components['schemas']['LanguageName'];
73
+ export type WordType = components['schemas']['WordType'];
74
+ export type WordExtraMark = components['schemas']['WordExtraMark'];
75
+ export type WordToggleableProperty = components['schemas']['WordToggleableProperty'];
76
+
77
+ // Export DTOs
78
+ export type UserDTO = components['schemas']['UserDTO'];
79
+ export type WordDTO = components['schemas']['WordDTO'];
80
+ export type QuicklyAddedWordDTO = components['schemas']['QuicklyAddedWordDTO'];
81
+ export type CreateQAWRequest = components['schemas']['CreateQAWRequest'];
82
+ export type PaginatedDataResponse<T> = components['schemas']['PaginatedDataResponse'] & {
83
+ data: T[];
84
+ };
85
+ ```
86
+
87
+ ## Usage with TanStack Query (Svelte)
88
+
89
+ ### Setup Query Client
90
+
91
+ ```typescript
92
+ // src/routes/+layout.ts
93
+ import { browser } from '$app/environment';
94
+ import { QueryClient } from '@tanstack/svelte-query';
95
+
96
+ export const load = async () => {
97
+ const queryClient = new QueryClient({
98
+ defaultOptions: {
99
+ queries: {
100
+ enabled: browser,
101
+ staleTime: 60 * 1000, // 1 minute
102
+ },
103
+ },
104
+ });
105
+
106
+ return { queryClient };
107
+ };
108
+ ```
109
+
110
+ ```svelte
111
+ <!-- src/routes/+layout.svelte -->
112
+ <script lang="ts">
113
+ import { QueryClientProvider } from '@tanstack/svelte-query';
114
+
115
+ let { data, children } = $props();
116
+ </script>
117
+
118
+ <QueryClientProvider client={data.queryClient}>
119
+ {@render children()}
120
+ </QueryClientProvider>
121
+ ```
122
+
123
+ ### Create Query Functions
124
+
125
+ ```typescript
126
+ // src/lib/api/queries/words.ts
127
+ import { createQuery, createMutation } from '@tanstack/svelte-query';
128
+ import { api } from '$lib/api/client';
129
+ import type { QuicklyAddedWordDTO, CreateQAWRequest, PaginatedDataResponse } from '$lib/types/api-types';
130
+
131
+ export const createQuicklyAddedWordsQuery = (page = 0, perPage = 20) => {
132
+ return createQuery({
133
+ queryKey: ['quickly-added-words', page, perPage],
134
+ queryFn: async () => {
135
+ const response = await api.get<PaginatedDataResponse<QuicklyAddedWordDTO>>(
136
+ '/api/v1/quickly-added-words/',
137
+ { params: { page, perPage } }
138
+ );
139
+ return response.data;
140
+ },
141
+ });
142
+ };
143
+
144
+ export const createCreateQAWMutation = () => {
145
+ return createMutation({
146
+ mutationFn: async (word: CreateQAWRequest) => {
147
+ const response = await api.post<QuicklyAddedWordDTO>(
148
+ '/api/v1/quickly-added-words/',
149
+ word
150
+ );
151
+ return response.data;
152
+ },
153
+ });
154
+ };
155
+
156
+ export const createDeleteQAWMutation = () => {
157
+ return createMutation({
158
+ mutationFn: async (id: string) => {
159
+ await api.delete(`/api/v1/quickly-added-words/${id}`);
160
+ },
161
+ });
162
+ };
163
+ ```
164
+
165
+ ### Use in Svelte 5 Components
166
+
167
+ ```svelte
168
+ <!-- src/routes/words/+page.svelte -->
169
+ <script lang="ts">
170
+ import { createQuicklyAddedWordsQuery, createCreateQAWMutation } from '$lib/api/queries/words';
171
+ import type { LanguageName } from '$lib/types/api-types';
172
+
173
+ let page = $state(0);
174
+ let perPage = $state(20);
175
+
176
+ // Query
177
+ const wordsQuery = createQuicklyAddedWordsQuery(page, perPage);
178
+ const words = $derived($wordsQuery.data?.data ?? []);
179
+ const pagination = $derived($wordsQuery.data?.pagination);
180
+
181
+ // Mutation
182
+ const createWordMutation = createCreateQAWMutation();
183
+
184
+ async function handleCreateWord(word: string, language: LanguageName) {
185
+ await $createWordMutation.mutateAsync({
186
+ word,
187
+ language,
188
+ });
189
+
190
+ // Invalidate and refetch
191
+ $wordsQuery.refetch();
192
+ }
193
+ </script>
194
+
195
+ {#if $wordsQuery.isPending}
196
+ <p>Loading...</p>
197
+ {:else if $wordsQuery.isError}
198
+ <p>Error: {$wordsQuery.error.message}</p>
199
+ {:else}
200
+ <div>
201
+ <h1>Words ({pagination?.totalResults ?? 0})</h1>
202
+
203
+ {#each words as word (word.id)}
204
+ <div>
205
+ <h3>{word.word}</h3>
206
+ <p>{word.language}</p>
207
+ </div>
208
+ {/each}
209
+
210
+ <!-- Pagination -->
211
+ {#if pagination}
212
+ <button
213
+ disabled={page === 0}
214
+ onclick={() => page--}
215
+ >
216
+ Previous
217
+ </button>
218
+ <span>Page {page + 1} of {pagination.totalPages}</span>
219
+ <button
220
+ disabled={page >= pagination.totalPages - 1}
221
+ onclick={() => page++}
222
+ >
223
+ Next
224
+ </button>
225
+ {/if}
226
+ </div>
227
+ {/if}
228
+ ```
229
+
230
+ ### Authentication Flow
231
+
232
+ ```typescript
233
+ // src/lib/api/queries/auth.ts
234
+ import { createMutation } from '@tanstack/svelte-query';
235
+ import { api } from '$lib/api/client';
236
+ import type { components, paths } from '@ord-api/ord-api-types';
237
+
238
+ type OtpRequestBody = paths['/api/v1/auth/otp-request']['post']['requestBody']['content']['application/json'];
239
+ type OtpVerifyBody = paths['/api/v1/auth/otp-verify']['post']['requestBody']['content']['application/json'];
240
+ type UserDTO = components['schemas']['UserDTO'];
241
+
242
+ export const createRequestOtpMutation = () => {
243
+ return createMutation({
244
+ mutationFn: async (body: OtpRequestBody) => {
245
+ await api.post('/api/v1/auth/otp-request', body);
246
+ },
247
+ });
248
+ };
249
+
250
+ export const createVerifyOtpMutation = () => {
251
+ return createMutation({
252
+ mutationFn: async (body: OtpVerifyBody) => {
253
+ const response = await api.post('/api/v1/auth/otp-verify', body);
254
+ return response.data;
255
+ },
256
+ });
257
+ };
258
+
259
+ export const createLogoutMutation = () => {
260
+ return createMutation({
261
+ mutationFn: async () => {
262
+ await api.delete('/api/v1/auth/logout');
263
+ },
264
+ });
265
+ };
266
+
267
+ export const createCurrentUserQuery = () => {
268
+ return createQuery({
269
+ queryKey: ['user', 'me'],
270
+ queryFn: async () => {
271
+ const response = await api.get<UserDTO>('/api/v1/users/me');
272
+ return response.data;
273
+ },
274
+ });
275
+ };
276
+ ```
277
+
278
+ ```svelte
279
+ <!-- src/routes/login/+page.svelte -->
280
+ <script lang="ts">
281
+ import { goto } from '$app/navigation';
282
+ import { createRequestOtpMutation, createVerifyOtpMutation } from '$lib/api/queries/auth';
283
+
284
+ let email = $state('');
285
+ let code = $state('');
286
+ let step = $state<'email' | 'code'>('email');
287
+
288
+ const requestOtpMutation = createRequestOtpMutation();
289
+ const verifyOtpMutation = createVerifyOtpMutation();
290
+
291
+ async function handleRequestOtp() {
292
+ await $requestOtpMutation.mutateAsync({ email });
293
+ step = 'code';
294
+ }
295
+
296
+ async function handleVerifyOtp() {
297
+ await $verifyOtpMutation.mutateAsync({ email, code });
298
+ goto('/dashboard');
299
+ }
300
+ </script>
301
+
302
+ {#if step === 'email'}
303
+ <form onsubmit={handleRequestOtp}>
304
+ <input
305
+ type="email"
306
+ bind:value={email}
307
+ placeholder="Enter your email"
308
+ required
309
+ />
310
+ <button
311
+ type="submit"
312
+ disabled={$requestOtpMutation.isPending}
313
+ >
314
+ {$requestOtpMutation.isPending ? 'Sending...' : 'Send OTP'}
315
+ </button>
316
+ </form>
317
+ {:else}
318
+ <form onsubmit={handleVerifyOtp}>
319
+ <input
320
+ type="text"
321
+ bind:value={code}
322
+ placeholder="Enter 6-digit code"
323
+ required
324
+ />
325
+ <button
326
+ type="submit"
327
+ disabled={$verifyOtpMutation.isPending}
328
+ >
329
+ {$verifyOtpMutation.isPending ? 'Verifying...' : 'Verify'}
330
+ </button>
331
+ </form>
332
+ {/if}
333
+ ```
334
+
335
+ ### Server Load Functions with Types
336
+
337
+ ```typescript
338
+ // src/routes/words/[id]/+page.ts
339
+ import type { PageLoad } from './$types';
340
+ import type { components } from '@ord-api/ord-api-types';
341
+ import { api } from '$lib/api/client';
342
+
343
+ type WordDTO = components['schemas']['WordDTO'];
344
+
345
+ export const load: PageLoad = async ({ params }) => {
346
+ const response = await api.get<WordDTO>(`/api/v1/words/${params.id}`);
347
+
348
+ return {
349
+ word: response.data,
350
+ };
351
+ };
352
+ ```
353
+
354
+ ```svelte
355
+ <!-- src/routes/words/[id]/+page.svelte -->
356
+ <script lang="ts">
357
+ let { data } = $props();
358
+ </script>
359
+
360
+ <h1>{data.word.word}</h1>
361
+ <p>Language: {data.word.language}</p>
362
+ <p>Type: {data.word.type ?? 'Not specified'}</p>
363
+ ```
364
+
365
+ ## Advanced Patterns
366
+
367
+ ### Type-Safe API Wrapper
368
+
369
+ ```typescript
370
+ // src/lib/api/wrapper.ts
371
+ import type { paths } from '@ord-api/ord-api-types';
372
+ import { api } from './client';
373
+
374
+ type ApiPath = keyof paths;
375
+ type ApiMethod = 'get' | 'post' | 'patch' | 'delete';
376
+
377
+ type RequestBody<Path extends ApiPath, Method extends ApiMethod> =
378
+ paths[Path][Method] extends { requestBody: { content: { 'application/json': infer Body } } }
379
+ ? Body
380
+ : never;
381
+
382
+ type ResponseData<Path extends ApiPath, Method extends ApiMethod> =
383
+ paths[Path][Method] extends { responses: { 200: { content: { 'application/json': infer Data } } } }
384
+ ? Data
385
+ : never;
386
+
387
+ export async function apiCall<Path extends ApiPath, Method extends ApiMethod>(
388
+ method: Method,
389
+ path: Path,
390
+ body?: RequestBody<Path, Method>
391
+ ): Promise<ResponseData<Path, Method>> {
392
+ const response = await api.request({
393
+ method,
394
+ url: path as string,
395
+ data: body,
396
+ });
397
+ return response.data;
398
+ }
399
+
400
+ // Usage
401
+ const user = await apiCall('get', '/api/v1/users/me');
402
+ const word = await apiCall('post', '/api/v1/words/', { word: 'test', language: 'ENGLISH' });
403
+ ```
404
+
405
+ ### Form Actions with Types
406
+
407
+ ```typescript
408
+ // src/routes/words/create/+page.server.ts
409
+ import type { Actions } from './$types';
410
+ import type { CreateQAWRequest } from '$lib/types/api-types';
411
+ import { api } from '$lib/api/client';
412
+ import { fail } from '@sveltejs/kit';
413
+
414
+ export const actions = {
415
+ default: async ({ request }) => {
416
+ const data = await request.formData();
417
+
418
+ const wordData: CreateQAWRequest = {
419
+ word: data.get('word') as string,
420
+ language: data.get('language') as any,
421
+ definition: data.get('definition') as string || undefined,
422
+ };
423
+
424
+ try {
425
+ await api.post('/api/v1/quickly-added-words/', wordData);
426
+ return { success: true };
427
+ } catch (error) {
428
+ return fail(400, { error: 'Failed to create word' });
429
+ }
430
+ },
431
+ } satisfies Actions;
432
+ ```
433
+
434
+ ## Best Practices
435
+
436
+ 1. **Use `$derived`** for computed values from queries
437
+ 2. **Use `$state`** for local component state
438
+ 3. **Export query factories** instead of hooks (Svelte pattern)
439
+ 4. **Keep types in a central location** (`src/lib/types/api-types.ts`)
440
+ 5. **Use SvelteKit's proxy** for API calls in development
441
+ 6. **Handle SSR vs CSR** with `browser` check from `$app/environment`
442
+
443
+ ## Updating
444
+
445
+ This package is automatically published when the backend API changes. To update:
446
+
447
+ ```bash
448
+ pnpm update @ord-api/ord-api-types
449
+ ```
450
+
451
+ ## Resources
452
+
453
+ - [TanStack Query Svelte Docs](https://tanstack.com/query/latest/docs/svelte/overview)
454
+ - [SvelteKit Docs](https://kit.svelte.dev/)
455
+ - [Svelte 5 Runes](https://svelte-5-preview.vercel.app/docs/runes)
456
+
457
+ ## License
458
+
459
+ MIT
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@ord-api/ord-api-types",
3
+ "version": "1.0.2",
4
+ "description": "TypeScript types for ORD API - Auto-generated from OpenAPI specification",
5
+ "main": "types.ts",
6
+ "types": "types.ts",
7
+ "files": [
8
+ "types.ts",
9
+ "README.md"
10
+ ],
11
+ "author": "ORD API Team",
12
+ "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/Kacper-Ksiazek/ord-api.git"
16
+ },
17
+ "homepage": "https://github.com/Kacper-Ksiazek/ord-api#readme",
18
+ "bugs": {
19
+ "url": "https://github.com/Kacper-Ksiazek/ord-api/issues"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ }
24
+ }