@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 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, Swift):
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 `codegen` and fails if `src/generated/` drifts from the schemas — every schema bump must be paired with a regenerate-and-commit.
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.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 .",