@pfdev/api-types 3.0.0 → 3.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 (4) hide show
  1. package/README.md +143 -62
  2. package/index.ts +1 -1
  3. package/package.json +5 -2
  4. package/v3.ts +57 -37
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @pfdev/api-types
2
2
 
3
- TypeScript types for PF API V3, directly exported from TypeBox schemas.
3
+ TypeScript types for PF API V3, synced directly from TypeBox schemas in pfapi-fs.
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -13,98 +13,179 @@ npm install @pfdev/api-types
13
13
  ### Use in React/React Native
14
14
 
15
15
  ```typescript
16
- import type { components, paths } from '@pfdev/api-types';
17
-
18
- // Type your API responses
19
- type SetListResponse = components['schemas']['SetListResponse'];
20
- type SetDetail = components['schemas']['SetDetail'];
21
-
22
- // Type your API calls
23
- const getSets = async (): Promise<SetListResponse> => {
24
- const res = await fetch('/api/v3/sets');
25
- return res.json();
26
- };
27
-
28
- const getSet = async (setid: string): Promise<SetDetail> => {
29
- const res = await fetch(`/api/v3/sets/${setid}`);
30
- return res.json();
31
- };
16
+ import { useState, useEffect } from 'react';
17
+ import type { SetDetail } from '@pfdev/api-types';
18
+
19
+ function SetDisplay({ setId }: { setId: string }) {
20
+ const [set, setSet] = useState<SetDetail | null>(null);
21
+ const [loading, setLoading] = useState(true);
22
+
23
+ useEffect(() => {
24
+ const fetchSet = async () => {
25
+ const response = await fetch(`/api/v3/sets/${setId}`);
26
+ const data: SetDetail = await response.json();
27
+ setSet(data);
28
+ setLoading(false);
29
+ };
30
+
31
+ fetchSet();
32
+ }, [setId]);
33
+
34
+ if (loading) return <div>Loading...</div>;
35
+ if (!set) return <div>Not found</div>;
36
+
37
+ return (
38
+ <div>
39
+ <h1>{set.name}</h1>
40
+ <p>Series: {set.series}</p>
41
+ <p>Released: {set.releaseddate}</p>
42
+ <img src={set.imglogo} alt={set.name} />
43
+
44
+ {set.current_price && (
45
+ <p>Current Price: ${set.current_price}</p>
46
+ )}
47
+
48
+ <div>
49
+ <p>7-day change: {set.change_7d}%</p>
50
+ <p>1-year change: {set.change_1y}%</p>
51
+ </div>
52
+
53
+ <h3>Rarity Distribution</h3>
54
+ <ul>
55
+ {set.rarities.map((rarity) => (
56
+ <li key={rarity.rarity}>
57
+ {rarity.rarity}: {rarity.count} cards
58
+ </li>
59
+ ))}
60
+ </ul>
61
+ </div>
62
+ );
63
+ }
32
64
  ```
33
65
 
66
+ **Benefits:**
67
+ - ✅ Full IDE autocomplete on `set.` properties
68
+ - ✅ Type errors caught at compile time
69
+ - ✅ Optional fields properly typed (e.g., `current_price?: number`)
70
+ - ✅ Nested types fully typed (e.g., `rarities: RarityCount[]`)
71
+
34
72
  ## Features
35
73
 
36
- ✅ **Fully Typed** - All API endpoints have TypeScript types
37
- ✅ **Auto-Generated** - Types come directly from API schemas
38
- ✅ **Zero Manual Maintenance** - Regenerate when API changes
39
- ✅ **OpenAPI Standard** - Compatible with any OpenAPI tooling
40
- ✅ **Free to Publish** - No paid npm account needed
74
+ ✅ **Single Source of Truth** - Types synced from pfapi-fs schemas
75
+ ✅ **Fully Typed** - IDE autocompletion on all API responses
76
+ ✅ **Zero Dependencies** - Only ~5 KB, no runtime overhead
77
+ ✅ **Type Safe** - Catch errors at compile time, not runtime
78
+ ✅ **Free** - No paid npm account needed
79
+
80
+ ## Publishing Workflow
81
+
82
+ ### Prerequisites
83
+
84
+ - pfapi-fs available locally (no need to run it)
85
+ - npm installed
41
86
 
42
- ## Development
87
+ ### Step-by-Step
43
88
 
44
- ### Add/Update Types
89
+ #### 1. Make changes in pfapi-fs
45
90
 
46
- When you add new V3 endpoints:
91
+ Add or modify V3 endpoints with TypeBox schemas:
47
92
 
48
- 1. Create schemas in `../pfapi-fs/src/routes/v3/{resource}/schemas.ts`
49
- 2. Export the TypeBox schemas
50
- 3. Copy the types to `v3.ts` in this package
51
- 4. Commit and publish
93
+ ```typescript
94
+ // pfapi-fs/src/routes/v3/sets/schemas.ts
95
+ export const SetDetailSchema = Type.Object({
96
+ setid: Type.String(),
97
+ name: Type.String(),
98
+ series: Type.String(),
99
+ // ... more fields
100
+ });
101
+
102
+ export type SetDetail = Static<typeof SetDetailSchema>;
103
+ ```
104
+
105
+ #### 2. Bump version and generate types
52
106
 
53
- Example workflow:
54
107
  ```bash
55
- # Backend: Create new endpoint with TypeBox schemas
56
- # pfapi-fs/src/routes/v3/cards/schemas.ts
57
- export const CardSchema = Type.Object({ ... })
58
- export type Card = Static<typeof CardSchema>
108
+ cd ../pfapi-types
109
+ npm version patch # or minor/major
110
+ ```
111
+
112
+ This automatically:
113
+ - ✅ Syncs TypeBox schemas from `../pfapi-fs/src/routes/v3/*/schemas.ts`
114
+ - ✅ Validates with TypeScript
115
+ - ✅ Stages v3.ts with git
116
+ - ✅ Bumps version (3.0.0 → 3.0.1)
117
+ - ✅ Creates git tag
59
118
 
60
- # Types package: Re-export in v3.ts
61
- # pfapi-types/v3.ts
62
- export { CardSchema, type Card } from '...'
119
+ #### 3. Publish to npm
63
120
 
64
- # Publish
65
- npm version patch
121
+ ```bash
66
122
  npm publish
67
123
  ```
68
124
 
69
- ## Publishing
70
-
71
- ### First Time Only
125
+ Verifies v3.ts changed, then publishes to npm.
72
126
 
73
- 1. Create free npm account: https://www.npmjs.com/signup
74
- 2. Login locally: `npm login`
75
- 3. Publish: `npm publish`
127
+ ## Manual Type Generation
76
128
 
77
- ### Update Existing Package
129
+ To manually regenerate types without versioning:
78
130
 
79
131
  ```bash
80
- # Regenerate types from updated API
81
132
  npm run generate
133
+ ```
82
134
 
83
- # Bump version
84
- npm version patch # or minor/major
135
+ ## How It Works
85
136
 
86
- # Publish
87
- npm publish
137
+ ### Single Source of Truth
138
+ ```
139
+ pfapi-fs/src/routes/v3/sets/schemas.ts ← Edit here
140
+ ↓
141
+ npm run generate
142
+ ↓
143
+ pfapi-types/v3.ts ← Auto-synced
144
+ ↓
145
+ Consumer imports
88
146
  ```
89
147
 
90
- ## Version Mapping
148
+ **No drift possible** — types always match the backend schemas.
91
149
 
92
- - **V3.x.x** - API V3 types
93
- - **V2.x.x** - (future) API V2 types
150
+ ## Version Strategy
151
+
152
+ - **Major** (3.0.0 → 4.0.0) - Breaking API changes
153
+ - **Minor** (3.0.0 → 3.1.0) - New endpoints/features
154
+ - **Patch** (3.0.0 → 3.0.1) - Bug fixes in types
94
155
 
95
156
  ## Files
96
157
 
158
+ - `generate-types.sh` - Script that syncs TypeBox schemas from pfapi-fs
159
+ - `package.json` - npm metadata with automated scripts
160
+ - `v3.ts` - Auto-generated types (do not edit manually)
97
161
  - `index.ts` - Main entry point (re-exports v3.ts)
98
- - `v3.ts` - Auto-generated types (run `npm run generate`)
99
- - `package.json` - npm metadata
100
- - `SETUP.md` - Detailed setup guide
162
+
163
+ ## Troubleshooting
164
+
165
+ ### "Error: No changes to v3.ts since last tag"
166
+
167
+ The `preversion` hook prevents versioning if types haven't changed. Make sure:
168
+ - You've made actual changes to V3 schemas in pfapi-fs
169
+ - Run `npm run generate` to test schema sync
170
+
171
+ ### "TypeScript validation failed"
172
+
173
+ Check that:
174
+ - All TypeBox schemas in pfapi-fs compile
175
+ - Imports are correct in `src/routes/v3/*/schemas.ts`
176
+
177
+ ### "npm ERR! code E404"
178
+
179
+ Make sure npm is authenticated and you have publish permissions for `@pfdev/api-types`.
180
+
181
+ ## Publishing for the First Time
182
+
183
+ 1. Create free npm account: https://www.npmjs.com/signup
184
+ 2. Login: `npm login`
185
+ 3. Publish: `npm publish`
101
186
 
102
187
  ## No Cost
103
188
 
104
189
  - ✅ npm account: FREE (forever)
105
190
  - ✅ Publish to npm: FREE (unlimited public packages)
106
- - ✅ Type generation: FREE (openapi-typescript is open source)
107
-
108
- ## Support
109
-
110
- See `SETUP.md` for troubleshooting and CI/CD setup.
191
+ - ✅ All tools: FREE (open source)
package/index.ts CHANGED
@@ -1,2 +1,2 @@
1
- // Re-export all V3 API types
1
+ // Re-export all V3 API types synced from pfapi-fs
2
2
  export * from './v3';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pfdev/api-types",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "TypeScript types for PF API V3",
5
5
  "main": "index.ts",
6
6
  "types": "index.ts",
@@ -9,7 +9,10 @@
9
9
  "v3.ts"
10
10
  ],
11
11
  "scripts": {
12
- "verify": "tsc --noEmit v3.ts"
12
+ "verify": "tsc --noEmit v3.ts",
13
+ "generate": "bash generate-types.sh",
14
+ "preversion": "npm run generate && git add v3.ts",
15
+ "prepublishonly": "git diff HEAD v3.ts || (echo 'Error: No changes to v3.ts since last publish' && exit 1)"
13
16
  },
14
17
  "keywords": [
15
18
  "api",
package/v3.ts CHANGED
@@ -1,11 +1,13 @@
1
- // V3 API Types
2
- // Manually exported from backend TypeBox schemas
3
- // Update this as new V3 endpoints are added
1
+ // Auto-generated from pfapi-fs/src/routes/v3/*/schemas.ts
2
+ // Do not edit manually - run `npm run generate` to update
4
3
 
5
4
  import { Static, Type } from '@sinclair/typebox';
6
5
 
6
+
7
7
  // ============= SETS =============
8
8
 
9
+
10
+ // Response for list of sets
9
11
  export const SetListItemSchema = Type.Object({
10
12
  setid: Type.String({ description: 'Unique set identifier' }),
11
13
  name: Type.String({ description: 'Set name' }),
@@ -21,48 +23,66 @@ export const SetListItemSchema = Type.Object({
21
23
 
22
24
  export type SetListItem = Static<typeof SetListItemSchema>;
23
25
 
24
- export const SetListResponseSchema = Type.Object({
25
- data: Type.Array(SetListItemSchema),
26
- total: Type.Number({ description: 'Total number of sets' }),
27
- count: Type.Number({ description: 'Number of sets returned' })
28
- });
26
+ export const SetListResponseSchema = Type.Object(
27
+ {
28
+ data: Type.Array(SetListItemSchema, { description: 'Array of sets' }),
29
+ total: Type.Number({ description: 'Total number of sets available' }),
30
+ count: Type.Number({ description: 'Number of sets returned in this response' })
31
+ },
32
+ {
33
+ title: 'SetListResponse',
34
+ description: 'Paginated list of Pokemon card sets'
35
+ }
36
+ );
29
37
 
30
38
  export type SetListResponse = Static<typeof SetListResponseSchema>;
31
39
 
32
- export const RarityCountSchema = Type.Object({
33
- rarity: Type.String(),
34
- count: Type.Number()
35
- });
40
+ // Response for set details
41
+ export const RarityCountSchema = Type.Object(
42
+ {
43
+ rarity: Type.String({ description: 'Rarity level' }),
44
+ count: Type.Number({ description: 'Number of cards with this rarity' })
45
+ },
46
+ {
47
+ title: 'RarityCount',
48
+ description: 'Card rarity distribution in a set'
49
+ }
50
+ );
36
51
 
37
52
  export type RarityCount = Static<typeof RarityCountSchema>;
38
53
 
39
- export const SetDetailSchema = Type.Object({
40
- setid: Type.String(),
41
- name: Type.String(),
42
- printedtotal: Type.Number(),
43
- total: Type.Number(),
44
- series: Type.String(),
45
- releaseddate: Type.String({ format: 'date' }),
46
- updatedat: Type.String({ format: 'date-time' }),
47
- imgsymbol: Type.String({ format: 'uri' }),
48
- imglogo: Type.String({ format: 'uri' }),
49
- slug: Type.String(),
50
- ptcgocode: Type.Optional(Type.String()),
51
- legalities: Type.Optional(Type.Record(Type.String(), Type.String())),
52
- current_price: Type.Optional(Type.Number()),
53
- change_1d: Type.Optional(Type.Number()),
54
- change_7d: Type.Optional(Type.Number()),
55
- change_1m: Type.Optional(Type.Number()),
56
- change_3m: Type.Optional(Type.Number()),
57
- change_6m: Type.Optional(Type.Number()),
58
- change_1y: Type.Optional(Type.Number()),
59
- rarities: Type.Array(RarityCountSchema)
60
- });
54
+ export const SetDetailSchema = Type.Object(
55
+ {
56
+ setid: Type.String({ description: 'Unique set identifier' }),
57
+ name: Type.String({ description: 'Set name' }),
58
+ printedtotal: Type.Number({ description: 'Total cards printed (official)' }),
59
+ total: Type.Number({ description: 'Total unique cards in set' }),
60
+ series: Type.String({ description: 'Pokemon series name' }),
61
+ releaseddate: Type.String({ format: 'date', description: 'Release date' }),
62
+ updatedat: Type.String({ format: 'date-time', description: 'Last update timestamp' }),
63
+ imgsymbol: Type.String({ format: 'uri', description: 'Set symbol image URL' }),
64
+ imglogo: Type.String({ format: 'uri', description: 'Set logo image URL' }),
65
+ slug: Type.String({ description: 'URL-friendly identifier' }),
66
+ ptcgocode: Type.Optional(Type.String({ description: 'Pokemon TCG Live code (if available)' })),
67
+ legalities: Type.Optional(Type.Record(Type.String(), Type.String(), { description: 'Format legalities' })),
68
+ current_price: Type.Optional(Type.Number({ description: 'Current market price' })),
69
+ change_1d: Type.Optional(Type.Number({ description: '1-day price change %' })),
70
+ change_7d: Type.Optional(Type.Number({ description: '7-day price change %' })),
71
+ change_1m: Type.Optional(Type.Number({ description: '30-day price change %' })),
72
+ change_3m: Type.Optional(Type.Number({ description: '90-day price change %' })),
73
+ change_6m: Type.Optional(Type.Number({ description: '180-day price change %' })),
74
+ change_1y: Type.Optional(Type.Number({ description: '1-year price change %' })),
75
+ rarities: Type.Array(RarityCountSchema, { description: 'Card rarity distribution' })
76
+ },
77
+ {
78
+ title: 'SetDetail',
79
+ description: 'Detailed information about a Pokemon card set'
80
+ }
81
+ );
61
82
 
62
83
  export type SetDetail = Static<typeof SetDetailSchema>;
63
84
 
64
- // ============= QUERY/PARAMS =============
65
-
85
+ // Query parameters
66
86
  export const SetListQuerySchema = Type.Object({
67
87
  search: Type.Optional(Type.String({ description: 'Search by set name' })),
68
88
  series: Type.Optional(Type.String({ description: 'Filter by series' })),
@@ -72,9 +92,9 @@ export const SetListQuerySchema = Type.Object({
72
92
 
73
93
  export type SetListQuery = Static<typeof SetListQuerySchema>;
74
94
 
95
+ // Path parameters
75
96
  export const SetDetailParamSchema = Type.Object({
76
97
  setid: Type.String({ description: 'Set ID or slug' })
77
98
  });
78
99
 
79
100
  export type SetDetailParam = Static<typeof SetDetailParamSchema>;
80
-