Skip to content

Commit ef10a74

Browse files
authored
Merge pull request #10 from RAMP-Protocol/feature/sdk-libraries
Generated SDK types export (Pydantic + Zod) from the proto; money as exact decimal
2 parents 0930484 + 5aa186c commit ef10a74

93 files changed

Lines changed: 10450 additions & 8419 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/proto-ci.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ jobs:
4242
# (informational, pre-v1). The remark docs-guard step self-skips here because
4343
# node_modules is absent; docs-ci.yml owns the docs build.
4444
- name: gating sequence (scripts/ci-local.sh)
45-
run: ./scripts/ci-local.sh
45+
# sdk-types-ci.yml owns the Pydantic/Zod gate (path-filtered), so skip it here
46+
# and keep this job the proto mirror. Locally ci-local.sh runs both.
47+
run: RAMP_CI_SKIP_SDK_TYPES=1 ./scripts/ci-local.sh

.github/workflows/sdk-types-ci.yml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
name: sdk-types-ci
2+
3+
# Drift gate for the generated TYPES EXPORT (Pydantic + Zod). Regenerates from the
4+
# proto via scripts/gen-sdk-types.sh and fails if the committed output differs — the
5+
# same regenerate-and-diff contract as the gen/ drift gate, for the SDK types. Runs
6+
# only when the proto, the descriptor, the generators, or the committed output change.
7+
on:
8+
push:
9+
branches: [main]
10+
paths: &paths
11+
- 'proto/**'
12+
- 'gen/descriptor.binpb'
13+
- 'scripts/gen-sdk-types.sh'
14+
- 'scripts/check-canonical.sh'
15+
- 'scripts/sdk-types/**'
16+
- 'conformance/**'
17+
- 'gen/python/**'
18+
- 'gen/ts/**'
19+
- '.github/workflows/sdk-types-ci.yml'
20+
pull_request:
21+
paths: *paths
22+
23+
jobs:
24+
sdk-types:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v4
28+
- uses: actions/setup-go@v5
29+
with:
30+
go-version-file: go.mod
31+
- uses: bufbuild/buf-setup-action@v1
32+
with:
33+
version: 1.66.1
34+
github_token: ${{ secrets.GITHUB_TOKEN }}
35+
- uses: actions/setup-python@v5
36+
with:
37+
python-version: '3.12'
38+
- uses: actions/setup-node@v4
39+
with:
40+
node-version: 22
41+
42+
- name: regenerate types export
43+
run: ./scripts/gen-sdk-types.sh
44+
45+
# Only the two generated files; wire/base.py is hand-written (the seam) and the
46+
# vocab constants are generated by buf, gated separately.
47+
- name: assert no drift
48+
run: |
49+
if ! git diff --exit-code -- gen/python/wire/models.py gen/ts/wire/schemas.ts; then
50+
echo "::error::Generated types export is out of sync with the proto. Run scripts/gen-sdk-types.sh and commit gen/python/wire/models.py + gen/ts/wire/schemas.ts."
51+
exit 1
52+
fi
53+
54+
# Cross-language validation parity: the generated Pydantic models and Zod schemas
55+
# must reach the SAME verdict as Go protovalidate on every case in the generated
56+
# corpus (conformance/corpus/cases.json) — proving the proto -> JSON Schema ->
57+
# client pipeline carries every field-level rule. The corpus is pinned to
58+
# protovalidate by the Go conformance suite (proto-ci) and gated for drift there.
59+
- name: Python (Pydantic) parity
60+
run: |
61+
python -m pip install -q "pydantic>=2.0" pytest
62+
PYTHONPATH=gen/python pytest gen/python/tests -q
63+
64+
- name: TypeScript (Zod) parity
65+
working-directory: gen/ts
66+
run: |
67+
npm install
68+
npm test
69+
70+
# Canonical proto-JSON interop: each client re-serializes every valid corpus
71+
# instance and the emission, read back through Go protojson, must decode to the
72+
# same proto message as the original (incl. Timestamp/Duration). Reuses the
73+
# .sdk-types-work venv + zod provisioned by gen-sdk-types.sh above.
74+
- name: Canonical proto-JSON round-trip
75+
run: ./scripts/check-canonical.sh

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ research-*.md
99

1010
# Local agent/review scratch — never ship AI-review artifacts in the protocol repo
1111
.claude/
12+
__pycache__/
13+
.sdk-types-work/

README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,44 @@ A working multi-language stack — Exchange (Go), Broker (Go), Edge (TypeScript)
3535

3636
## SDKs
3737

38+
All three languages are generated from `proto/`: Go is native protobuf + Connect via
39+
`buf generate` (it is the server/runtime); the Python and TypeScript **types exports**
40+
— Pydantic models and Zod schemas — are generated from the same proto via JSON Schema
41+
by `scripts/gen-sdk-types.sh` (the two real consumers, the Python MCP shim and the
42+
TypeScript edge worker, cannot use protobuf natively). All three carry **registered
43+
vocabulary constants** per axis (`pricingunits`, `quotametrics`, `functiontokens`,
44+
`geographytokens`, `usertypes`) so consumers use typed constants and an
45+
`IsRegistered`/`isRegistered`/`is_registered` membership check instead of magic
46+
strings. The vocab is emitted from the single `(ramp.v1.vocab)` source in one pass, so
47+
the three languages cannot drift from each other.
48+
3849
### Go
3950

4051
```go
4152
import (
4253
rampv1 "github.com/RAMP-Protocol/protocol/gen/go/ramp/v1"
4354
"github.com/RAMP-Protocol/protocol/gen/go/ramp/v1/rampv1connect"
55+
"github.com/RAMP-Protocol/protocol/gen/go/vocab/pricingunits"
4456
)
4557
```
4658

4759
### TypeScript
4860

49-
TypeScript message types and a Connect client are generated under [`gen/ts/`](gen/ts) (Protobuf-ES + Connect-ES); the [reference implementation](https://github.com/RAMP-Protocol/reference-implementation) shows them in use.
61+
Zod schemas for every message are generated under [`gen/ts/wire/schemas.ts`](gen/ts/wire/schemas.ts) (validated message types; the edge worker uses them for request validation), with vocabulary constants under [`gen/ts/vocab/`](gen/ts/vocab); the [reference implementation](https://github.com/RAMP-Protocol/reference-implementation) shows them in use.
62+
63+
```typescript
64+
import { OfferSchema } from "@ramp-protocol/sdk/wire/schemas";
65+
import { pricingunits } from "@ramp-protocol/sdk/vocab/pricingunits";
66+
```
67+
68+
### Python
69+
70+
Pydantic v2 models for every message (extending the hand-written `wire.base.WireModel` seam) plus vocabulary constants are generated under [`gen/python/`](gen/python) (`pip install .` from that directory; see its [README](gen/python/README.md)).
71+
72+
```python
73+
from wire.models import Offer, Pricing
74+
from vocab import pricingunits
75+
```
5076

5177
## License
5278

0 commit comments

Comments
 (0)