@postman/sdk-config 0.1.1 → 0.2.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/README.md +29 -12
- package/dist/index.cjs +284 -139
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +277 -140
- package/dist/index.js.map +1 -1
- package/dist/sdk-config/index.cjs +281 -109
- package/dist/sdk-config/index.cjs.map +1 -1
- package/dist/sdk-config/index.d.cts +2 -2
- package/dist/sdk-config/index.d.ts +2 -2
- package/dist/sdk-config/index.js +276 -110
- package/dist/sdk-config/index.js.map +1 -1
- package/dist/sdk-config/v1/index.cjs +281 -109
- package/dist/sdk-config/v1/index.cjs.map +1 -1
- package/dist/sdk-config/v1/index.d.cts +6903 -289
- package/dist/sdk-config/v1/index.d.ts +6903 -289
- package/dist/sdk-config/v1/index.js +276 -110
- package/dist/sdk-config/v1/index.js.map +1 -1
- package/dist/sdk-config-ir/index.cjs +58 -24
- package/dist/sdk-config-ir/index.cjs.map +1 -1
- package/dist/sdk-config-ir/index.d.cts +2 -2
- package/dist/sdk-config-ir/index.d.ts +2 -2
- package/dist/sdk-config-ir/index.js +57 -25
- package/dist/sdk-config-ir/index.js.map +1 -1
- package/dist/sdk-config-ir/v1/index.cjs +58 -24
- package/dist/sdk-config-ir/v1/index.cjs.map +1 -1
- package/dist/sdk-config-ir/v1/index.d.cts +94 -15
- package/dist/sdk-config-ir/v1/index.d.ts +94 -15
- package/dist/sdk-config-ir/v1/index.js +57 -25
- package/dist/sdk-config-ir/v1/index.js.map +1 -1
- package/dist/{typescript-DK97815_.d.cts → typescript-DNqK3T3v.d.cts} +3 -0
- package/dist/{typescript-DK97815_.d.ts → typescript-DNqK3T3v.d.ts} +3 -0
- package/docs/releasing.md +114 -0
- package/package.json +1 -1
- package/src/sdk-config/v1/README.md +91 -23
- package/src/sdk-config-ir/v1/README.md +3 -2
|
@@ -239,6 +239,7 @@ declare const mcpGenerationConfigSchema: z.ZodObject<{
|
|
|
239
239
|
}>>;
|
|
240
240
|
bundle: z.ZodOptional<z.ZodBoolean>;
|
|
241
241
|
exportClassDefault: z.ZodOptional<z.ZodBoolean>;
|
|
242
|
+
namespaceExportName: z.ZodOptional<z.ZodString>;
|
|
242
243
|
allowCustomFetcher: z.ZodOptional<z.ZodBoolean>;
|
|
243
244
|
useBrandedStringAliases: z.ZodOptional<z.ZodBoolean>;
|
|
244
245
|
useLegacyExports: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -412,6 +413,8 @@ declare const typescriptGenerationConfigSchema: z.ZodObject<{
|
|
|
412
413
|
}>>;
|
|
413
414
|
bundle: z.ZodOptional<z.ZodBoolean>;
|
|
414
415
|
exportClassDefault: z.ZodOptional<z.ZodBoolean>;
|
|
416
|
+
/** Name of the top-level namespace export emitted by Fern-compatible TypeScript SDKs. */
|
|
417
|
+
namespaceExportName: z.ZodOptional<z.ZodString>;
|
|
415
418
|
allowCustomFetcher: z.ZodOptional<z.ZodBoolean>;
|
|
416
419
|
useBrandedStringAliases: z.ZodOptional<z.ZodBoolean>;
|
|
417
420
|
useLegacyExports: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Releasing `@postman/sdk-config`
|
|
2
|
+
|
|
3
|
+
Package publication is initiated with the repository's `npm run release` helper. The helper creates
|
|
4
|
+
and pushes a signed release tag, validates the release branches, and dispatches the **Package
|
|
5
|
+
Release** GitHub Actions workflow with the tag as its input.
|
|
6
|
+
|
|
7
|
+
The commands below use `1.1.0` as an example. Replace it consistently with the version being
|
|
8
|
+
released.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
- Node.js 24 or newer
|
|
13
|
+
- GitHub CLI (`gh`) authenticated for the repository
|
|
14
|
+
- Git configured to create and verify signed tags
|
|
15
|
+
- Permission to push release tags and run the **Package Release** workflow
|
|
16
|
+
- A clean Git worktree
|
|
17
|
+
|
|
18
|
+
Verify the local tools and signing configuration before starting:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
node --version
|
|
22
|
+
gh auth status
|
|
23
|
+
git config --get gpg.format
|
|
24
|
+
git config --get user.signingkey
|
|
25
|
+
git status --short
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 1. Prepare a release branch from `develop`
|
|
29
|
+
|
|
30
|
+
Start from an up-to-date `develop`, update the package version without creating a tag, and run the
|
|
31
|
+
complete check suite:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
git switch develop
|
|
35
|
+
git pull --ff-only origin develop
|
|
36
|
+
git switch -c release/v1.1.0
|
|
37
|
+
npm version 1.1.0 --no-git-tag-version
|
|
38
|
+
npm run check
|
|
39
|
+
git add package.json package-lock.json
|
|
40
|
+
git commit -m "release: v1.1.0"
|
|
41
|
+
git push -u origin release/v1.1.0
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Open a pull request from `release/v1.1.0` into `main`. Review the version change, wait for required
|
|
45
|
+
checks and approvals, and merge it. Do not create the release tag yet.
|
|
46
|
+
|
|
47
|
+
## 2. Merge the release back into `develop`
|
|
48
|
+
|
|
49
|
+
The release script requires the tagged `main` commit to be contained in both `main` and `develop`.
|
|
50
|
+
After the release pull request is merged, create a temporary synchronization branch from the
|
|
51
|
+
released `main` commit:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
git switch main
|
|
55
|
+
git pull --ff-only origin main
|
|
56
|
+
git switch -c chore/merge-main-after-v1.1.0
|
|
57
|
+
git push -u origin chore/merge-main-after-v1.1.0
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Open a pull request from `chore/merge-main-after-v1.1.0` into `develop`. Wait for its checks and
|
|
61
|
+
merge it using **Create a merge commit**. Do not squash or rebase this pull request: `develop` must
|
|
62
|
+
retain the released `main` commit in its ancestry for the release script's validation.
|
|
63
|
+
|
|
64
|
+
## 3. Run the release script from `main`
|
|
65
|
+
|
|
66
|
+
After the synchronization pull request is merged, update `main` and confirm the package version:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
git switch main
|
|
70
|
+
git pull --ff-only origin main
|
|
71
|
+
node -p "require('./package.json').version"
|
|
72
|
+
git status --short
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The version must be `1.1.0`, and the worktree must be clean. Run the release helper with the matching
|
|
76
|
+
tag:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
npm run release -- v1.1.0
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
For a new release, the helper:
|
|
83
|
+
|
|
84
|
+
1. Fetches the latest `main`, `develop`, and tags.
|
|
85
|
+
2. Confirms local `main` exactly matches `origin/main`.
|
|
86
|
+
3. Confirms `package.json` matches the requested tag.
|
|
87
|
+
4. Creates and verifies a signed, annotated tag.
|
|
88
|
+
5. Confirms the tagged commit is contained in both `origin/main` and `origin/develop`.
|
|
89
|
+
6. Pushes the tag without moving or replacing an existing tag.
|
|
90
|
+
7. Dispatches `.github/workflows/npm-publish.yml` with the tag as its input.
|
|
91
|
+
|
|
92
|
+
In GitHub, open **Actions** → **Package Release** and confirm the dispatched run succeeds. The
|
|
93
|
+
workflow validates the tag again before publishing the package.
|
|
94
|
+
|
|
95
|
+
## Verify the published package
|
|
96
|
+
|
|
97
|
+
After the workflow completes, verify the published version and npm distribution tags:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
npm view @postman/sdk-config@1.1.0 version
|
|
101
|
+
npm view @postman/sdk-config dist-tags
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Retry a failed publication
|
|
105
|
+
|
|
106
|
+
If publishing fails after the tag has been pushed, do not delete, move, or recreate the tag. Fix the
|
|
107
|
+
underlying problem, return to a clean worktree, and run the same command again:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
npm run release -- v1.1.0
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
When the remote tag already exists, the helper fetches and verifies that immutable tag and
|
|
114
|
+
redispatches the **Package Release** workflow without creating or pushing a replacement.
|
package/package.json
CHANGED
|
@@ -4,11 +4,30 @@
|
|
|
4
4
|
describes portable generation intent and uses the discriminator `schemaVersion: "sdk-config/v1"`.
|
|
5
5
|
|
|
6
6
|
```ts
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
import {
|
|
8
|
+
parseSdkConfigV1,
|
|
9
|
+
validateSdkConfigV1,
|
|
10
|
+
type SdkConfigV1,
|
|
11
|
+
type SdkConfigV1Document,
|
|
12
|
+
} from '@postman/sdk-config/sdk-config/v1';
|
|
13
|
+
|
|
14
|
+
// Validate a customer-authored document while preserving omitted properties.
|
|
15
|
+
const document: SdkConfigV1Document = validateSdkConfigV1(untrustedInput);
|
|
16
|
+
|
|
17
|
+
// Resolve domain defaults only when preparing a runtime configuration.
|
|
18
|
+
const resolved: SdkConfigV1 = parseSdkConfigV1(document);
|
|
10
19
|
```
|
|
11
20
|
|
|
21
|
+
`validateSdkConfigV1` is the correct boundary for persisted files, migration output, and request
|
|
22
|
+
transport. It validates the same schema as `parseSdkConfigV1` but returns the sparse authored
|
|
23
|
+
document, so omitted options remain omitted. `parseSdkConfigV1` is the runtime-resolution boundary:
|
|
24
|
+
it materializes shared domain defaults needed while expanding a target into `SdkConfigIrV1`.
|
|
25
|
+
|
|
26
|
+
This separation is intentional. A migration must not invent `sdkVersion`, `apiVersion`, or other
|
|
27
|
+
default-valued settings that were absent from the legacy Fern configuration. An explicit value—even
|
|
28
|
+
one equal to the current default—must remain distinguishable from omission so future default changes
|
|
29
|
+
do not silently alter customer intent.
|
|
30
|
+
|
|
12
31
|
### Convert a Fern generator group
|
|
13
32
|
|
|
14
33
|
The Fern CLI can convert its resolved in-memory generator group without serializing or reparsing
|
|
@@ -20,6 +39,9 @@ import { mapFernConfigToSdkConfigV1 } from '@postman/sdk-config/sdk-config/v1';
|
|
|
20
39
|
|
|
21
40
|
const { sdkConfig, unsupportedFields } = mapFernConfigToSdkConfigV1({
|
|
22
41
|
apiName: definition.rootApiFile.contents.name,
|
|
42
|
+
source: {
|
|
43
|
+
specs: [{ id: 'payments', type: 'openapi', path: './openapi.yml' }],
|
|
44
|
+
},
|
|
23
45
|
apiVersion: definition.specVersion,
|
|
24
46
|
sdkVersion,
|
|
25
47
|
group: {
|
|
@@ -35,28 +57,39 @@ representation are returned in `unsupportedFields`; each issue includes a code,
|
|
|
35
57
|
severity, reason, suggested manual action, and the SDK Config destination when one exists.
|
|
36
58
|
`FernConfigMappingError.issues` uses the same structure for missing information and other fatal
|
|
37
59
|
cases. Generation must not recover omitted values from legacy configuration. Differing
|
|
38
|
-
target-specific values
|
|
39
|
-
|
|
40
|
-
|
|
60
|
+
target-specific values are retained as sparse target overrides when the public shape can represent
|
|
61
|
+
them. Optional `api` enrichment may be supplied after Fern's definition or IR has already been
|
|
62
|
+
lowered into the public API shape. Credentials and signing material remain outside SDK Config; the
|
|
63
|
+
mapper reports one target-level diagnostic when a Fern output contains them without logging their
|
|
64
|
+
values.
|
|
41
65
|
|
|
42
66
|
## Contract boundaries
|
|
43
67
|
|
|
44
68
|
`SdkConfigV1` is distinct from both existing configuration contracts:
|
|
45
69
|
|
|
46
|
-
- `SdkConfigV1` is customer-facing, may contain multiple one-language targets, and
|
|
47
|
-
the
|
|
48
|
-
|
|
70
|
+
- `SdkConfigV1` is customer-facing, may contain multiple one-language targets, and explicitly names
|
|
71
|
+
the local paths or HTTP(S) URLs of the API specifications it configures. A source may be one spec
|
|
72
|
+
or an ordered multi-spec set, with optional namespaces, overlays, overrides, and API import
|
|
73
|
+
settings.
|
|
49
74
|
- `SdkConfigIrV1` is the normalized, single-target internal input consumed by sdk-gen-core. A server
|
|
50
|
-
expands one `SdkConfigV1` into one IR document per target
|
|
51
|
-
|
|
75
|
+
expands one `SdkConfigV1` into one IR document per target, uploads the declared source files, and
|
|
76
|
+
replaces customer paths with internal `specUrl` values without changing the IR shape.
|
|
52
77
|
- The legacy Postman configuration (`BuildParameters`) is an older producer-specific input. It is
|
|
53
78
|
not accepted by `parseSdkConfigV1`; legacy translators normalize it independently.
|
|
54
79
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
80
|
+
Each public source contains exactly one customer-owned locator: `path` for a local file or `url` for
|
|
81
|
+
an HTTP(S) resource. A generation client must materialize the selected resource and upload the exact
|
|
82
|
+
bytes for the build; the server replaces the customer locator with an internal signed `specUrl` in
|
|
83
|
+
SDK Config IR. Customer URLs never become generator fetch URLs. Signed URLs, S3 locations, and
|
|
84
|
+
server-generated artifact metadata are not valid public locators. The public schema deliberately has
|
|
85
|
+
no `compatibility`, source-origin, artifact ID, credential-resolution, or server-generated
|
|
86
|
+
publishing control fields. Unknown fields are rejected at every object boundary. Portable API,
|
|
87
|
+
client, documentation, package, source settings, and language field schemas come from a neutral
|
|
88
|
+
shared domain layer to prevent drift; the public and internal envelopes and their operational
|
|
89
|
+
extensions remain separate explicit allowlists.
|
|
90
|
+
|
|
91
|
+
Source `path`, `overlays`, and `overrides` values must be relative paths without parent-directory
|
|
92
|
+
segments. Absolute paths and `..` traversal are rejected at validation time.
|
|
60
93
|
|
|
61
94
|
## Shape
|
|
62
95
|
|
|
@@ -65,17 +98,26 @@ internal envelopes and their operational extensions remain separate explicit all
|
|
|
65
98
|
"schemaVersion": "sdk-config/v1",
|
|
66
99
|
"sdkName": "Acme SDK",
|
|
67
100
|
"sdkVersion": "1.0.0",
|
|
101
|
+
"source": {
|
|
102
|
+
"specs": [{ "id": "payments", "type": "openapi", "url": "https://example.com/openapi.yml" }]
|
|
103
|
+
},
|
|
68
104
|
"api": {},
|
|
69
105
|
"client": {},
|
|
70
106
|
"package": { "description": "Acme API SDK" },
|
|
71
107
|
"output": { "delivery": "zip" },
|
|
72
108
|
"docs": {},
|
|
73
|
-
"generation": {
|
|
109
|
+
"generation": {
|
|
110
|
+
"includeWatermark": true,
|
|
111
|
+
"naming": { "smartCasing": true, "smartCasingDigitWordBoundary": false }
|
|
112
|
+
},
|
|
74
113
|
"targets": [
|
|
75
114
|
{
|
|
76
115
|
"language": "typescript",
|
|
77
116
|
"package": { "packageName": "@acme/sdk" },
|
|
78
|
-
"generation": {
|
|
117
|
+
"generation": {
|
|
118
|
+
"packageManager": "pnpm",
|
|
119
|
+
"namespaceExportName": "AcmeSDK"
|
|
120
|
+
}
|
|
79
121
|
},
|
|
80
122
|
{
|
|
81
123
|
"language": "python",
|
|
@@ -92,6 +134,20 @@ Each target has exactly one `language`. A language may occur only once, so both
|
|
|
92
134
|
targets and differing targets that conflict on the same language are rejected. `generatorVersion`
|
|
93
135
|
is an optional target-only exact semantic version.
|
|
94
136
|
|
|
137
|
+
Field placement follows ownership rather than whichever Fern generator happens to appear first:
|
|
138
|
+
|
|
139
|
+
- API configuration and API version are global.
|
|
140
|
+
- Client, documentation, and common generation settings are global when identical across every
|
|
141
|
+
target; differing values become sparse target overrides.
|
|
142
|
+
- Package identity, output delivery, publication, repositories, generator version, and
|
|
143
|
+
language-specific generation settings remain on their target.
|
|
144
|
+
- SDK name and version use a global baseline with optional target overrides.
|
|
145
|
+
|
|
146
|
+
The root `output` is therefore optional. It is useful as an explicitly authored baseline, but every
|
|
147
|
+
target must have an effective output either from that baseline or from its own `output` block. Fern
|
|
148
|
+
migration writes output directly on each target because repositories and publication registries are
|
|
149
|
+
properties of the generated language artifact.
|
|
150
|
+
|
|
95
151
|
## Supported languages
|
|
96
152
|
|
|
97
153
|
SdkConfig v1 is language-agnostic across every sdk-gen-core target available when this contract was
|
|
@@ -99,7 +155,7 @@ defined. Each language has an explicitly allowlisted `generation` shape:
|
|
|
99
155
|
|
|
100
156
|
| Language | `language` value | Representative target setting |
|
|
101
157
|
| ---------- | ---------------- | ----------------------------- |
|
|
102
|
-
| TypeScript | `typescript` | `
|
|
158
|
+
| TypeScript | `typescript` | `namespaceExportName` |
|
|
103
159
|
| Python | `python` | `pythonVersion` |
|
|
104
160
|
| Java | `java` | `includeKotlinSnippets` |
|
|
105
161
|
| Kotlin | `kotlin` | `asyncStyle` |
|
|
@@ -122,14 +178,26 @@ When a server expands the public config into single-target IR documents, it appl
|
|
|
122
178
|
|
|
123
179
|
| Configuration | Rule |
|
|
124
180
|
| ----------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
125
|
-
| `api
|
|
126
|
-
|
|
|
127
|
-
|
|
|
181
|
+
| `api` | Shared unchanged by every target; no target override exists. |
|
|
182
|
+
| `client`, `docs` | Sparse target properties recursively override root properties; omitted properties inherit. Arrays replace. |
|
|
183
|
+
| Root `generation` | Shared generation behavior inherited by every target. |
|
|
184
|
+
| Target `generation` | Sparse common generation properties override root values; language-specific properties configure that target. |
|
|
128
185
|
| `sdkName`, `sdkVersion` | A target value wins; otherwise the root value is inherited. |
|
|
129
186
|
| `package` | Target properties override root properties; omitted properties inherit. Arrays replace rather than concatenate. |
|
|
130
|
-
| `output` |
|
|
187
|
+
| `output` | An optional root baseline is inherited; a target block replaces it completely. Every target must resolve one. |
|
|
131
188
|
| `apiVersion` | Shared unchanged by every target. |
|
|
132
189
|
|
|
190
|
+
Target `client`, `docs`, and common `generation` blocks are intentionally sparse. This allows one
|
|
191
|
+
multi-language document to retain a shared baseline while expressing a Fern setting that differs
|
|
192
|
+
between generators—for example, a Python-specific client name. Nested objects inherit recursively,
|
|
193
|
+
while an explicitly supplied array replaces the inherited array.
|
|
194
|
+
|
|
195
|
+
An integration may also supply operational values at generation time. Those request values take
|
|
196
|
+
precedence over the persisted SDK Config for fields the integration exposes, such as SDK name,
|
|
197
|
+
SDK version, API version, package settings, generator version, and output intent. The SDK Config
|
|
198
|
+
continues to provide every field that the request does not override. Schema/domain defaults are
|
|
199
|
+
applied only after this merge, when the single-target `SdkConfigIrV1` is parsed.
|
|
200
|
+
|
|
133
201
|
Package publication requirements are validated after applying package and output precedence. For
|
|
134
202
|
example, a TypeScript target publishing to npm may inherit a root `packageName`, while a Python
|
|
135
203
|
target must replace an inherited npm output with a PyPI-compatible output.
|
|
@@ -209,6 +209,7 @@ audited on 2026-07-17. Counts guide the initial contract; they are not a permane
|
|
|
209
209
|
| generator `inlineFileProperties`, `inline-file-properties` | `client.filePropertyStyle` | 1-3 per language |
|
|
210
210
|
| `inline_request_params` | `client.requestParameterStyle` | 6 Python |
|
|
211
211
|
| `customPagerName`, `custom-pager-name`, `custom_pager_name` | `generation.naming.pagerName` | 2-5 per language |
|
|
212
|
+
| `smart-casing`, `smart-casing-digit-word-boundary` | `generation.naming` | Preserved only when explicitly set. |
|
|
212
213
|
| timeout aliases in seconds or milliseconds | `client.timeoutMs` | Translator converts units. |
|
|
213
214
|
| `skipResponseValidation`, Python `skip_validation` | `client.responseValidation` | Inverted; 12 TS, 8 Python |
|
|
214
215
|
| `useDefaultRequestParameterValues` aliases | `client.useDefaultRequestParameterValues` | 1 |
|
|
@@ -281,10 +282,10 @@ Only options that remain language-specific stay in `generation.language`.
|
|
|
281
282
|
|
|
282
283
|
| Language | Fern fields retained in language config | Shared mappings lifted out |
|
|
283
284
|
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
284
|
-
| TypeScript | `packageManager` (1), `testFramework` (2), `allowCustomFetcher` (13), branded aliases (1), legacy exports (1), `useBigInt`, and positive `serdeLayer` from `noSerdeLayer` (8)
|
|
285
|
+
| TypeScript | `packageManager` (1), `testFramework` (2), `namespaceExportName`, `allowCustomFetcher` (13), branded aliases (1), legacy exports (1), `useBigInt`, and positive `serdeLayer` from `noSerdeLayer` (8) | Namespace, validation, inline types, dependencies, wire tests, streams, WebSockets, pager/client names |
|
|
285
286
|
| Python | Python/Pydantic versions, client filenames (13), Pydantic compatibility, frozen models (1), required optionals (2), union naming (1), field aliases (3), always-initialize optionals, TypedDict requests (3) | Package/module names, enum form, extra fields, response validation, request style, dependencies, timeout, layout, wire tests, WebSockets |
|
|
286
287
|
| Java/Kotlin | Package layout (3), local dates (2), optional-nullable collapse (2), Gradle settings (7), and JVM async-client style | Maven identity, namespace, names, forward-compatible enums, inline properties, dependencies, pager, wire tests |
|
|
287
|
-
| Go | Legacy complex models, union version (3), legacy client options (1),
|
|
288
|
+
| Go | Legacy complex models, union version (3), legacy client options (1), and the fern root-client constructor name | Module/package identity, client name, environments, smart casing, inline properties, pager, wire tests |
|
|
288
289
|
| C# | Optional wrapper, simplified dictionaries (1), explicit namespaces (7), core namespace behavior (1), exception handler (5), and the experimental explicit-nullable-optional switch | NuGet identity, namespace, class/error names, pager, wire tests |
|
|
289
290
|
| PHP | Property access (2) and generated client interfaces (1) | Composer identity, namespace, client/pager names, request style, dependencies, wire tests |
|
|
290
291
|
| Ruby | Require paths (2) | Gem identity, client name, dependencies, pager, wire tests |
|