@myrobotaxi/contracts 0.3.0 → 0.4.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/CONTRIBUTING.md +15 -4
- package/README.md +40 -2
- package/package.json +2 -1
package/CONTRIBUTING.md
CHANGED
|
@@ -11,8 +11,8 @@ This means any schema change requires:
|
|
|
11
11
|
1. Open a PR in [`myrobotaxi/telemetry`](https://github.com/myrobotaxi/telemetry) that edits the source `.schema.json` file under `docs/contracts/schemas/`. Get it reviewed and merged.
|
|
12
12
|
2. Open a paired PR in this repo that:
|
|
13
13
|
- Copies the new schema file from the telemetry repo into `schemas/`
|
|
14
|
-
- Runs `npm run codegen` to regenerate `src/generated/`
|
|
15
|
-
- Commits the regenerated `.ts` files
|
|
14
|
+
- Runs `npm run codegen` to regenerate `src/generated/` and `npm run codegen:swift` to regenerate `Sources/MyRobotaxiContracts/Generated/`
|
|
15
|
+
- Commits the regenerated `.ts` and `.swift` files
|
|
16
16
|
- Bumps the version per the [versioning policy](#versioning-policy)
|
|
17
17
|
|
|
18
18
|
Until [Phase 2](#phase-2-migration-authoring-home) ships, this paired-PR convention is enforced by review (no automation).
|
|
@@ -40,9 +40,20 @@ The MyRoboTaxi schemas use these non-standard keywords:
|
|
|
40
40
|
| `x-encrypted` / `x-encrypted-at-rest` | AES-256-GCM at rest |
|
|
41
41
|
| `x-tesla-proto-field` | Source Tesla protobuf field number |
|
|
42
42
|
|
|
43
|
-
The codegen pipeline (`scripts/codegen.mjs`) **folds these into TSDoc comments** at generation time, so they survive into the consumer's editor as `@classification "P0"` annotations.
|
|
43
|
+
The codegen pipeline (`scripts/codegen.mjs`) **folds these into TSDoc comments** at generation time, so they survive into the consumer's editor as `@classification "P0"` annotations. The Swift pipeline (`scripts/codegen-swift.mjs`) does the same folding into SwiftDoc (`///`) comments.
|
|
44
44
|
|
|
45
|
-
If you add a new `x-*` keyword to a schema, add it to the `ANNOTATIONS` array in `scripts/codegen.mjs` and re-run `npm run codegen`.
|
|
45
|
+
If you add a new `x-*` keyword to a schema, add it to the `ANNOTATIONS` array in **both** `scripts/codegen.mjs` and `scripts/codegen-swift.mjs`, then re-run `npm run codegen` and `npm run codegen:swift`.
|
|
46
|
+
|
|
47
|
+
## Swift codegen pipeline
|
|
48
|
+
|
|
49
|
+
The repo doubles as a Swift package (`Package.swift` at the root, product `MyRobotaxiContracts`). Swift types are generated from the same `schemas/*.json` source of truth:
|
|
50
|
+
|
|
51
|
+
- **Generator**: `scripts/codegen-swift.mjs` — a small custom Node script (zero npm dependencies; runs without `npm ci`). One `Codable`/`Equatable`/`Sendable` struct per root schema object and per `$defs` entry (websocket-protocol.md §9.2); string enums become Swift `enum ...: String` with wire raw values.
|
|
52
|
+
- **Output**: `Sources/MyRobotaxiContracts/Generated/*.swift` — **committed**, never hand-edited (same rule as `src/generated/`). Regeneration is deterministic: emission order follows the schema JSON, so re-running on an unchanged schema is a no-op diff.
|
|
53
|
+
- **Hand-written support code**: `Sources/MyRobotaxiContracts/JSONValue.swift` (arbitrary-JSON enum used for `WebSocketEnvelope.payload` and `VehicleUpdatePayload.fields`) is NOT generated and may be edited.
|
|
54
|
+
- **Regenerate**: `npm run codegen:swift` after any schema change, and commit the result alongside the regenerated TypeScript.
|
|
55
|
+
- **CI**: the `swift` job on `macos-latest` runs `swift build`, `swift test`, then `npm run codegen:swift` and fails on drift in `Sources/MyRobotaxiContracts/Generated/` — mirroring the TypeScript `codegen-drift` job.
|
|
56
|
+
- **Consumption**: Swift consumers resolve the package by git URL + tag (`from: "0.x.y"`); there is no Swift registry publish. The `v0.x.y` git tags pushed for npm releases are also what SwiftPM resolves against, so the versioning policy above applies to the Swift surface too.
|
|
46
57
|
|
|
47
58
|
## Release process
|
|
48
59
|
|
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ import { schemas } from '@myrobotaxi/contracts';
|
|
|
28
28
|
// schemas.vehicleState, schemas.wsMessages, schemas.wsEnvelope
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Raw JSON for non-JS consumers (Go
|
|
31
|
+
Raw JSON for non-JS consumers (Go):
|
|
32
32
|
|
|
33
33
|
```
|
|
34
34
|
./node_modules/@myrobotaxi/contracts/schemas/vehicle-state.schema.json
|
|
@@ -36,6 +36,40 @@ Raw JSON for non-JS consumers (Go, Swift):
|
|
|
36
36
|
./node_modules/@myrobotaxi/contracts/schemas/ws-envelope.schema.json
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
## Swift
|
|
40
|
+
|
|
41
|
+
This repo is also a Swift package (`MyRobotaxiContracts`) with **pre-generated `Codable`/`Sendable` structs** under `Sources/MyRobotaxiContracts/Generated/` — produced by `scripts/codegen-swift.mjs` and committed for diff review, exactly like the TypeScript types. Swift consumers resolve by git URL + semver tag (no registry publish).
|
|
42
|
+
|
|
43
|
+
In your `Package.swift`:
|
|
44
|
+
|
|
45
|
+
```swift
|
|
46
|
+
dependencies: [
|
|
47
|
+
.package(url: "https://github.com/myrobotaxi/contracts.git", from: "0.4.0")
|
|
48
|
+
],
|
|
49
|
+
targets: [
|
|
50
|
+
.target(
|
|
51
|
+
name: "MyApp",
|
|
52
|
+
dependencies: [.product(name: "MyRobotaxiContracts", package: "contracts")]
|
|
53
|
+
)
|
|
54
|
+
]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Usage:
|
|
58
|
+
|
|
59
|
+
```swift
|
|
60
|
+
import MyRobotaxiContracts
|
|
61
|
+
|
|
62
|
+
let state = try JSONDecoder().decode(VehicleState.self, from: snapshotData)
|
|
63
|
+
let envelope = try JSONDecoder().decode(WebSocketEnvelope.self, from: frameData)
|
|
64
|
+
if envelope.type == .vehicleUpdate { /* decode VehicleUpdatePayload from envelope.payload */ }
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The same custom annotations are folded into the generated SwiftDoc comments, so `grep '@classification "P1"'` works inside the checked-out package too. Wire enums (`status`, `chargeState`, `MessageType`, error codes, …) generate as Swift `enum ...: String` with wire raw values; nullable / non-required schema fields are Swift optionals. The intentionally-open wire positions — `WebSocketEnvelope.payload` and `VehicleUpdatePayload.fields` — are typed via the hand-written `JSONValue` enum, which preserves explicit JSON `null`s (required for atomic-group clears per NFR-3.9).
|
|
68
|
+
|
|
69
|
+
## Tool choice (Swift): custom generator
|
|
70
|
+
|
|
71
|
+
Like the TypeScript side, the Swift generator is a small custom script (`scripts/codegen-swift.mjs`, no `quicktype`): it keeps the annotation-folding grep affordance, emits exactly one type per root schema and per `$defs` entry (websocket-protocol.md §9.2), needs no npm install (zero dependencies), and is deterministic so CI can diff the committed output.
|
|
72
|
+
|
|
39
73
|
## What's in the generated TypeScript
|
|
40
74
|
|
|
41
75
|
Custom JSON Schema annotations from the source schemas — `x-classification`, `x-atomic-group`, `x-unit`, `x-encrypted`, `x-tesla-proto-field` — are folded into the generated TSDoc comments at codegen time. This means consumers can `grep '@classification "P1"'` inside their `node_modules` to find every sensitive field without leaving their editor.
|
|
@@ -82,12 +116,16 @@ A planned follow-up moves the schema authoring home from `telemetry/docs/contrac
|
|
|
82
116
|
```bash
|
|
83
117
|
npm install
|
|
84
118
|
npm run codegen # regenerate src/generated/ from schemas/
|
|
119
|
+
npm run codegen:swift # regenerate Sources/MyRobotaxiContracts/Generated/ from schemas/
|
|
85
120
|
npm run typecheck
|
|
86
121
|
npm run test
|
|
87
122
|
npm run build # tsup → dist/
|
|
123
|
+
|
|
124
|
+
swift build # Swift package
|
|
125
|
+
swift test
|
|
88
126
|
```
|
|
89
127
|
|
|
90
|
-
CI runs
|
|
128
|
+
CI runs both codegens and fails if `src/generated/` or `Sources/MyRobotaxiContracts/Generated/` drifts from the schemas — every schema bump must be paired with a regenerate-and-commit (both languages).
|
|
91
129
|
|
|
92
130
|
## License
|
|
93
131
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myrobotaxi/contracts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Canonical wire-protocol schemas for the MyRoboTaxi platform. JSON Schema (draft-2020-12) + pre-generated TypeScript types. Consumed by SDKs (TS, Swift) and the Go telemetry server.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
],
|
|
53
53
|
"scripts": {
|
|
54
54
|
"codegen": "node scripts/codegen.mjs",
|
|
55
|
+
"codegen:swift": "node scripts/codegen-swift.mjs",
|
|
55
56
|
"build": "tsup",
|
|
56
57
|
"clean": "rm -rf dist coverage",
|
|
57
58
|
"lint": "eslint .",
|