Repository navigation
Release 2.1.0-beta.1 - #464
Open
mrafnadeem-apimatic wants to merge 9 commits into
Open
mrafnadeem-apimatic wants to merge 9 commits into
mrafnadeem-apimatic wants to merge 9 commits into
Conversation
Release 2.0.0
Closes #420. 2.0.0 has shipped and `main` is back in `dev` (52b9c39), so this merges without conflicts. ## The change Nothing commits a version or a changelog back to a branch since #409, so both files would go stale: - **`CHANGELOG.md`** opens with a line pointing at GitHub Releases. It keeps the history up to 1.5.0 and drops the 2.0.0-beta.1 and 2.0.0-beta.2 sections, which are in GitHub Releases. - **`package.json`'s `version`** becomes `0.0.0-semantically-released`, the placeholder semantic-release's FAQ suggests. Otherwise it stays at `2.0.0-beta.2`. ## Checked - Everything in `CHANGELOG.md` from 1.5.0 down is unchanged. - `@semantic-release/npm` runs `npm version <next> --no-git-tag-version --allow-same-version` before `npm publish`. On a copy of this `package.json`, that writes the real version. `oclif.manifest.json` is generated after that, by `prepack`. - A build from source: `apimatic --version` prints `@apimatic/cli/0.0.0-semantically-released`, and the User-Agent and telemetry report the same version. `npm pack` names the tarball `apimatic-cli-0.0.0-semantically-released.tgz`, and Portal automation tests find it with a `*.tgz` glob. ## Not in this PR `oclif readme` takes the version from `package.json` for the README's "See code" links and the `--version` example. Run without its `--version` flag, it now writes `blob/v0.0.0-semantically-released/…` links, which 404. Nothing runs it automatically; the README's command section was last regenerated at 1.3.1. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… files samples by spec (#448) ## The problem When two merged specs declare the same method and path, such as `GET /status` on two services, the platform's code samples hold one sample for the pair, keyed by path and method. The portal cannot tell whose it is, so since #435 it leaves the SDK sample off such an operation and warns. The platform is adding a grouping to its samples file. When the operations come from two or more spec files, `code-samples/<language>.json` gains `specs`: each spec's samples, keyed by its main file relative to `src/spec/`. `paths` stays as it is, so released CLIs are unaffected. Tracked in apimatic-io issue 2298. ## What changes - **Samples filed by spec are placed by spec.** When a samples file has `specs`, each spec takes the samples filed under its own file, and only those. The file is matched exactly: `orders/openapi.yaml` for `src/spec/orders/openapi.yaml`. An operation two specs declare then shows each spec's own call. A spec with nothing filed under it shows no SDK sample, rather than calls from `paths` that may be another API's. - **A file without `specs` is read as before.** Every spec takes `paths`, less the operations two specs declare. Every samples file the platform sends today is of this kind. - **The shared-operation warning now depends on the samples file.** It moves from before the server run to after it, and appears only for a file without `specs`. - **Samples no operation takes are checked within each spec** when they are filed by spec, and the warning names the spec. - **Samples filed under a file no spec is read from are named too,** as samples no operation takes. That happens when the platform builds a merged folder from another file than the OpenAPI document the portal reads, such as a Postman collection that sorts first (apimatic-io issue 2307). - **`code-samples.json` changes shape.** The CLI writes this file for the template, and it becomes `{ paths, specs }`, with `specs` keyed by section slug. Each section reads `paths` plus its own entry. A test holds the CLI's and the template's declarations of the file to one shape, as it does for `portal.config.json`. - **Tidy-ups:** - the samples warnings live together in `src/prompts/portal/code-samples.ts`; - `PortalSource.sharedEndpoints` goes, since the placed samples work out the shared operations. ## What it prints Without `specs`, the warning reads as before but prints after the samples arrive: ``` ▲ More than one API definition declares this operation, so the portal shows no SDK sample on it: │ • 'GET /status': 'spec/alpha/alpha.json' and 'spec/beta/beta.json' ``` A sample filed under a spec that declares no such operation: ``` ▲ No operation in 'spec/orders/openapi.yaml' takes the code samples for POST /refunds. ``` Samples filed under a file the portal reads no API definition from: ``` ▲ No operation in 'spec/inventory/collection.json' takes the code samples for GET /status, GET /stock. ``` ## Testing - `pnpm test` with `APIMATIC_E2E=1`, as CI runs it: 2054 passing, ESLint clean. - **Unit:** - placing samples with and without `specs`, and refusing a malformed `specs`; - exact matching: `./orders/openapi.yaml`, `orders\openapi.yaml`, `Orders/openapi.yaml` and the folder `orders` match nothing, and a spec in a nested folder matches; - both warnings, the file no spec is read from among them, and the template reading `paths` plus its section's entry, including a section named `constructor`. - **End to end:** - A new build of the merged fixture with its samples filed by spec shows each API's own call on both `GET /status` pages. - That build fails when the template is made to ignore `specs`. - The existing build without `specs` still shows no SDK sample on either `/status` page. - **Against production:** a real `portal generate` of the two-spec fixture. Production files have no `specs` yet, so the result matches #435's: - the warning names `GET /status` with both specs; - neither status page carries an SDK sample; - the other two pages carry their own calls. ## Not in this PR - **Nothing changes for users until the platform sends `specs`.** The backend change is tracked in apimatic-io issue 2298. - **An operation the platform folds into an identical one from an earlier spec** is filed under the earlier spec only, so the later spec's page shows no SDK sample. The fix is on the backend. - **A merged folder holding another API format beside its OpenAPI document,** such as a Postman collection that sorts first, gets its SDK built from that other file. The warning above names the file; the CLI should refuse such a folder (apimatic-io issue 2307). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…atic/ folder (#457) `portal generate`, `portal serve` (and so `quickstart`), `sdk generate` (and so `sdk publish`) and `plugin generate` no longer upload `src/static/` with the build. Nothing on the server reads it, and the portal build still copies it from disk. `content/` is still uploaded. A project whose `static/` folder made the upload too large, such as one with a few large GIFs, used to fail with "An unexpected error occurred". It now generates. ## What changed - **One build upload for all three commands.** `ProjectContext` makes it: `buildZip` for the portal and the SDK, and `pluginBuildZip` for the plugin, which also narrows the copy's `languages`. Each copies `src/` to a temporary folder without `static/`, then zips the copy. So a large `static/` is no longer copied to disk either. - **`static/` is matched in any letter case.** On Windows and macOS the portal build reads a `Static/` folder as `static/`, so that folder is left out too. - **The copy holds what links point to.** A linked folder in `src/` used to fail every upload, and a relative file link broke in the copy that `sdk generate` and `plugin generate` made. Both are now uploaded as what they point to, the way the portal build reads them. - **A build that can't be prepared says why.** All three commands now report "'…/src' could not be zipped for upload: <reason>", for example when a file is locked. Before, `portal generate` and `portal serve` showed "An unexpected error occurred, please try again later", and `sdk generate` and `plugin generate` crashed with a raw `EBUSY` error. No partial copy is left behind in the temporary folder. - **The portal's build is sent like the SDK and plugin builds:** as a file named by a random ID, of type `application/octet-stream`, rather than `build.zip` / `application/zip`. Production accepts it. ## How it was verified - Tests pin each part: the folders left out (any case, top level only), the links followed, a failed copy reported only once the copy has stopped, and the upload contents of each command. Each was checked by breaking the code and seeing a test fail. - The full suite passes with `APIMATIC_E2E=1`. - Real runs against production, against 2.0.0: | Project | 2.0.0 | This branch | |---|---|---| | 23 MB in `static/`: `portal generate`, `sdk generate`, `plugin generate` | "An unexpected error occurred" | all three succeed; `portal serve` serves the files | | 22 MB in `Static/`: `portal generate` | not run | succeeds, and the files are published | | A locked file in `src/` | portal: generic message; sdk and plugin: raw `EBUSY` crash | all three name the file and the reason | | A small project with `static/`: `plugin generate` | 69 files | byte-identical, 69 files | ## Known edge A link inside `src/` that points back at `src/` or a folder above it is followed about 63 levels deep before the copy fails with `ELOOP`. That failure is reported with the same message. Before, such a link failed straight away. A clearer message for an upload that is still too large follows separately. Refs apimatic/apimatic-io#2316 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#455) Follows up the `oclif readme` note in #453. Tracked in apimatic-io issue 2315. ## The problem The README, which npm shows on the package page, still carries 1.3.1: - The usage block shows `apimatic --version` printing `@apimatic/cli/1.3.1`. - The 13 "See code" links point at `blob/v1.3.1/`, the 1.x source of each command. - The License badge links `blob/master/package.json`, which is a 404: `master` holds the old Python CLI. `pnpm readme` couldn't repair it. Since #453 it writes `blob/v0.0.0-semantically-released/` links, and on the CRLF README it adds a second usage block and a second commands block instead of replacing them. ## What changes - **LF README.** `README.md` is stored with LF endings, and a new `.gitattributes` keeps it LF on every checkout. The first commit is that conversion alone, so the Files tab shows the whole README as changed; the other commits have the real changes. - **Links.** `oclif.repositoryPrefix` in `package.json` makes `pnpm readme` link each command's source on `dev`, where every command exists. `prepack` now runs `oclif readme` too, so the README packed for npm links the release's own tag, which semantic-release pushes before it publishes. The plugin-autocomplete and plugin-help links still point at those plugins' own repositories. - **Usage block.** The version line and the `<!-- usage -->` markers go, so `pnpm readme` no longer rewrites the block. - **License badge.** It links `blob/main/LICENSE`. - The commands section is regenerated, which re-wraps two lines of the `plugin generate` description. A `docs:` change makes no release, so npm shows this README from the next release. ## Checked - `README.md` has no `1.3.1`, no `apimatic-cli/blob/v` and no `blob/master`. All 13 linked files exist on `dev`, and `LICENSE` on `main`. - `pnpm build && pnpm readme` leaves the README unchanged, with one commands block and no usage block. - `npm version 2.1.0 --no-git-tag-version && npm pack` packs a README whose 13 links point at `blob/v2.1.0/` and which otherwise matches the committed one; `2.1.0-beta.1` gives `blob/v2.1.0-beta.1/`. At the placeholder version, `pnpm pack` leaves the README unchanged. - With the platform faked as Linux and `CI` set, as in the release job, `oclif manifest && oclif readme` writes the committed README byte for byte. - A fresh clone checks the README out with LF under `core.autocrlf` `true`, `false` and `input`. ## Open PRs that edit the README - **#438** merges cleanly with `git merge -X renormalize origin/dev`; a plain merge conflicts on the line endings. Its `portal copilot sync` link points at `blob/v1.3.1/`, so run `pnpm readme` after the merge. - **#445** still conflicts, even with `-X renormalize`, in the usage block and the 13 links. Keep `dev`'s side in each conflict, then run `pnpm readme`. - **#454**, stacked on #445, gets the same conflict and takes #445's resolution. ## Regenerating the README Run `pnpm readme` after `pnpm build`, with colour on and `COLUMNS` unset; `.ai/instructions.md` now says so. Our command examples carry colour codes, so oclif leaves them as written. With colour off, every example gains a `$ ` prefix. `pnpm build` also deletes any `oclif.manifest.json`, whose examples `oclif readme` would otherwise use. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary
The README's install line is now `npm install -g @apimatic/cli@2`. The
Requirements paragraph now explains why the major is pinned.
## Why
The README said npm "only warns" on a Node older than 24, so the install
succeeds and the CLI then refuses to run. That is true for `@2`, but not
for the bare command the README showed:
- 2.0.0 declares `engines.node >=24.0.0`, and 1.5.0 declares `>=20.0.0`.
- When `latest` fails the running Node's engines check, npm (10.8.2 and
later) skips it and installs the newest release that passes, which is
1.5.0.
- npm prints no warning, and the `init` hook's Node check never runs
because v2 was never installed.
I reproduced this with the official Node 22.23.2 binary and its bundled
npm 10.9.8, installing into a throwaway prefix:
| Command | Result on Node 22.23.2 |
|---|---|
| `npm install -g @apimatic/cli` | Installs **1.5.0** with no warning;
`apimatic --version` → `@apimatic/cli/1.5.0 win32-x64 node-v22.23.2` |
| `npm install -g @apimatic/cli@2` | `npm warn EBADENGINE Unsupported
engine … required: { node: '>=24.0.0' }`, installs 2.0.0, then every
command exits 1 with *"The APIMatic CLI needs Node >=24.0.0; this is
Node 22.23.2. Upgrade Node … and reinstall the CLI."* |
Deprecating 1.x wouldn't change npm's pick; it would only add a warning.
A 2026-10-28 signup on Node 22.23.2 generated SDKs and a portal with
1.5.0 this way.
## Not changed
- `apimatic.schema.json`'s `$id`, `APIMATIC_SCHEMA_URL` (the `$schema`
the scaffold writes) and the test fixtures already point at
`https://cdn.jsdelivr.net/npm/@apimatic/cli@2/…`.
- The `init` hook's comment ("npm and pnpm only warn…") describes a
pinned or local install, where it holds.
Companion PRs pin the same command in the platform app, the skills repo
and apimatic-docs. A separate PR lowers the engine floor to Node 22.12.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary The CLI runs on **Node 22.14 or newer** again. `engines.node` goes from `>=24.0.0` to `>=22.14.0`, the test matrix adds Node 22.14.0 and the newest 22.x, and `@types/node` is pinned to exactly 22.14.1 to match the floor. ## Why - **The 24 floor is policy, not a requirement.** #347 raised it because "Node 22 reaches end of life on 2027-04-30, inside the supported life of the next major". It names no API or dependency that needs Node 24. The CLI itself needs 22.12, which #343 set for the local Fumadocs/TanStack Start portal build (Vite needs `^20.19.0 || >=22.12.0`). The floor is 22.14 because the repo's own toolchain needs it: pnpm 11 declares `>=22.13` and semantic-release 25 `^22.14.0 || >=24.10.0`. 22.14 is the oldest Node the CLI can also be installed, built, tested and released on. - **Node 22 is common among real users.** In the last 90 days, 13 of the 40 external users who ran the CLI locally did so on Node 22. - **On Node 22, v2 is out of reach:** - A bare `npm install -g @apimatic/cli` silently installs **CLI v1 (1.5.0)**, because npm skips a `latest` release whose `engines` the running Node fails. - A pinned `@2` installs v2, which then refuses to run. - A 2026-10-28 signup on Node 22.23.2 generated SDKs and a portal with 1.5.0 this way. - **What this fixes:** with the floor at 22.14, both commands give v2 on Node 22.14+. Node 20 and 22.0–22.13 still resolve a bare install to 1.5.0. That's why the companion PRs pin `@apimatic/cli@2` in every install instruction (README #461, the platform app, skills and apimatic-docs). ## Changes | File | Change | |---|---| | `package.json` | `engines.node`: `>=24.0.0` → `>=22.14.0`. The `init` hook reads it, so the runtime gate follows. | | `package.json`, `pnpm-workspace.yaml`, `pnpm-lock.yaml` | `@types/node` `^24.13.4` → exactly `22.14.1`, the types for the 22.14 floor itself, and an override `'@types/node': $@types/node` that resolves every package to that one copy. Before, `@types/fs-extra`, `@types/adm-zip`, `@types/unzipper`, `@types/yazl` and `@inquirer/core` pulled in 24.13.4 and 22.19.18 as well. This follows #347's rule that the types describe the floor runtime, so the compiler rejects any Node API added after 22.14, including ones backported later in the 22 line such as `process.execve` (22.15). The lockfile changes only `@types/node` and `undici-types`. | | `tsconfig.json` | `lib` drops `dom`. The source compiles without it. It declared browser globals Node 22 lacks, which compiled and would then throw `ReferenceError` on 22: `URLPattern` and `CloseEvent` (Node 24), and `localStorage`, `sessionStorage`, `Storage` and `ErrorEvent` (Node 26). Every 22.x from 22.12 to 22.23.4 has the same set of these globals, so no 22.x floor would make any of them safe. | | `.github/workflows/test.yml` | Matrix `node: ['22.14.0', '22', '24', '26']`. The first entry is the floor itself, so a dependency or API that needs a later 22 release fails there. `'22'` is the newest 22.x, where most Node 22 users are. Install runs with `--engine-strict`, so a package whose `engines` excludes the job's Node fails the job instead of printing a warning. A new step runs `node bin/run.js --version` after the build; it goes through the `init` hook, so a floor that refuses the job's Node fails CI. The jobs run with `APIMATIC_E2E=1`, so the real portal build runs on Node 22.14.0 on Linux, Windows and macOS. | | `README.md` | "Node.js 24 or newer" → "Node.js 22.14 or newer", keeping #461's `@2` wording. | | `test/infrastructure/services/plugin-service.test.ts` | The hand-rolled `drain` helper is replaced by `text()` from `node:stream/consumers`. `@types/node` 22.14.x has no `Buffer.from` overload for the `string \| Buffer` chunk the helper passed, so it stopped type-checking. | `release.yml`, `pull-requests.yml` and `portal_tests.yml` stay on Node 24. Release needs npm ≥ 11.5.1 for trusted publishing, and the other two are single-version jobs. ## Verification The local runs used the official **Node 22.14.0** binary and the standalone pnpm 11.0.8 that CI installs: - [x] `tsc` build against `@types/node` 22.14.1 without the `dom` lib: clean. - [x] `tsc -p test/tsconfig.json`: clean. - [x] Full suite with `APIMATIC_E2E=1`: **2080 passing**, 1 pending, 0 failing, including **78** end-to-end portal builds and serves. This includes the guard that every portal-template dependency's `engines` covers `>=22.14.0` (`portal-project-service.test.ts`, "supports only Node versions every template dependency supports"). - [x] `eslint .`: clean. - [x] Engines gate: `node bin/run.js --version` exits 0 on Node 22.14.0 and 22.23.4. On 22.13.0 it exits 1 with "The APIMatic CLI needs Node >=22.14.0; this is Node 22.13.0." - [x] `--engine-strict`: a fresh install of these manifests passes on Node 22.14.0. On Node 22.13.0, with `engines` lowered to `>=22.12.0` so only dependencies are checked, it fails on `semantic-release@25.0.3` with the flag and passes without it. This shows the standalone pnpm checks against the Node on `PATH`, not the one it bundles. - [x] Every package in `pnpm-lock.yaml` accepts Node 22.14.0, 22.23.4, 24.22.2 and 26.13.0. - [x] CI on Node 22.14.0, 22.23.4 (the newest 22.x), 24.22.1 and 26.13.0 for Linux, macOS and Windows, E2E included: **2076 passing** on Linux and macOS (5 Windows-only tests pending) and **2081** on Windows, 0 failing. Every job installed with `--engine-strict`. Every job's gate step printed that job's own Node, `node-v22.14.0` on the floor jobs. ## Trade-off This is the cost #347 was avoiding: v2 now supports a runtime that reaches end of life on 2027-04-30. When that happens, dropping Node 22 in a 2.x minor is low-risk once installs are pinned to `@2`. npm then installs the newest 2.x that still supports Node 22, not v1. ## Follow-ups after release - Replace "Requires Node.js 24.0.0 or later" in the platform app's setup and transform steps with 22.14. - Do the same for the "Node.js v24 or later" prerequisites in apimatic-docs v4 and the skills' `node --version` checks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
mrafnadeem-apimatic
requested review from
Shield-Jaguar and
saeedjamshaid
as code owners
November 2, 2026 11:38
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Promotes dev to beta, expected to publish 2.1.0-beta.1 to the npm
betadist-tag as a GitHub prerelease. The run commits nothing back to beta; the tag goes on this merge commit. dev already contains main's 2.0.0 merge, so the version continues from v2.0.0.Merge with Create a merge commit.
What releases
<img>in an .mdx page from beside the page and under a path (fix(portal): load an <img> in an .mdx page from beside the page and under a path #456)#453, #455 and #461 are
choreanddocscommits and stay out of the notes.After the merge
package.json'sversionto0.0.0-semantically-released. Check thatnpm view @apimatic/cli dist-tagsshowsbeta: 2.1.0-beta.1and thatnpx @apimatic/cli@beta --versionreports 2.1.0-beta.1, not the placeholder.🤖 Generated with Claude Code