@postman/sdk-config 0.1.0 → 0.1.1

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 CHANGED
@@ -1,164 +1,162 @@
1
1
  # @postman/sdk-config
2
2
 
3
- Shared, runtime-validated public and internal configuration contracts for Postman's SDK generation
4
- pipeline.
3
+ Build and validate SDK Config documents for SDK Generation API requests.
5
4
 
6
- This package is the source of truth for the customer-facing `SdkConfig` and internal `SdkConfigIr`.
7
- It is intended for sdk-gen-core, sdk-gen-api, Postman and Fern CLIs, and translators that normalize
8
- producer-specific configuration before generation.
5
+ SDK Config describes what to generate: SDK identity, API behavior, client behavior, package
6
+ metadata, documentation, output, shared generation options, and one or more language targets. API
7
+ source files, authentication, idempotency, and transport metadata belong to the SDK Generation API
8
+ request rather than the SDK Config document.
9
9
 
10
10
  ## Install
11
11
 
12
- The package is configured as a restricted package in the `@postman` npm scope.
13
-
14
12
  ```sh
15
13
  npm install @postman/sdk-config
16
14
  ```
17
15
 
18
- ## Use
19
-
20
- Use `SdkConfigV1` for customer-authored, potentially multi-target generation configuration:
21
-
22
- ```ts
23
- import { parseSdkConfigV1, type SdkConfigV1 } from '@postman/sdk-config/sdk-config/v1';
16
+ Node.js 24 or newer is required. Both ESM and CommonJS are supported.
24
17
 
25
- const sdkConfig: SdkConfigV1 = parseSdkConfigV1(untrustedInput);
26
- ```
18
+ ## Create and validate an SDK Config
27
19
 
28
- Use `SdkConfigIrV1` only for the normalized, single-target internal generator contract:
20
+ Use the versioned entry point when creating an API payload. `parseSdkConfigV1` validates unknown
21
+ input, applies defaults, and returns the normalized `SdkConfigV1` type.
29
22
 
30
23
  ```ts
31
- import { parseSdkConfigIrV1, type SdkConfigIrV1 } from '@postman/sdk-config/sdk-config-ir/v1';
32
-
33
- const sdkConfigIr: SdkConfigIrV1 = parseSdkConfigIrV1(untrustedInput);
24
+ import {
25
+ parseSdkConfigV1,
26
+ type SdkConfigV1,
27
+ type SdkConfigV1Input,
28
+ } from '@postman/sdk-config/sdk-config/v1';
29
+
30
+ const input: SdkConfigV1Input = {
31
+ schemaVersion: 'sdk-config/v1',
32
+ sdkName: 'Example SDK',
33
+ sdkVersion: '1.0.0',
34
+ api: {},
35
+ client: { timeoutMs: 30_000 },
36
+ package: {},
37
+ output: { delivery: 'zip', fileName: 'example-typescript.zip' },
38
+ docs: { includeApiReference: true },
39
+ generation: { includeWatermark: true },
40
+ targets: [
41
+ {
42
+ language: 'typescript',
43
+ generatorVersion: '1.2.3',
44
+ package: { packageName: '@example/sdk' },
45
+ generation: { packageManager: 'pnpm', testFramework: 'vitest' },
46
+ },
47
+ ],
48
+ };
49
+
50
+ const sdkConfig: SdkConfigV1 = parseSdkConfigV1(input);
34
51
  ```
35
52
 
36
- The package also exposes `@postman/sdk-config`, `@postman/sdk-config/sdk-config`, and
37
- `@postman/sdk-config/sdk-config-ir` as convenient current-version entry points. Persisted payloads
38
- must still include the appropriate `schemaVersion`.
39
-
40
- `SdkConfigV1` does not accept source selection, server-owned fields, `SdkConfigIrV1`, or legacy
41
- Postman `BuildParameters`. See the [SDK Config v1 reference](src/sdk-config/v1/README.md) for the
42
- boundaries and target precedence rules.
43
-
44
- Both ESM `import` and CommonJS `require` consumers are supported.
45
-
46
- ## Project layout
47
-
48
- ```text
49
- src/
50
- sdk-config-domain/
51
- v1/ # Portable field schemas shared by public config and internal IR
52
- sdk-config/
53
- v1/ # Customer-facing multi-target schema and contract reference
54
- sdk-config-ir/
55
- v1/ # Versioned schema, inferred types, and contract reference
56
- tests/
57
- fixtures/
58
- sdk-config/v1/ # Canonical public configuration payloads
59
- sdk-config-ir/v1/ # Canonical portable payloads
60
- sdk-config/v1/ # Public contract and export tests
61
- sdk-config-ir/v1/ # Contract behavior tests
62
- docs/
63
- migration.md # sdk-gen-core adoption sequence
64
- ```
65
-
66
- ## Develop
53
+ For validation without throwing, use the exported schema:
67
54
 
68
- Requires Node.js 24 or newer. If you use nvm, run `nvm use` from the repository root.
55
+ ```ts
56
+ import { sdkConfigV1Schema } from '@postman/sdk-config/sdk-config/v1';
69
57
 
70
- ```sh
71
- npm install
72
- npm run check
73
- npm pack --dry-run
58
+ const result = sdkConfigV1Schema.safeParse(input);
59
+ if (!result.success) {
60
+ console.error(result.error.issues);
61
+ }
74
62
  ```
75
63
 
76
- `npm run check` verifies formatting, linting, TypeScript, tests, and the dual-format package build.
77
-
78
- ## Versioning and publishing
64
+ SDK Config objects are strict. Unknown fields, duplicate language targets, incompatible package
65
+ publication settings, and non-exact generator versions are rejected.
79
66
 
80
- - npm access is `restricted`; do not set package.json `private: true`, because npm would refuse to
81
- publish it.
82
- - Additive v1 fields require a package minor version and a consumer-first rollout because v1 uses
83
- strict runtime objects: an older consumer rejects fields it does not know.
84
- - Breaking wire changes get a new schema directory and discriminator such as `sdk-config/v2` or
85
- `sdk-config-ir/v2`.
86
- - Keep the previous version exported while consumers migrate.
67
+ ## Use SDK Config in an SDK Generation API request
87
68
 
88
- ### Manual release process
69
+ An SDK Generation API request combines three kinds of data:
89
70
 
90
- Release automation is intentionally deferred while the tagging and publishing process is reviewed
91
- with Postman's security team. Until that process is established, use the following manual release
92
- procedure. The commands use `1.1.0` as an example; replace it consistently with the version being
93
- released.
71
+ 1. Request metadata describing the API input and generation targets.
72
+ 2. A source archive containing the API definition files.
73
+ 3. One SDK Config JSON payload for each request target that uses `payloadKind: "sdk-config-v1"`.
94
74
 
95
- #### 1. Prepare a release branch from develop
75
+ The payload filename must match its target ID: `<targetId>.json`.
96
76
 
97
- Normal feature pull requests target `develop`. Start the release from an up-to-date `develop`
98
- branch, update the version without creating a tag, and run the complete check suite:
99
-
100
- ```sh
101
- git switch develop
102
- git pull --ff-only origin develop
103
- git switch -c release/v1.1.0
104
- npm version 1.1.0 --no-git-tag-version
105
- npm run check
106
- git add package.json package-lock.json
107
- git commit -m "release: v1.1.0"
108
- git push -u origin release/v1.1.0
77
+ ```ts
78
+ const targetId = 'typescript-sdk';
79
+ const request = {
80
+ protocolVersion: 2,
81
+ apiName: 'Example API',
82
+ idempotencyKey: crypto.randomUUID(),
83
+ apiInputs: [{ id: 'default', specIndexes: 'all' }],
84
+ targets: [
85
+ {
86
+ targetId,
87
+ apiInputId: 'default',
88
+ language: 'typescript',
89
+ sdk: {
90
+ name: sdkConfig.sdkName,
91
+ version: sdkConfig.sdkVersion,
92
+ ...(sdkConfig.apiVersion === undefined ? {} : { apiVersion: sdkConfig.apiVersion }),
93
+ },
94
+ fernGenerator: { id: 'typescript-generator', version: '1.2.3' },
95
+ payloadKind: 'sdk-config-v1',
96
+ package: sdkConfig.targets[0]?.package,
97
+ requestedOutput: { type: 'download' },
98
+ },
99
+ ],
100
+ };
101
+
102
+ const form = new FormData();
103
+ form.append('request', JSON.stringify(request));
104
+ form.append('sources', sourceArchive, 'sources.tar.gz');
105
+ form.append(
106
+ 'payloads',
107
+ new Blob([JSON.stringify(sdkConfig)], { type: 'application/json' }),
108
+ `${targetId}.json`,
109
+ );
110
+
111
+ const response = await fetch('https://api.example.com/sdk-generations', {
112
+ method: 'POST',
113
+ headers: { Authorization: `Bearer ${accessToken}` },
114
+ body: form,
115
+ });
109
116
  ```
110
117
 
111
- Open a pull request from `release/v1.1.0` into `main`. Review the version change, wait for required
112
- checks and approvals, and merge it. The release branch isolates the version bump and preserves the
113
- exact `develop` snapshot being reviewed, while work can continue independently on `develop`.
118
+ The endpoint URL, authentication scheme, source archive format, and response shape are defined by
119
+ the SDK Generation API provider.
114
120
 
115
- #### 2. Merge main back into develop
121
+ This request form supports downloaded archives. Its effective SDK Config output must be
122
+ `{ "delivery": "zip" }` without publication settings, and `requestedOutput` must be
123
+ `{ "type": "download" }`.
116
124
 
117
- The publishing workflow requires the tagged commit to be in the history of the repository's default
118
- branch, `develop`. After the release pull request is merged, create a synchronization branch from
119
- the latest `develop` and merge the released `main` into it:
125
+ ### Keep request targets consistent
120
126
 
121
- ```sh
122
- git fetch origin
123
- git switch -c chore/merge-main-after-v1.1.0 origin/develop
124
- git merge --no-ff origin/main -m "Merge main back to develop after v1.1.0"
125
- git push -u origin chore/merge-main-after-v1.1.0
126
- ```
127
+ For each request target, the API request and matching SDK Config target must agree on:
127
128
 
128
- Open a pull request from `chore/merge-main-after-v1.1.0` into `develop`, wait for its checks, and use
129
- **Create a merge commit** to merge it. Do not squash or rebase this pull request: the original
130
- `main` commit must remain in `develop`'s ancestry for the publishing workflow's validation. The
131
- temporary branch can then be deleted safely.
129
+ - `language`
130
+ - effective SDK name and version
131
+ - API version, when present
132
+ - generator version, when `generatorVersion` is present in SDK Config
133
+ - every package property included in the API request; the request may omit package properties
134
+ - ZIP output without publication settings, paired with a download request
132
135
 
133
- #### 3. Create the release tag from main
136
+ Root package properties are inherited by each target and overridden by target package properties.
137
+ A target output replaces the root output; it is not merged with it.
134
138
 
135
- After the synchronization pull request is merged, update your local `main` and verify that
136
- `package.json` contains the version you are about to tag:
139
+ ## Generation file paths
137
140
 
138
- ```sh
139
- git switch main
140
- git pull --ff-only origin main
141
- node -p "require('./package.json').version"
142
- ```
141
+ These SDK Config values are interpreted as file paths during generation:
143
142
 
144
- Create the signed tag and dispatch the **Package Release** workflow with the tag as its explicit
145
- input:
143
+ - `generation.customQueryPaths[]`
144
+ - `generation.workflows[].path`
145
+ - `generation.hooks.source.location` when `source.type` is `path`
146
+ - `generation.customCode.source.location` when `source.type` is `path`
146
147
 
147
- ```sh
148
- npm run release -- v1.1.0
149
- ```
148
+ Each value must be a relative path and cannot contain a `..` path segment. Absolute POSIX paths,
149
+ Windows drive paths, UNC paths, and parent-directory traversal are rejected during validation. URL
150
+ source locations are not treated as file paths.
151
+
152
+ ## Multiple targets
150
153
 
151
- The release script requires a clean, up-to-date `main`, verifies that the package version matches
152
- the tag and that the commit is already contained in `main` and `develop`, creates and verifies a
153
- signed, annotated tag, pushes it, and dispatches `.github/workflows/npm-publish.yml` with
154
- `tag=v1.1.0`. The workflow independently rechecks `main` ancestry before calling the shared
155
- publisher, which verifies `develop` ancestry and the tag signature. Explicit dispatch avoids
156
- duplicate publish runs and keeps retries tied to the immutable tag. In GitHub, open **Actions** →
157
- **Package Release** and confirm the dispatched run succeeds.
154
+ An SDK Config can describe several language targets. Shared `api`, `client`, `docs`, and generation
155
+ settings apply to every target. SDK identity, package metadata, output, and language-specific
156
+ generation settings can be overridden per target.
158
157
 
159
- If publishing fails after the tag has been created, do not delete, move, or recreate the tag. After
160
- the underlying problem is fixed, run the same command again. The script verifies and reuses the
161
- existing tag before dispatching another run. You can also use **Actions** → **Package Release** →
162
- **Run workflow** and enter the existing tag, such as `v1.1.0`.
158
+ Each language can appear only once. When sending a multi-target SDK Config to an SDK Generation API,
159
+ attach the config under each request target that should select its matching language configuration.
163
160
 
164
- See the [SDK Config IR v1 reference](src/sdk-config-ir/v1/README.md) for the complete contract.
161
+ Supported target languages are `typescript`, `python`, `java`, `kotlin`, `go`, `csharp`, `php`,
162
+ `ruby`, `rust`, `swift`, `cli`, `mcp`, and `terraform`.
package/dist/index.cjs CHANGED
@@ -9,6 +9,10 @@ var semver__default = /*#__PURE__*/_interopDefault(semver);
9
9
 
10
10
  // src/sdk-config-domain/v1/api.ts
11
11
  var nonEmptyStringSchema = zod.z.string().min(1);
12
+ var relativePathSchema = nonEmptyStringSchema.refine(
13
+ (value) => !/^(?:[\\/]|[A-Za-z]:)/.test(value) && !value.split(/[\\/]/).some((segment) => segment === ".."),
14
+ { message: "must be a relative path without parent directory segments" }
15
+ );
12
16
  var exactSemverSchema = zod.z.string().refine(
13
17
  (value) => {
14
18
  if (value.trim() !== value || !/^\d/.test(value)) {
@@ -253,7 +257,7 @@ var clientConfigSchema = zod.z.strictObject({
253
257
 
254
258
  // src/sdk-config/v1/client.ts
255
259
  var sdkConfigV1ClientConfigSchema = clientConfigSchema;
256
- var goModulePathSchema = nonEmptyStringSchema.regex(
260
+ var goModulePathSchema = relativePathSchema.regex(
257
261
  /^(?!.*(?:^|\/)\.{1,2}(?:\/|$))[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)+$/,
258
262
  "Go module path must be a slash-delimited path using letters, numbers, dots, dashes, underscores, or tildes"
259
263
  );
@@ -934,7 +938,7 @@ function outputDiagnostic(path, index) {
934
938
  };
935
939
  }
936
940
  var customerGenerationAssetSchema = zod.z.discriminatedUnion("type", [
937
- zod.z.strictObject({ type: zod.z.literal("path"), location: nonEmptyStringSchema }),
941
+ zod.z.strictObject({ type: zod.z.literal("path"), location: relativePathSchema }),
938
942
  zod.z.strictObject({ type: zod.z.literal("url"), location: nonEmptyStringSchema })
939
943
  ]);
940
944
  var hookDependencySchema = zod.z.strictObject({
@@ -955,7 +959,7 @@ var customCodeConfigSchema = zod.z.strictObject({
955
959
  protectedFiles: zod.z.array(nonEmptyStringSchema).optional()
956
960
  });
957
961
  var workflowConfigSchema = zod.z.strictObject({
958
- path: nonEmptyStringSchema,
962
+ path: relativePathSchema,
959
963
  outputName: nonEmptyStringSchema.optional()
960
964
  });
961
965
  var analyticsHeaderSchema = zod.z.union([
@@ -1032,7 +1036,7 @@ var sdkConfigV1GenerationConfigSchema = zod.z.strictObject({
1032
1036
  hooks: hooksConfigSchema.optional(),
1033
1037
  customCode: customCodeConfigSchema.optional(),
1034
1038
  workflows: zod.z.array(workflowConfigSchema).optional(),
1035
- customQueryPaths: zod.z.array(nonEmptyStringSchema).optional(),
1039
+ customQueryPaths: zod.z.array(relativePathSchema).optional(),
1036
1040
  analytics: analyticsConfigSchema.optional(),
1037
1041
  wireTests: wireTestsSchema.optional(),
1038
1042
  unitTests: unitTestsSchema.optional(),
@@ -2219,10 +2223,11 @@ var compatibilityConfigSchema = zod.z.strictObject({
2219
2223
  legacyInput: legacyInputSchema.optional(),
2220
2224
  unsupportedFields: zod.z.array(unsupportedFieldSchema).optional()
2221
2225
  });
2222
- var generationAssetSchema = zod.z.strictObject({
2223
- type: zod.z.enum(["path", "url", "artifact"]),
2224
- location: nonEmptyStringSchema
2225
- });
2226
+ var generationAssetSchema = zod.z.discriminatedUnion("type", [
2227
+ zod.z.strictObject({ type: zod.z.literal("path"), location: relativePathSchema }),
2228
+ zod.z.strictObject({ type: zod.z.literal("url"), location: nonEmptyStringSchema }),
2229
+ zod.z.strictObject({ type: zod.z.literal("artifact"), location: nonEmptyStringSchema })
2230
+ ]);
2226
2231
  var hookDependencySchema2 = zod.z.strictObject({
2227
2232
  name: nonEmptyStringSchema,
2228
2233
  version: nonEmptyStringSchema,
@@ -2242,7 +2247,7 @@ var customCodeConfigSchema2 = zod.z.strictObject({
2242
2247
  protectedFiles: zod.z.array(nonEmptyStringSchema).optional()
2243
2248
  });
2244
2249
  var workflowConfigSchema2 = zod.z.strictObject({
2245
- path: nonEmptyStringSchema,
2250
+ path: relativePathSchema,
2246
2251
  outputName: nonEmptyStringSchema.optional()
2247
2252
  });
2248
2253
  var analyticsHeaderSchema2 = zod.z.union([
@@ -2348,7 +2353,7 @@ var generationConfigSchema = zod.z.strictObject({
2348
2353
  hooks: hooksConfigSchema2.optional(),
2349
2354
  customCode: customCodeConfigSchema2.optional(),
2350
2355
  workflows: zod.z.array(workflowConfigSchema2).optional(),
2351
- customQueryPaths: zod.z.array(nonEmptyStringSchema).optional(),
2356
+ customQueryPaths: zod.z.array(relativePathSchema).optional(),
2352
2357
  analytics: analyticsConfigSchema2.optional(),
2353
2358
  wireTests: wireTestsSchema2.optional(),
2354
2359
  unitTests: unitTestsSchema2.optional(),
@@ -2708,6 +2713,7 @@ exports.publishRegistrySchema = publishRegistrySchema;
2708
2713
  exports.pythonGenerationConfigSchema = pythonGenerationConfigSchema;
2709
2714
  exports.readmeCustomSectionSchema = readmeCustomSectionSchema;
2710
2715
  exports.readmeEndpointSchema = readmeEndpointSchema;
2716
+ exports.relativePathSchema = relativePathSchema;
2711
2717
  exports.rubyGenerationConfigSchema = rubyGenerationConfigSchema;
2712
2718
  exports.rustGenerationConfigSchema = rustGenerationConfigSchema;
2713
2719
  exports.sdkConfigIrV1Schema = sdkConfigIrV1Schema;
@@ -2736,6 +2742,7 @@ exports.sdkConfigV1PublishRegistrySchema = sdkConfigV1PublishRegistrySchema;
2736
2742
  exports.sdkConfigV1PythonGenerationConfigSchema = pythonGenerationConfigSchema;
2737
2743
  exports.sdkConfigV1ReadmeCustomSectionSchema = sdkConfigV1ReadmeCustomSectionSchema;
2738
2744
  exports.sdkConfigV1ReadmeEndpointSchema = sdkConfigV1ReadmeEndpointSchema;
2745
+ exports.sdkConfigV1RelativePathSchema = relativePathSchema;
2739
2746
  exports.sdkConfigV1RubyGenerationConfigSchema = rubyGenerationConfigSchema;
2740
2747
  exports.sdkConfigV1RustGenerationConfigSchema = rustGenerationConfigSchema;
2741
2748
  exports.sdkConfigV1Schema = sdkConfigV1Schema;