@postman-cse/onboarding-bootstrap 2.4.0 → 2.5.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 CHANGED
@@ -6,7 +6,7 @@ Provisions a [Postman workspace](https://learning.postman.com/docs/collaborating
6
6
 
7
7
  Part of the [Postman API Onboarding suite](https://github.com/postman-cs/postman-api-onboarding-action).
8
8
 
9
- > **Standards-grounded assertion generation.** Every collection this action generates ships with executable contract tests compiled from your spec. For OpenAPI: operation mapping, status-code, `Content-Type`, response-header, request/response body, parameter, security-credential, and `Content-Length` checks, with JSON Schema (draft-07 / 2020-12) body validation, dialect-exclusive keyword rejection, and RFC-checked formats (RFC 3339 timestamps, RFC 4122 UUIDs, RFC 3986 URIs, and more). Layered on top: RFC 9110 status-code, framing, and field-syntax requirements, RFC 9457 `application/problem+json` error bodies with RFC 8259 encoding and RFC 8288 `Link` checks, RFC 6265 `Set-Cookie`, RFC 6797 HSTS and security headers, WHATWG Fetch CORS, RFC 9651 structured fields, RFC 9209 typed `Proxy-Status`, RFC 9421 message signatures, RFC 9530 body digests, `Accept` negotiation, media-type conventions (NDJSON, multipart boundaries, HAL, JSON:API), authentication-scheme credential grammar, preconditions and RFC 6902 / RFC 7386 patch bodies, `Deprecation`/`Sunset` advisories, and OpenAPI links/servers resolution. Beyond REST: canonical proto3 JSON well-known-type validation for gRPC, version-aware SOAP 1.1/1.2 media-type and Fault-status checks, GraphQL-over-HTTP media-type/status discipline, static AsyncAPI WebSocket / Socket.IO / MQTT message validation, and static MCP server-manifest contract checks. The full test inventory and the standard behind each check: [Generated assertions](docs/generated-assertions.md) and [Multi-Protocol Contract Assertions](docs/MULTIPROTOCOL-ASSERTIONS.md).
9
+ > **Standards-grounded assertion generation.** Every collection this action generates ships with executable contract tests compiled from your spec. For OpenAPI: operation mapping, status-code, `Content-Type`, response-header, request/response body, parameter, security-credential, and `Content-Length` checks, with JSON Schema (draft-07 / 2020-12) body validation, dialect-exclusive keyword rejection, and RFC-checked formats (RFC 3339 timestamps, RFC 4122 UUIDs, RFC 3986 URIs, and more). Layered on top: RFC 9110 status-code, framing, and field-syntax requirements, RFC 9457 `application/problem+json` error bodies with RFC 8259 encoding and RFC 8288 `Link` checks, RFC 6265 `Set-Cookie`, RFC 6797 HSTS and security headers, WHATWG Fetch CORS, RFC 9651 structured fields, RFC 9209 typed `Proxy-Status`, RFC 9421 message signatures, RFC 9530 body digests, `Accept` negotiation, media-type conventions (NDJSON, multipart boundaries, HAL, JSON:API), authentication-scheme credential grammar, preconditions and RFC 6902 / RFC 7386 patch bodies, `Deprecation`/`Sunset` advisories, and OpenAPI links/servers resolution. Beyond REST: canonical proto3 JSON well-known-type validation for gRPC with per-streamed-message shape checks and metadata/trailer wire-conformance, version-aware SOAP 1.1/1.2 media-type and Fault-status checks, GraphQL-over-HTTP media-type/status discipline, static AsyncAPI WebSocket / Socket.IO / MQTT message validation, and static MCP server-manifest contract checks. The full test inventory and the standard behind each check: [Generated assertions](docs/generated-assertions.md) and [Multi-Protocol Contract Assertions](docs/MULTIPROTOCOL-ASSERTIONS.md).
10
10
 
11
11
  ## Which action should I use?
12
12
 
package/dist/action.cjs CHANGED
@@ -297618,7 +297618,17 @@ function createGrpcScript(spec) {
297618
297618
  // reporters/cli/modules/grpc.ts:15-21.
297619
297619
  'var GRPC_STATUS = { 0: "OK", 1: "CANCELLED", 2: "UNKNOWN", 3: "INVALID_ARGUMENT", 4: "DEADLINE_EXCEEDED", 5: "NOT_FOUND", 6: "ALREADY_EXISTS", 7: "PERMISSION_DENIED", 8: "RESOURCE_EXHAUSTED", 9: "FAILED_PRECONDITION", 10: "ABORTED", 11: "OUT_OF_RANGE", 12: "UNIMPLEMENTED", 13: "INTERNAL", 14: "UNAVAILABLE", 15: "DATA_LOSS", 16: "UNAUTHENTICATED" };',
297620
297620
  'function grpcStatusName() { if (typeof pm.response.status === "string" && pm.response.status) return pm.response.status; return GRPC_STATUS[pm.response.code] || ("UNKNOWN(" + pm.response.code + ")"); }',
297621
- "function grpcMessage() { try { return pm.response.json(); } catch (error) { return undefined; } }",
297621
+ // Terminal message: pm.response.json() where the sandbox provides it,
297622
+ // falling back to the last received message in pm.response.messages (the
297623
+ // unified runtime's GRPCResponse exposes messages but no json()).
297624
+ "function grpcMessage() {",
297625
+ ' try { if (pm.response && typeof pm.response.json === "function") { var viaJson = pm.response.json(); if (viaJson !== undefined && viaJson !== null) return viaJson; } } catch (error) { /* fall back to messages */ }',
297626
+ " try {",
297627
+ " var list = pm.response && pm.response.messages;",
297628
+ ' if (list && typeof list.each === "function") { var last; list.each(function (member) { last = member && member.data !== undefined ? member.data : member; }); return last; }',
297629
+ " } catch (error) { return undefined; }",
297630
+ " return undefined;",
297631
+ "}",
297622
297632
  "function jsonTypeOf(value) {",
297623
297633
  ' if (value === null || value === undefined) return "null";',
297624
297634
  ' if (Array.isArray(value)) return "array";',
@@ -297769,9 +297779,38 @@ function createGrpcScript(spec) {
297769
297779
  ' if (set.length > 1) pm.expect.fail("gRPC response at " + path + " sets multiple members of a oneof: " + set.join(", "));',
297770
297780
  " });",
297771
297781
  "}",
297782
+ // Wire-conformance helpers for response metadata/trailers ({ key, value }
297783
+ // PropertyLists; each/has/one guarded so the script stays inert on runtimes
297784
+ // or harnesses that do not surface them).
297785
+ 'function grpcEachMeta(list, cb) { if (list && typeof list.each === "function") list.each(cb); }',
297786
+ 'function grpcMetaOne(list, key) { try { if (list && typeof list.has === "function" && list.has(key) && typeof list.one === "function") return list.one(key); } catch (error) { /* absent */ } return null; }',
297787
+ "function grpcCheckMetaPairs(list, label) {",
297788
+ " grpcEachMeta(list, function (entry) {",
297789
+ " if (!entry || entry.disabled) return;",
297790
+ ' var key = entry.key === undefined || entry.key === null ? "" : String(entry.key);',
297791
+ ' var value = entry.value === undefined || entry.value === null ? "" : String(entry.value);',
297792
+ ' if (!/^[0-9a-z_.-]+$/.test(key)) pm.expect.fail(label + " key " + JSON.stringify(key) + " must be a lowercase gRPC metadata key ([0-9a-z_.-])");',
297793
+ ' if (/-bin$/.test(key)) { if (!/^[A-Za-z0-9+/=]*\\s*$/.test(value)) pm.expect.fail(label + " " + key + " must carry base64 data but was " + JSON.stringify(value)); }',
297794
+ ' else if (!/^[\\x20-\\x7e]*$/.test(value)) pm.expect.fail(label + " " + key + " value must be printable ASCII (gRPC ASCII-Value)");',
297795
+ " });",
297796
+ "}",
297772
297797
  `pm.test('gRPC status is OK for ' + grpcSpec.methodPath, function () {`,
297773
297798
  ' pm.expect(pm.response.code, "gRPC call for " + grpcSpec.methodPath + " returned " + grpcStatusName() + " (" + pm.response.code + ")").to.eql(0);',
297774
297799
  "});",
297800
+ // Metadata/trailer wire conformance runs on every terminal status (error
297801
+ // statuses carry trailers too, so this is not gated on code === 0).
297802
+ `pm.test('gRPC response metadata and trailers conform to gRPC wire rules for ' + grpcSpec.methodPath, function () {`,
297803
+ ' grpcCheckMetaPairs(pm.response.metadata, "gRPC response metadata");',
297804
+ ' grpcCheckMetaPairs(pm.response.trailers, "gRPC response trailer");',
297805
+ ' var contentType = grpcMetaOne(pm.response.metadata, "content-type");',
297806
+ ' if (contentType && contentType.value !== undefined && contentType.value !== null && !/^application\\/grpc/.test(String(contentType.value))) pm.expect.fail("gRPC response content-type metadata must be application/grpc[+proto|+json] but was " + contentType.value);',
297807
+ ' var echoedStatus = grpcMetaOne(pm.response.trailers, "grpc-status");',
297808
+ " if (echoedStatus) {",
297809
+ " var echoedCode = Number(echoedStatus.value);",
297810
+ ' if (!Number.isInteger(echoedCode) || echoedCode < 0 || echoedCode > 16) pm.expect.fail("grpc-status trailer must be a canonical gRPC code 0-16 but was " + JSON.stringify(echoedStatus.value));',
297811
+ ' else if (echoedCode !== pm.response.code) pm.expect.fail("grpc-status trailer (" + echoedCode + ") disagrees with the reported status code (" + pm.response.code + ")");',
297812
+ " }",
297813
+ "});",
297775
297814
  // Terminal-response-message expectation. unary and client-streaming RPCs
297776
297815
  // return exactly one terminal response message; server/bidi streaming may
297777
297816
  // legitimately return ZERO messages on an OK stream, so no minimum is
@@ -297793,6 +297832,26 @@ function createGrpcScript(spec) {
297793
297832
  ' if (grpcSpec.responseShape) grpcCheckShape(message, grpcSpec.responseShape, grpcSpec.responseType + ".");',
297794
297833
  " if (grpcSpec.responseIsRpcStatus) grpcCheckRpcStatus(message, grpcSpec.responseType);",
297795
297834
  "});"
297835
+ ] : [],
297836
+ // Every streamed message is validated, not only the terminal one that
297837
+ // pm.response.json() returns; pm.response.messages is the full received
297838
+ // stream. Server/bidi only: for unary/client the single terminal message
297839
+ // is already covered above.
297840
+ ...(spec.stream === "server" || spec.stream === "bidi") && (spec.hasResponseShape || spec.responseIsRpcStatus) ? [
297841
+ `pm.test('gRPC streamed response messages each match ' + grpcSpec.responseType, function () {`,
297842
+ " if (pm.response.code !== 0) return;",
297843
+ " var list = pm.response.messages;",
297844
+ ' if (!list || typeof list.each !== "function") return;',
297845
+ " var messageIndex = 0;",
297846
+ " list.each(function (member) {",
297847
+ " var data = member && member.data !== undefined ? member.data : member;",
297848
+ ' var label = grpcSpec.responseType + "[message " + messageIndex + "]";',
297849
+ " messageIndex += 1;",
297850
+ ' if (jsonTypeOf(data) !== "object") { pm.expect.fail("gRPC streamed response " + label + " is not a decodable message object but " + jsonTypeOf(data)); return; }',
297851
+ ' if (grpcSpec.responseShape) grpcCheckShape(data, grpcSpec.responseShape, label + ".");',
297852
+ " if (grpcSpec.responseIsRpcStatus) grpcCheckRpcStatus(data, label);",
297853
+ " });",
297854
+ "});"
297796
297855
  ] : []
297797
297856
  ];
297798
297857
  }
package/dist/cli.cjs CHANGED
@@ -295936,7 +295936,17 @@ function createGrpcScript(spec) {
295936
295936
  // reporters/cli/modules/grpc.ts:15-21.
295937
295937
  'var GRPC_STATUS = { 0: "OK", 1: "CANCELLED", 2: "UNKNOWN", 3: "INVALID_ARGUMENT", 4: "DEADLINE_EXCEEDED", 5: "NOT_FOUND", 6: "ALREADY_EXISTS", 7: "PERMISSION_DENIED", 8: "RESOURCE_EXHAUSTED", 9: "FAILED_PRECONDITION", 10: "ABORTED", 11: "OUT_OF_RANGE", 12: "UNIMPLEMENTED", 13: "INTERNAL", 14: "UNAVAILABLE", 15: "DATA_LOSS", 16: "UNAUTHENTICATED" };',
295938
295938
  'function grpcStatusName() { if (typeof pm.response.status === "string" && pm.response.status) return pm.response.status; return GRPC_STATUS[pm.response.code] || ("UNKNOWN(" + pm.response.code + ")"); }',
295939
- "function grpcMessage() { try { return pm.response.json(); } catch (error) { return undefined; } }",
295939
+ // Terminal message: pm.response.json() where the sandbox provides it,
295940
+ // falling back to the last received message in pm.response.messages (the
295941
+ // unified runtime's GRPCResponse exposes messages but no json()).
295942
+ "function grpcMessage() {",
295943
+ ' try { if (pm.response && typeof pm.response.json === "function") { var viaJson = pm.response.json(); if (viaJson !== undefined && viaJson !== null) return viaJson; } } catch (error) { /* fall back to messages */ }',
295944
+ " try {",
295945
+ " var list = pm.response && pm.response.messages;",
295946
+ ' if (list && typeof list.each === "function") { var last; list.each(function (member) { last = member && member.data !== undefined ? member.data : member; }); return last; }',
295947
+ " } catch (error) { return undefined; }",
295948
+ " return undefined;",
295949
+ "}",
295940
295950
  "function jsonTypeOf(value) {",
295941
295951
  ' if (value === null || value === undefined) return "null";',
295942
295952
  ' if (Array.isArray(value)) return "array";',
@@ -296087,9 +296097,38 @@ function createGrpcScript(spec) {
296087
296097
  ' if (set.length > 1) pm.expect.fail("gRPC response at " + path + " sets multiple members of a oneof: " + set.join(", "));',
296088
296098
  " });",
296089
296099
  "}",
296100
+ // Wire-conformance helpers for response metadata/trailers ({ key, value }
296101
+ // PropertyLists; each/has/one guarded so the script stays inert on runtimes
296102
+ // or harnesses that do not surface them).
296103
+ 'function grpcEachMeta(list, cb) { if (list && typeof list.each === "function") list.each(cb); }',
296104
+ 'function grpcMetaOne(list, key) { try { if (list && typeof list.has === "function" && list.has(key) && typeof list.one === "function") return list.one(key); } catch (error) { /* absent */ } return null; }',
296105
+ "function grpcCheckMetaPairs(list, label) {",
296106
+ " grpcEachMeta(list, function (entry) {",
296107
+ " if (!entry || entry.disabled) return;",
296108
+ ' var key = entry.key === undefined || entry.key === null ? "" : String(entry.key);',
296109
+ ' var value = entry.value === undefined || entry.value === null ? "" : String(entry.value);',
296110
+ ' if (!/^[0-9a-z_.-]+$/.test(key)) pm.expect.fail(label + " key " + JSON.stringify(key) + " must be a lowercase gRPC metadata key ([0-9a-z_.-])");',
296111
+ ' if (/-bin$/.test(key)) { if (!/^[A-Za-z0-9+/=]*\\s*$/.test(value)) pm.expect.fail(label + " " + key + " must carry base64 data but was " + JSON.stringify(value)); }',
296112
+ ' else if (!/^[\\x20-\\x7e]*$/.test(value)) pm.expect.fail(label + " " + key + " value must be printable ASCII (gRPC ASCII-Value)");',
296113
+ " });",
296114
+ "}",
296090
296115
  `pm.test('gRPC status is OK for ' + grpcSpec.methodPath, function () {`,
296091
296116
  ' pm.expect(pm.response.code, "gRPC call for " + grpcSpec.methodPath + " returned " + grpcStatusName() + " (" + pm.response.code + ")").to.eql(0);',
296092
296117
  "});",
296118
+ // Metadata/trailer wire conformance runs on every terminal status (error
296119
+ // statuses carry trailers too, so this is not gated on code === 0).
296120
+ `pm.test('gRPC response metadata and trailers conform to gRPC wire rules for ' + grpcSpec.methodPath, function () {`,
296121
+ ' grpcCheckMetaPairs(pm.response.metadata, "gRPC response metadata");',
296122
+ ' grpcCheckMetaPairs(pm.response.trailers, "gRPC response trailer");',
296123
+ ' var contentType = grpcMetaOne(pm.response.metadata, "content-type");',
296124
+ ' if (contentType && contentType.value !== undefined && contentType.value !== null && !/^application\\/grpc/.test(String(contentType.value))) pm.expect.fail("gRPC response content-type metadata must be application/grpc[+proto|+json] but was " + contentType.value);',
296125
+ ' var echoedStatus = grpcMetaOne(pm.response.trailers, "grpc-status");',
296126
+ " if (echoedStatus) {",
296127
+ " var echoedCode = Number(echoedStatus.value);",
296128
+ ' if (!Number.isInteger(echoedCode) || echoedCode < 0 || echoedCode > 16) pm.expect.fail("grpc-status trailer must be a canonical gRPC code 0-16 but was " + JSON.stringify(echoedStatus.value));',
296129
+ ' else if (echoedCode !== pm.response.code) pm.expect.fail("grpc-status trailer (" + echoedCode + ") disagrees with the reported status code (" + pm.response.code + ")");',
296130
+ " }",
296131
+ "});",
296093
296132
  // Terminal-response-message expectation. unary and client-streaming RPCs
296094
296133
  // return exactly one terminal response message; server/bidi streaming may
296095
296134
  // legitimately return ZERO messages on an OK stream, so no minimum is
@@ -296111,6 +296150,26 @@ function createGrpcScript(spec) {
296111
296150
  ' if (grpcSpec.responseShape) grpcCheckShape(message, grpcSpec.responseShape, grpcSpec.responseType + ".");',
296112
296151
  " if (grpcSpec.responseIsRpcStatus) grpcCheckRpcStatus(message, grpcSpec.responseType);",
296113
296152
  "});"
296153
+ ] : [],
296154
+ // Every streamed message is validated, not only the terminal one that
296155
+ // pm.response.json() returns; pm.response.messages is the full received
296156
+ // stream. Server/bidi only: for unary/client the single terminal message
296157
+ // is already covered above.
296158
+ ...(spec.stream === "server" || spec.stream === "bidi") && (spec.hasResponseShape || spec.responseIsRpcStatus) ? [
296159
+ `pm.test('gRPC streamed response messages each match ' + grpcSpec.responseType, function () {`,
296160
+ " if (pm.response.code !== 0) return;",
296161
+ " var list = pm.response.messages;",
296162
+ ' if (!list || typeof list.each !== "function") return;',
296163
+ " var messageIndex = 0;",
296164
+ " list.each(function (member) {",
296165
+ " var data = member && member.data !== undefined ? member.data : member;",
296166
+ ' var label = grpcSpec.responseType + "[message " + messageIndex + "]";',
296167
+ " messageIndex += 1;",
296168
+ ' if (jsonTypeOf(data) !== "object") { pm.expect.fail("gRPC streamed response " + label + " is not a decodable message object but " + jsonTypeOf(data)); return; }',
296169
+ ' if (grpcSpec.responseShape) grpcCheckShape(data, grpcSpec.responseShape, label + ".");',
296170
+ " if (grpcSpec.responseIsRpcStatus) grpcCheckRpcStatus(data, label);",
296171
+ " });",
296172
+ "});"
296114
296173
  ] : []
296115
296174
  ];
296116
296175
  }
package/dist/index.cjs CHANGED
@@ -297635,7 +297635,17 @@ function createGrpcScript(spec) {
297635
297635
  // reporters/cli/modules/grpc.ts:15-21.
297636
297636
  'var GRPC_STATUS = { 0: "OK", 1: "CANCELLED", 2: "UNKNOWN", 3: "INVALID_ARGUMENT", 4: "DEADLINE_EXCEEDED", 5: "NOT_FOUND", 6: "ALREADY_EXISTS", 7: "PERMISSION_DENIED", 8: "RESOURCE_EXHAUSTED", 9: "FAILED_PRECONDITION", 10: "ABORTED", 11: "OUT_OF_RANGE", 12: "UNIMPLEMENTED", 13: "INTERNAL", 14: "UNAVAILABLE", 15: "DATA_LOSS", 16: "UNAUTHENTICATED" };',
297637
297637
  'function grpcStatusName() { if (typeof pm.response.status === "string" && pm.response.status) return pm.response.status; return GRPC_STATUS[pm.response.code] || ("UNKNOWN(" + pm.response.code + ")"); }',
297638
- "function grpcMessage() { try { return pm.response.json(); } catch (error) { return undefined; } }",
297638
+ // Terminal message: pm.response.json() where the sandbox provides it,
297639
+ // falling back to the last received message in pm.response.messages (the
297640
+ // unified runtime's GRPCResponse exposes messages but no json()).
297641
+ "function grpcMessage() {",
297642
+ ' try { if (pm.response && typeof pm.response.json === "function") { var viaJson = pm.response.json(); if (viaJson !== undefined && viaJson !== null) return viaJson; } } catch (error) { /* fall back to messages */ }',
297643
+ " try {",
297644
+ " var list = pm.response && pm.response.messages;",
297645
+ ' if (list && typeof list.each === "function") { var last; list.each(function (member) { last = member && member.data !== undefined ? member.data : member; }); return last; }',
297646
+ " } catch (error) { return undefined; }",
297647
+ " return undefined;",
297648
+ "}",
297639
297649
  "function jsonTypeOf(value) {",
297640
297650
  ' if (value === null || value === undefined) return "null";',
297641
297651
  ' if (Array.isArray(value)) return "array";',
@@ -297786,9 +297796,38 @@ function createGrpcScript(spec) {
297786
297796
  ' if (set.length > 1) pm.expect.fail("gRPC response at " + path + " sets multiple members of a oneof: " + set.join(", "));',
297787
297797
  " });",
297788
297798
  "}",
297799
+ // Wire-conformance helpers for response metadata/trailers ({ key, value }
297800
+ // PropertyLists; each/has/one guarded so the script stays inert on runtimes
297801
+ // or harnesses that do not surface them).
297802
+ 'function grpcEachMeta(list, cb) { if (list && typeof list.each === "function") list.each(cb); }',
297803
+ 'function grpcMetaOne(list, key) { try { if (list && typeof list.has === "function" && list.has(key) && typeof list.one === "function") return list.one(key); } catch (error) { /* absent */ } return null; }',
297804
+ "function grpcCheckMetaPairs(list, label) {",
297805
+ " grpcEachMeta(list, function (entry) {",
297806
+ " if (!entry || entry.disabled) return;",
297807
+ ' var key = entry.key === undefined || entry.key === null ? "" : String(entry.key);',
297808
+ ' var value = entry.value === undefined || entry.value === null ? "" : String(entry.value);',
297809
+ ' if (!/^[0-9a-z_.-]+$/.test(key)) pm.expect.fail(label + " key " + JSON.stringify(key) + " must be a lowercase gRPC metadata key ([0-9a-z_.-])");',
297810
+ ' if (/-bin$/.test(key)) { if (!/^[A-Za-z0-9+/=]*\\s*$/.test(value)) pm.expect.fail(label + " " + key + " must carry base64 data but was " + JSON.stringify(value)); }',
297811
+ ' else if (!/^[\\x20-\\x7e]*$/.test(value)) pm.expect.fail(label + " " + key + " value must be printable ASCII (gRPC ASCII-Value)");',
297812
+ " });",
297813
+ "}",
297789
297814
  `pm.test('gRPC status is OK for ' + grpcSpec.methodPath, function () {`,
297790
297815
  ' pm.expect(pm.response.code, "gRPC call for " + grpcSpec.methodPath + " returned " + grpcStatusName() + " (" + pm.response.code + ")").to.eql(0);',
297791
297816
  "});",
297817
+ // Metadata/trailer wire conformance runs on every terminal status (error
297818
+ // statuses carry trailers too, so this is not gated on code === 0).
297819
+ `pm.test('gRPC response metadata and trailers conform to gRPC wire rules for ' + grpcSpec.methodPath, function () {`,
297820
+ ' grpcCheckMetaPairs(pm.response.metadata, "gRPC response metadata");',
297821
+ ' grpcCheckMetaPairs(pm.response.trailers, "gRPC response trailer");',
297822
+ ' var contentType = grpcMetaOne(pm.response.metadata, "content-type");',
297823
+ ' if (contentType && contentType.value !== undefined && contentType.value !== null && !/^application\\/grpc/.test(String(contentType.value))) pm.expect.fail("gRPC response content-type metadata must be application/grpc[+proto|+json] but was " + contentType.value);',
297824
+ ' var echoedStatus = grpcMetaOne(pm.response.trailers, "grpc-status");',
297825
+ " if (echoedStatus) {",
297826
+ " var echoedCode = Number(echoedStatus.value);",
297827
+ ' if (!Number.isInteger(echoedCode) || echoedCode < 0 || echoedCode > 16) pm.expect.fail("grpc-status trailer must be a canonical gRPC code 0-16 but was " + JSON.stringify(echoedStatus.value));',
297828
+ ' else if (echoedCode !== pm.response.code) pm.expect.fail("grpc-status trailer (" + echoedCode + ") disagrees with the reported status code (" + pm.response.code + ")");',
297829
+ " }",
297830
+ "});",
297792
297831
  // Terminal-response-message expectation. unary and client-streaming RPCs
297793
297832
  // return exactly one terminal response message; server/bidi streaming may
297794
297833
  // legitimately return ZERO messages on an OK stream, so no minimum is
@@ -297810,6 +297849,26 @@ function createGrpcScript(spec) {
297810
297849
  ' if (grpcSpec.responseShape) grpcCheckShape(message, grpcSpec.responseShape, grpcSpec.responseType + ".");',
297811
297850
  " if (grpcSpec.responseIsRpcStatus) grpcCheckRpcStatus(message, grpcSpec.responseType);",
297812
297851
  "});"
297852
+ ] : [],
297853
+ // Every streamed message is validated, not only the terminal one that
297854
+ // pm.response.json() returns; pm.response.messages is the full received
297855
+ // stream. Server/bidi only: for unary/client the single terminal message
297856
+ // is already covered above.
297857
+ ...(spec.stream === "server" || spec.stream === "bidi") && (spec.hasResponseShape || spec.responseIsRpcStatus) ? [
297858
+ `pm.test('gRPC streamed response messages each match ' + grpcSpec.responseType, function () {`,
297859
+ " if (pm.response.code !== 0) return;",
297860
+ " var list = pm.response.messages;",
297861
+ ' if (!list || typeof list.each !== "function") return;',
297862
+ " var messageIndex = 0;",
297863
+ " list.each(function (member) {",
297864
+ " var data = member && member.data !== undefined ? member.data : member;",
297865
+ ' var label = grpcSpec.responseType + "[message " + messageIndex + "]";',
297866
+ " messageIndex += 1;",
297867
+ ' if (jsonTypeOf(data) !== "object") { pm.expect.fail("gRPC streamed response " + label + " is not a decodable message object but " + jsonTypeOf(data)); return; }',
297868
+ ' if (grpcSpec.responseShape) grpcCheckShape(data, grpcSpec.responseShape, label + ".");',
297869
+ " if (grpcSpec.responseIsRpcStatus) grpcCheckRpcStatus(data, label);",
297870
+ " });",
297871
+ "});"
297813
297872
  ] : []
297814
297873
  ];
297815
297874
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postman-cse/onboarding-bootstrap",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "Bootstrap Postman workspaces, specs, and collections from OpenAPI.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",