@@ -27,158 +27,131 @@ PMXT uses a **"Sidecar" architecture** for multi-language support:
2727
2828### Why This Approach?
2929
30- 1 . ** Single Source of Truth** : The Node.js implementation is the canonical version
30+ 1 . ** Single Source of Truth** : The implementation in ` core/ ` is the canonical version
31312 . ** Consistency** : All languages get identical behavior
32323 . ** Rapid Iteration** : Update the server, all SDKs update automatically
33334 . ** Quality** : We can write the core logic once, in TypeScript, with full testing
3434
35- ## Directory Structure
35+ ## General Directory Structure
36+
37+ All SDKs follow this pattern:
3638
3739```
3840sdks/
39- └── python /
41+ └── {language} /
4042 ├── pmxt/ # Human-written wrapper (EDIT THIS)
41- │ ├── __init__.py
42- │ ├── client.py # Main Exchange classes
43- │ └── models.py # Clean dataclasses
44- ├── generated/ # Auto-generated (DO NOT EDIT)
45- │ └── pmxt_internal/ # Raw OpenAPI client
43+ │ └── ... # Clean, idiomatic code
44+ ├── {generated}/ # Auto-generated client (DO NOT EDIT)
45+ │ └── ... # Raw OpenAPI client
4646 ├── examples/
47- │ └── basic_usage.py
48- ├── pyproject.toml
49- └── README.md
47+ └── {package-manager-files}
5048```
5149
5250### The Golden Rule
5351
54- ** NEVER manually edit files in ` generated/ ` ** . They will be overwritten.
52+ ** NEVER manually edit files in the generated directory ** . They will be overwritten.
5553
56- All human code goes in ` pmxt/ ` (the wrapper).
54+ All human logic goes in the ` pmxt/ ` directory (the wrapper).
5755
58- ## Generating SDKs
56+ ## Supported Languages
5957
60- ### Python
58+ ### 1. Python ( ` sdks/python ` )
6159
62- ``` bash
63- # Generate the raw OpenAPI client
64- npm run generate:sdk:python
60+ - ** Reference** : [ sdks/python/README.md] ( ./python/README.md )
61+ - ** Generator** : ` python `
62+ - ** Generated Dir** : ` sdks/python/generated/ `
63+ - ** Wrapper Dir** : ` sdks/python/pmxt/ `
6564
66- # Or manually:
67- npx @openapitools/openapi-generator-cli generate \
68- -i src/server/openapi.yaml \
69- -g python \
70- -o sdks/python/generated \
71- --package-name pmxt_internal \
72- --additional-properties=projectName=pmxt-internal,packageVersion=0.4.4,library=urllib3
73- ```
65+ ### 2. TypeScript (` sdks/typescript ` )
7466
75- This creates the "ugly" auto-generated client in ` sdks/python/generated/pmxt_internal/ ` .
67+ - ** Reference** : [ sdks/typescript/README.md] ( ./typescript/README.md )
68+ - ** Generator** : ` typescript-fetch `
69+ - ** Generated Dir** : ` sdks/typescript/src/ `
70+ - ** Wrapper Dir** : ` sdks/typescript/pmxt/ `
7671
77- The human wrapper in ` sdks/python/pmxt/ ` imports this and provides a clean API.
72+ ## Generating SDKs
7873
79- ### Future Languages
74+ To regenerate all SDKs after updating the server specification:
8075
81- When adding Go, Java, etc.:
76+ ``` bash
77+ # In the root or core directory
78+ npm run generate:sdk:all
79+ ```
80+
81+ To generate a specific language:
8282
8383``` bash
84- # Go
85- npm run generate:sdk:go
84+ # Python
85+ npm run generate:sdk:python
8686
87- # Java
88- npm run generate:sdk:java
87+ # TypeScript
88+ npm run generate:sdk:typescript
8989```
9090
91- Each will follow the same pattern:
92- - ` sdks/{language}/generated/ ` - Auto-generated client
93- - ` sdks/{language}/pmxt/ ` - Human wrapper
94-
9591## The Human Wrapper Pattern
9692
97- The wrapper does three things:
93+ The " wrapper" is a handwritten layer that sits on top of the auto-generated code. Its job is to make the API feel native and clean for that language.
9894
99- ### 1. Clean Imports
95+ ### Responsibilities
10096
101- ``` python
102- # User writes:
103- import pmxt
104- poly = pmxt.Polymarket()
105-
106- # Not:
107- from pmxt_internal.api.default_api import DefaultApi
108- from pmxt_internal.configuration import Configuration
109- # ... etc
110- ```
97+ 1 . ** Hide the Ugly** : Generated code is often verbose. The wrapper hides this.
98+ 2 . ** Provide Idiomatic API** : Use language-specific features (e.g., Python properties, TypeScript interfaces).
99+ 3 . ** Manage Server Lifecycle** : Include the ` ServerManager ` to auto-start the sidecar.
100+ 4 . ** Simplify Models** : Convert complex generated schemas into simple data classes/interfaces.
111101
112- ### 2. Pythonic API
102+ ### Example: Python vs TypeScript
113103
114- ``` python
115- # User writes:
116- markets = poly.search_markets(" Trump" , MarketFilterParams(limit = 10 ))
104+ ** Python Wrapper (` sdks/python/pmxt/client.py ` )** :
117105
118- # Not:
119- request = SearchMarketsRequest(args = [" Trump" , {" limit" : 10 }])
120- response = api.search_markets(exchange = " polymarket" , search_markets_request = request)
121- data = response.to_dict()[" data" ]
106+ ``` python
107+ class Exchange (ABC ):
108+ def search_markets (self , query ):
109+ # Calls self._api.search_markets()
110+ # Converts response to UnifiedMarket dataclass
111+ pass
122112```
123113
124- ### 3. Clean Data Models
114+ ** TypeScript Wrapper ( ` sdks/typescript/pmxt/client.ts ` ) ** :
125115
126- ``` python
127- # User gets:
128- @dataclass
129- class UnifiedMarket :
130- id : str
131- title: str
132- outcomes: List[MarketOutcome]
133- # ...
134-
135- # Not:
136- class UnifiedMarket (BaseModel ):
137- def __init__ (self , id = None , title = None , outcomes = None , ...):
138- # 100 lines of generated code
116+ ``` typescript
117+ export abstract class Exchange {
118+ async searchMarkets(query : string ): Promise <UnifiedMarket []> {
119+ // Calls this.api.searchMarkets()
120+ // Converts response to UnifiedMarket interface
121+ return markets ;
122+ }
123+ }
139124```
140125
141- ## Maintaining the Wrapper
126+ ## Maintaining the SDKs
142127
143128When you add a new endpoint to the OpenAPI spec:
144129
145- 1 . ** Update ` src/server/openapi.yaml ` ** with the new endpoint
146- 2 . ** Regenerate** : ` npm run generate:sdk:python `
147- 3 . ** Update the wrapper** :
148- - Add the method to ` pmxt/client.py `
149- - Add any new models to ` pmxt/models.py `
150- - Add a converter function if needed
130+ 1 . ** Update ` src/server/openapi.yaml ` ** with the new endpoint.
131+ 2 . ** Regenerate** SDKs: ` npm run generate:sdk:all ` .
132+ 3 . ** Update the wrappers** :
133+ * ** Python** : Update ` sdks/python/pmxt/client.py ` & ` models.py ` .
134+ * ** TypeScript** : Update ` sdks/typescript/pmxt/client.ts ` & ` models.ts ` .
151135
152- Example:
136+ ## Testing
153137
154- ``` python
155- # In pmxt/client.py
156- def fetch_new_thing (self , thing_id : str ) -> NewThing:
157- """ Fetch a new thing."""
158- try :
159- request_body = {" args" : [thing_id]}
160-
161- response = self ._api.fetch_new_thing(
162- exchange = self .exchange_name,
163- fetch_new_thing_request = request_body,
164- )
165-
166- data = self ._handle_response(response.to_dict())
167- return _convert_new_thing(data)
168- except ApiException as e:
169- raise Exception (f " Failed to fetch new thing: { e} " )
170- ```
138+ Always test your changes in ** both** languages.
171139
172- ## Testing
140+ ### Python
173141
174142``` bash
175143cd sdks/python
176-
177- # Install in development mode
178144pip install -e " .[dev]"
145+ python examples/*
146+ ```
147+
148+ ### TypeScript
179149
180- # Run the example (requires server running)
181- python examples/basic_usage.py
150+ ``` bash
151+ cd sdks/typescript
152+ npm install
153+ npm run build
154+ npx tsx examples/*
182155```
183156
184157## Publishing
@@ -187,61 +160,31 @@ python examples/basic_usage.py
187160
188161``` bash
189162cd sdks/python
190-
191- # Build
192163python -m build
193-
194- # Upload to PyPI
195164python -m twine upload dist/*
196165```
197166
198- ### Version Bumping
199-
200- When releasing a new version:
201-
202- 1 . Update ` package.json ` version
203- 2 . Update ` sdks/python/pyproject.toml ` version
204- 3 . Regenerate SDKs: ` npm run generate:sdk:all `
205- 4 . Commit and tag: ` git tag v0.4.5 `
206-
207- ## Common Issues
208-
209- ### "Module not found: pmxt_internal"
167+ ### TypeScript (NPM)
210168
211- The generated client isn't in the Python path. The wrapper adds it dynamically:
212-
213- ``` python
214- # In pmxt/client.py
215- _GENERATED_PATH = os.path.join(os.path.dirname(__file__ ), " .." , " generated" )
216- sys.path.insert(0 , _GENERATED_PATH )
169+ ``` bash
170+ cd sdks/typescript
171+ npm publish --access public
217172```
218173
219- ### "OpenAPI validation error"
220-
221- Your ` openapi.yaml ` has a schema issue. Common problems:
222-
223- - Empty arrays without ` items: {} `
224- - Missing required fields
225- - Invalid enum values
226-
227- Run the generator with ` --skip-validate-spec ` to see the raw error.
174+ ## Version Bumping
228175
229- ### "Server not running"
230-
231- The Python SDK requires the sidecar server:
232-
233- ``` bash
234- # Terminal 1: Start server
235- npm run server
176+ When releasing a new version:
236177
237- # Terminal 2: Run Python code
238- python examples/basic_usage.py
239- ```
178+ 1 . Update ` core/package.json ` version.
179+ 2 . Update ` sdks/python/pyproject.toml ` version.
180+ 3 . Update ` sdks/typescript/package.json ` version.
181+ 4 . Regenerate SDKs: ` npm run generate:sdk:all ` .
182+ 5 . Commit and tag.
240183
241184## Future: Native Bindings (v2.0.0)
242185
243186Eventually, we'll move to native bindings (Rust + FFI) to eliminate the sidecar dependency. But for v1.0.0, the sidecar approach lets us move fast and support many languages with minimal effort.
244187
245188## Questions?
246189
247- See the main [ ROADMAP.md] ( ../../ ROADMAP.md ) for the overall project vision.
190+ See the main [ ROADMAP.md] ( ../ROADMAP.md ) for the overall project vision.
0 commit comments