|
| 1 | +# Plan 002: gh-v1 adopts `@versionone/sdk` (Track C) |
| 2 | + |
| 3 | +Brief for a session on `versionone/gh-v1`. Start once the SDK PR that adds |
| 4 | +this file has merged into `proposed_type_script_api_version`. Source plan: |
| 5 | +`plans/001-sdk-adoption-campaign.md`, Track C. |
| 6 | + |
| 7 | +## Goal |
| 8 | + |
| 9 | +gh-v1 talks to Agility only through `@versionone/sdk`. CLI behaviour and |
| 10 | +output stay the same; the code that duplicates the SDK goes. |
| 11 | + |
| 12 | +## Where things stand (checked 2026-11-06, gh-v1 `2c58c7e`) |
| 13 | + |
| 14 | +- G0–G3 are merged: executable bin, `V1_URL`/`V1_ACCESS_TOKEN` config, ESM |
| 15 | + (`"type": "module"`), `jsconfig.json` + `npm run typecheck`, one paging |
| 16 | + module (`lib/paging.js`). |
| 17 | +- The bin `gh-v1` is now a `sh` launcher that runs `gh-v1.js` with the real |
| 18 | + node (bypassing Volta's shim, which mangles arguments on Windows). The |
| 19 | + swap does not touch either; keep `test/launcher.test.js` green. |
| 20 | +- One seam: `lib/api.js` exports `api(cfg)` returning `query`, `queries`, |
| 21 | + `asset`, `attempt`, `rest`, `meta`, `localize`, `raw`, `blob`, |
| 22 | + `permalink`, typed by the `Api` JSDoc typedef. Its tests under `test/` |
| 23 | + stub global `fetch`. |
| 24 | +- String-boolean and OID helpers (`isTrue`, `oidOf`, `momentless`) are used |
| 25 | + in `lib/api.js`, `meta.js`, `resolve.js`, `board.js`, `batch.js`, and |
| 26 | + `commands/apply.js`, `bulk.js`, `board.js`. |
| 27 | + |
| 28 | +## Dependency |
| 29 | + |
| 30 | +No registry package yet. Add the first runtime dependency as a pinned commit: |
| 31 | +`"@versionone/sdk": "github:versionone/VersionOne.SDK.JavaScript#<merge sha>"`. |
| 32 | +The SDK's `prepare` script builds `dist` on install. gh-v1 is ESM now, so use |
| 33 | +`import` (the ESM build), not `require`. |
| 34 | + |
| 35 | +## Steps, one PR each, on branch `sdk-adoption` |
| 36 | + |
| 37 | +1. **C1 Seam swap** (`lib/api.js`). Keep `api(cfg)` and the `Api` typedef. |
| 38 | + Inside, build one `AgilityApiClient({ baseUrl: cfg.v1Url, accessToken })`. |
| 39 | + Map: `query`/`queries` → `client.assets.query`/`queries`; |
| 40 | + `asset` → `client.assets.send(cmds, { throwOnFailure: true })` |
| 41 | + (a `CommandFailureError` carries `failures` by index — keep `err.failures`); |
| 42 | + `attempt` → `client.assets.send` (failures returned, not thrown); |
| 43 | + `rest` → `client.data.list`/`get`; `meta` → `client.meta.*`; |
| 44 | + `localize` → `client.localize`. `raw`, `blob`, `permalink` stay local. |
| 45 | + Rows now arrive translated (`true`, numbers, single relations as one |
| 46 | + Ref), so update the fixtures in tests that assert raw strings, and add |
| 47 | + the meta fixture the schema needs (`test/meta-fixture.js`, or seed |
| 48 | + `ClientOptions.metamodel`). |
| 49 | +2. **C2 Delete the decodes.** Remove `isTrue`/`oidOf` call sites listed |
| 50 | + above; import `momentless` from the SDK. |
| 51 | +3. **C3 Invert the services.** `resolveAssets` → `client.resolve.numbers` |
| 52 | + (its `missing` drives the "not found — skipped" lines). `batch.run` → |
| 53 | + `client.batch.run`, with `confirm` as the prompt and the receipt written |
| 54 | + as returned. `--reverse` → `client.batch.reversible` (`--force` passes |
| 55 | + `force`). Keep the CLI's UX for an unguardable batch by checking |
| 56 | + `unguardable()` first, then sending with `guard: false` and the existing |
| 57 | + note. Prompting, rendering, permalinks and receipt files stay in gh-v1. |
| 58 | +4. **C4 Passthrough.** `raw`/`blob` stay as they are. `lib/guard.js` stays: |
| 59 | + it is CLI policy, not SDK behaviour. |
| 60 | + |
| 61 | +## Rules |
| 62 | + |
| 63 | +- Requests out must match today's, apart from what translation changes. |
| 64 | + Add a test that asserts the request body where it differs, and say why. |
| 65 | +- Every query keeps an explicit page (the SDK refuses one without). |
| 66 | +- Live Agility calls go only to the API/SDK testing instance, |
| 67 | + `https://www14.v1host.com/v1sdktesting` (`V1_URL`). Writes are allowed |
| 68 | + there and nowhere else: name fixtures `sdk-integration …` and delete them |
| 69 | + by exact OID when done. Every query sets an explicit page size and stays |
| 70 | + well under 20 s of server work. |
| 71 | + |
| 72 | +## Done when |
| 73 | + |
| 74 | +- `npm test` and `npm run typecheck` pass on each PR. |
| 75 | +- `lib/api.js` has no `fetch` call except in `raw`/`blob`. |
| 76 | +- No `isTrue`/`oidOf`/local `momentless` remain in `lib/`. |
| 77 | +- `lib/resolve.js` and `lib/batch.js` keep only prompting, rendering and |
| 78 | + file I/O. |
| 79 | +- Plan 001's checklist line `C1–C4 gh-v1` is ticked, with the PR links. |
0 commit comments