@postman-cse/onboarding-bootstrap 2.4.0 → 2.6.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 +1 -1
- package/dist/action.cjs +281 -5
- package/dist/cli.cjs +281 -5
- package/dist/index.cjs +281 -5
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -295272,12 +295272,36 @@ function buildOperationScript(operation, index, warnings) {
|
|
|
295272
295272
|
' if (mediaType === "application/json" && gqlBody.data !== undefined && gqlBody.data !== null && pm.response.code !== 200) { pm.expect.fail("a GraphQL response carrying data over application/json must be HTTP 200; got " + pm.response.code); }',
|
|
295273
295273
|
"});"
|
|
295274
295274
|
);
|
|
295275
|
+
lines.push(
|
|
295276
|
+
`pm.test(${JSON.stringify(`[${label}] GraphQL response map follows the spec response format`)}, function () {`,
|
|
295277
|
+
' var extraKeys = Object.keys(gqlBody).filter(function (key) { return key !== "data" && key !== "errors" && key !== "extensions"; });',
|
|
295278
|
+
' if (extraKeys.length > 0) pm.expect.fail("the GraphQL response map must not contain entries other than data, errors, and extensions (GraphQL spec 7.1): " + extraKeys.join(", "));',
|
|
295279
|
+
' if (Object.prototype.hasOwnProperty.call(gqlBody, "extensions") && (typeof gqlBody.extensions !== "object" || gqlBody.extensions === null || Array.isArray(gqlBody.extensions))) pm.expect.fail("the GraphQL extensions entry must be a map (GraphQL spec 7.1)");',
|
|
295280
|
+
' if (!Object.prototype.hasOwnProperty.call(gqlBody, "data") && (!Array.isArray(gqlBody.errors) || gqlBody.errors.length === 0)) pm.expect.fail("a GraphQL request-error result (no data entry) must carry a non-empty errors list (GraphQL spec 7.1)");',
|
|
295281
|
+
"});"
|
|
295282
|
+
);
|
|
295275
295283
|
lines.push(
|
|
295276
295284
|
`pm.test(${JSON.stringify(`[${label}] GraphQL errors are well-formed and not a total failure`)}, function () {`,
|
|
295277
295285
|
" var errors = gqlBody.errors;",
|
|
295278
295286
|
" if (errors === undefined || errors === null) return;",
|
|
295279
295287
|
` pm.expect(errors, "GraphQL 'errors' must be an array when present").to.be.an("array");`,
|
|
295280
|
-
|
|
295288
|
+
" errors.forEach(function (err, errIndex) {",
|
|
295289
|
+
' pm.expect(err, "each GraphQL error must carry a message").to.be.an("object").that.has.property("message");',
|
|
295290
|
+
' if (typeof err.message !== "string") pm.expect.fail("errors[" + errIndex + "].message must be a string (GraphQL spec 7.1.2)");',
|
|
295291
|
+
" if (err.locations !== undefined && err.locations !== null) {",
|
|
295292
|
+
' if (!Array.isArray(err.locations)) { pm.expect.fail("errors[" + errIndex + "].locations must be a list (GraphQL spec 7.1.2)"); return; }',
|
|
295293
|
+
" err.locations.forEach(function (loc, locIndex) {",
|
|
295294
|
+
' var locLabel = "errors[" + errIndex + "].locations[" + locIndex + "]";',
|
|
295295
|
+
' if (!loc || typeof loc !== "object" || Array.isArray(loc)) { pm.expect.fail(locLabel + " must be a map with line and column (GraphQL spec 7.1.2)"); return; }',
|
|
295296
|
+
' if (!Number.isInteger(loc.line) || loc.line < 1 || !Number.isInteger(loc.column) || loc.column < 1) pm.expect.fail(locLabel + " line and column must be positive integers starting from 1 (GraphQL spec 7.1.2)");',
|
|
295297
|
+
" });",
|
|
295298
|
+
" }",
|
|
295299
|
+
" if (err.path !== undefined && err.path !== null) {",
|
|
295300
|
+
' if (!Array.isArray(err.path)) { pm.expect.fail("errors[" + errIndex + "].path must be a list of path segments (GraphQL spec 7.1.2)"); return; }',
|
|
295301
|
+
' err.path.forEach(function (segment, segIndex) { if (typeof segment !== "string" && !Number.isInteger(segment)) pm.expect.fail("errors[" + errIndex + "].path[" + segIndex + "] must be a string field name or an integer list index (GraphQL spec 7.1.2)"); });',
|
|
295302
|
+
" }",
|
|
295303
|
+
' if (err.extensions !== undefined && err.extensions !== null && (typeof err.extensions !== "object" || Array.isArray(err.extensions))) pm.expect.fail("errors[" + errIndex + "].extensions must be a map (GraphQL spec 7.1.2)");',
|
|
295304
|
+
" });",
|
|
295281
295305
|
" var hasData = gqlBody.data !== undefined && gqlBody.data !== null;",
|
|
295282
295306
|
' if (!hasData && errors.length > 0) { pm.expect.fail("GraphQL request returned errors and no data: " + JSON.stringify(errors)); }',
|
|
295283
295307
|
"});"
|
|
@@ -295936,7 +295960,17 @@ function createGrpcScript(spec) {
|
|
|
295936
295960
|
// reporters/cli/modules/grpc.ts:15-21.
|
|
295937
295961
|
'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
295962
|
'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
|
-
|
|
295963
|
+
// Terminal message: pm.response.json() where the sandbox provides it,
|
|
295964
|
+
// falling back to the last received message in pm.response.messages (the
|
|
295965
|
+
// unified runtime's GRPCResponse exposes messages but no json()).
|
|
295966
|
+
"function grpcMessage() {",
|
|
295967
|
+
' 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 */ }',
|
|
295968
|
+
" try {",
|
|
295969
|
+
" var list = pm.response && pm.response.messages;",
|
|
295970
|
+
' if (list && typeof list.each === "function") { var last; list.each(function (member) { last = member && member.data !== undefined ? member.data : member; }); return last; }',
|
|
295971
|
+
" } catch (error) { return undefined; }",
|
|
295972
|
+
" return undefined;",
|
|
295973
|
+
"}",
|
|
295940
295974
|
"function jsonTypeOf(value) {",
|
|
295941
295975
|
' if (value === null || value === undefined) return "null";',
|
|
295942
295976
|
' if (Array.isArray(value)) return "array";',
|
|
@@ -296087,9 +296121,104 @@ function createGrpcScript(spec) {
|
|
|
296087
296121
|
' if (set.length > 1) pm.expect.fail("gRPC response at " + path + " sets multiple members of a oneof: " + set.join(", "));',
|
|
296088
296122
|
" });",
|
|
296089
296123
|
"}",
|
|
296124
|
+
// Wire-conformance helpers for response metadata/trailers ({ key, value }
|
|
296125
|
+
// PropertyLists; each/has/one guarded so the script stays inert on runtimes
|
|
296126
|
+
// or harnesses that do not surface them).
|
|
296127
|
+
'function grpcEachMeta(list, cb) { if (list && typeof list.each === "function") list.each(cb); }',
|
|
296128
|
+
'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; }',
|
|
296129
|
+
"function grpcCheckMetaPairs(list, label) {",
|
|
296130
|
+
" grpcEachMeta(list, function (entry) {",
|
|
296131
|
+
" if (!entry || entry.disabled) return;",
|
|
296132
|
+
' var key = entry.key === undefined || entry.key === null ? "" : String(entry.key);',
|
|
296133
|
+
' var value = entry.value === undefined || entry.value === null ? "" : String(entry.value);',
|
|
296134
|
+
' if (!/^[0-9a-z_.-]+$/.test(key)) pm.expect.fail(label + " key " + JSON.stringify(key) + " must be a lowercase gRPC metadata key ([0-9a-z_.-])");',
|
|
296135
|
+
' 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)); }',
|
|
296136
|
+
' else if (!/^[\\x20-\\x7e]*$/.test(value)) pm.expect.fail(label + " " + key + " value must be printable ASCII (gRPC ASCII-Value)");',
|
|
296137
|
+
" });",
|
|
296138
|
+
"}",
|
|
296139
|
+
// grpc-status-details-bin carries a base64-encoded google.rpc.Status protobuf
|
|
296140
|
+
// (the gRPC richer-error model). The sandbox has no protobuf runtime, so the
|
|
296141
|
+
// script walks the protobuf wire format directly: base64 -> bytes -> tagged
|
|
296142
|
+
// fields (varint / 64-bit / length-delimited / 32-bit). Groups (wire types
|
|
296143
|
+
// 3/4) are proto2-deprecated and never emitted by google.rpc.Status.
|
|
296144
|
+
"function grpcB64Bytes(value) {",
|
|
296145
|
+
' var clean = String(value).replace(/\\s+/g, "").replace(/-/g, "+").replace(/_/g, "/");',
|
|
296146
|
+
" if (clean.length % 4 === 1 || !/^[A-Za-z0-9+/]*={0,2}$/.test(clean)) return null;",
|
|
296147
|
+
' var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";',
|
|
296148
|
+
' var unpadded = clean.replace(/=+$/, ""); var bytes = []; var buffer = 0; var bits = 0;',
|
|
296149
|
+
" for (var i = 0; i < unpadded.length; i++) {",
|
|
296150
|
+
" var idx = alphabet.indexOf(unpadded.charAt(i));",
|
|
296151
|
+
" if (idx === -1) return null;",
|
|
296152
|
+
" buffer = (buffer << 6) | idx; bits += 6;",
|
|
296153
|
+
" if (bits >= 8) { bits -= 8; bytes.push((buffer >> bits) & 0xff); }",
|
|
296154
|
+
" }",
|
|
296155
|
+
" return bytes;",
|
|
296156
|
+
"}",
|
|
296157
|
+
"function grpcPbVarint(bytes, pos) {",
|
|
296158
|
+
" var value = 0; var shift = 0;",
|
|
296159
|
+
" while (pos < bytes.length) {",
|
|
296160
|
+
" var b = bytes[pos]; pos += 1;",
|
|
296161
|
+
" value += (b & 0x7f) * Math.pow(2, shift); shift += 7;",
|
|
296162
|
+
" if ((b & 0x80) === 0) return value > 9007199254740991 ? null : { value: value, pos: pos };",
|
|
296163
|
+
" if (shift > 63) return null;",
|
|
296164
|
+
" }",
|
|
296165
|
+
" return null;",
|
|
296166
|
+
"}",
|
|
296167
|
+
"function grpcPbFields(bytes) {",
|
|
296168
|
+
" var pos = 0; var fields = [];",
|
|
296169
|
+
" while (pos < bytes.length) {",
|
|
296170
|
+
" var tag = grpcPbVarint(bytes, pos); if (!tag) return null;",
|
|
296171
|
+
" pos = tag.pos;",
|
|
296172
|
+
" var fieldNumber = Math.floor(tag.value / 8); var wire = tag.value % 8;",
|
|
296173
|
+
" if (fieldNumber < 1) return null;",
|
|
296174
|
+
" if (wire === 0) { var varint = grpcPbVarint(bytes, pos); if (!varint) return null; fields.push({ field: fieldNumber, wire: 0, value: varint.value }); pos = varint.pos; }",
|
|
296175
|
+
" else if (wire === 1) { if (pos + 8 > bytes.length) return null; fields.push({ field: fieldNumber, wire: 1 }); pos += 8; }",
|
|
296176
|
+
" else if (wire === 2) { var len = grpcPbVarint(bytes, pos); if (!len) return null; pos = len.pos; if (pos + len.value > bytes.length) return null; fields.push({ field: fieldNumber, wire: 2, bytes: bytes.slice(pos, pos + len.value) }); pos += len.value; }",
|
|
296177
|
+
" else if (wire === 5) { if (pos + 4 > bytes.length) return null; fields.push({ field: fieldNumber, wire: 5 }); pos += 4; }",
|
|
296178
|
+
" else return null;",
|
|
296179
|
+
" }",
|
|
296180
|
+
" return fields;",
|
|
296181
|
+
"}",
|
|
296182
|
+
"function grpcCheckStatusDetailsBin(entry) {",
|
|
296183
|
+
' if (!entry || entry.value === undefined || entry.value === null || String(entry.value) === "") return;',
|
|
296184
|
+
" var detailBytes = grpcB64Bytes(entry.value);",
|
|
296185
|
+
' if (!detailBytes) { pm.expect.fail("grpc-status-details-bin trailer must carry base64-encoded bytes but was " + JSON.stringify(String(entry.value))); return; }',
|
|
296186
|
+
" var statusFields = grpcPbFields(detailBytes);",
|
|
296187
|
+
' if (!statusFields) { pm.expect.fail("grpc-status-details-bin does not decode as a protobuf wire message (google.rpc.Status)"); return; }',
|
|
296188
|
+
" statusFields.forEach(function (statusField) {",
|
|
296189
|
+
" if (statusField.field === 1) {",
|
|
296190
|
+
' if (statusField.wire !== 0) { pm.expect.fail("google.rpc.Status.code (field 1) in grpc-status-details-bin must be varint-encoded"); return; }',
|
|
296191
|
+
' if (statusField.value < 0 || statusField.value > 16) pm.expect.fail("google.rpc.Status.code in grpc-status-details-bin must be a canonical gRPC code 0-16 but was " + statusField.value);',
|
|
296192
|
+
' else if (statusField.value !== pm.response.code) pm.expect.fail("google.rpc.Status.code in grpc-status-details-bin (" + statusField.value + ") disagrees with the reported status code (" + pm.response.code + ")");',
|
|
296193
|
+
" } else if (statusField.field === 2) {",
|
|
296194
|
+
' if (statusField.wire !== 2) pm.expect.fail("google.rpc.Status.message (field 2) in grpc-status-details-bin must be length-delimited");',
|
|
296195
|
+
" } else if (statusField.field === 3) {",
|
|
296196
|
+
' if (statusField.wire !== 2) { pm.expect.fail("google.rpc.Status.details (field 3) in grpc-status-details-bin must be length-delimited google.protobuf.Any messages"); return; }',
|
|
296197
|
+
" var anyFields = grpcPbFields(statusField.bytes);",
|
|
296198
|
+
' if (!anyFields) { pm.expect.fail("google.rpc.Status.details entry in grpc-status-details-bin is not a decodable google.protobuf.Any message"); return; }',
|
|
296199
|
+
" var hasTypeUrl = anyFields.some(function (anyField) { return anyField.field === 1 && anyField.wire === 2 && anyField.bytes.length > 0; });",
|
|
296200
|
+
' if (!hasTypeUrl) pm.expect.fail("google.protobuf.Any in grpc-status-details-bin details must carry a non-empty type_url (field 1)");',
|
|
296201
|
+
" }",
|
|
296202
|
+
" });",
|
|
296203
|
+
"}",
|
|
296090
296204
|
`pm.test('gRPC status is OK for ' + grpcSpec.methodPath, function () {`,
|
|
296091
296205
|
' pm.expect(pm.response.code, "gRPC call for " + grpcSpec.methodPath + " returned " + grpcStatusName() + " (" + pm.response.code + ")").to.eql(0);',
|
|
296092
296206
|
"});",
|
|
296207
|
+
// Metadata/trailer wire conformance runs on every terminal status (error
|
|
296208
|
+
// statuses carry trailers too, so this is not gated on code === 0).
|
|
296209
|
+
`pm.test('gRPC response metadata and trailers conform to gRPC wire rules for ' + grpcSpec.methodPath, function () {`,
|
|
296210
|
+
' grpcCheckMetaPairs(pm.response.metadata, "gRPC response metadata");',
|
|
296211
|
+
' grpcCheckMetaPairs(pm.response.trailers, "gRPC response trailer");',
|
|
296212
|
+
' var contentType = grpcMetaOne(pm.response.metadata, "content-type");',
|
|
296213
|
+
' 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);',
|
|
296214
|
+
' var echoedStatus = grpcMetaOne(pm.response.trailers, "grpc-status");',
|
|
296215
|
+
" if (echoedStatus) {",
|
|
296216
|
+
" var echoedCode = Number(echoedStatus.value);",
|
|
296217
|
+
' 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));',
|
|
296218
|
+
' else if (echoedCode !== pm.response.code) pm.expect.fail("grpc-status trailer (" + echoedCode + ") disagrees with the reported status code (" + pm.response.code + ")");',
|
|
296219
|
+
" }",
|
|
296220
|
+
' grpcCheckStatusDetailsBin(grpcMetaOne(pm.response.trailers, "grpc-status-details-bin"));',
|
|
296221
|
+
"});",
|
|
296093
296222
|
// Terminal-response-message expectation. unary and client-streaming RPCs
|
|
296094
296223
|
// return exactly one terminal response message; server/bidi streaming may
|
|
296095
296224
|
// legitimately return ZERO messages on an OK stream, so no minimum is
|
|
@@ -296111,6 +296240,26 @@ function createGrpcScript(spec) {
|
|
|
296111
296240
|
' if (grpcSpec.responseShape) grpcCheckShape(message, grpcSpec.responseShape, grpcSpec.responseType + ".");',
|
|
296112
296241
|
" if (grpcSpec.responseIsRpcStatus) grpcCheckRpcStatus(message, grpcSpec.responseType);",
|
|
296113
296242
|
"});"
|
|
296243
|
+
] : [],
|
|
296244
|
+
// Every streamed message is validated, not only the terminal one that
|
|
296245
|
+
// pm.response.json() returns; pm.response.messages is the full received
|
|
296246
|
+
// stream. Server/bidi only: for unary/client the single terminal message
|
|
296247
|
+
// is already covered above.
|
|
296248
|
+
...(spec.stream === "server" || spec.stream === "bidi") && (spec.hasResponseShape || spec.responseIsRpcStatus) ? [
|
|
296249
|
+
`pm.test('gRPC streamed response messages each match ' + grpcSpec.responseType, function () {`,
|
|
296250
|
+
" if (pm.response.code !== 0) return;",
|
|
296251
|
+
" var list = pm.response.messages;",
|
|
296252
|
+
' if (!list || typeof list.each !== "function") return;',
|
|
296253
|
+
" var messageIndex = 0;",
|
|
296254
|
+
" list.each(function (member) {",
|
|
296255
|
+
" var data = member && member.data !== undefined ? member.data : member;",
|
|
296256
|
+
' var label = grpcSpec.responseType + "[message " + messageIndex + "]";',
|
|
296257
|
+
" messageIndex += 1;",
|
|
296258
|
+
' if (jsonTypeOf(data) !== "object") { pm.expect.fail("gRPC streamed response " + label + " is not a decodable message object but " + jsonTypeOf(data)); return; }',
|
|
296259
|
+
' if (grpcSpec.responseShape) grpcCheckShape(data, grpcSpec.responseShape, label + ".");',
|
|
296260
|
+
" if (grpcSpec.responseIsRpcStatus) grpcCheckRpcStatus(data, label);",
|
|
296261
|
+
" });",
|
|
296262
|
+
"});"
|
|
296114
296263
|
] : []
|
|
296115
296264
|
];
|
|
296116
296265
|
}
|
|
@@ -301907,6 +302056,7 @@ function createSoapScript(operation, warnings = []) {
|
|
|
301907
302056
|
};
|
|
301908
302057
|
const responseRegex = operation.expectedResponseElement ? elementPresenceRegex(operation.expectedResponseElement) : "";
|
|
301909
302058
|
const mediaType = operation.soapVersion === "1.2" ? "application/soap+xml" : "text/xml";
|
|
302059
|
+
const envelopeNs = operation.soapVersion === "1.2" ? "http://www.w3.org/2003/05/soap-envelope" : "http://schemas.xmlsoap.org/soap/envelope/";
|
|
301910
302060
|
const faultStatusLine = operation.soapVersion === "1.2" ? ' if (faulted && code !== 500 && code !== 400) pm.expect.fail("SOAP 1.2 Faults ride HTTP 500, or 400 for env:Sender faults (SOAP 1.2 Part 2 HTTP binding); got HTTP " + code);' : ' if (faulted && code !== 500) pm.expect.fail("SOAP 1.1 Faults must ride HTTP 500 (WS-I Basic Profile R1126); got HTTP " + code);';
|
|
301911
302061
|
const lines = [
|
|
301912
302062
|
`var soap = JSON.parse(${JSON.stringify(JSON.stringify(meta))});`,
|
|
@@ -301929,6 +302079,11 @@ function createSoapScript(operation, warnings = []) {
|
|
|
301929
302079
|
' pm.expect(bodyText, "response body is not a SOAP envelope").to.match(matchTag("Envelope"));',
|
|
301930
302080
|
"});",
|
|
301931
302081
|
"",
|
|
302082
|
+
`pm.test('SOAP Envelope namespace matches SOAP ${operation.soapVersion}', function () {`,
|
|
302083
|
+
' if (!matchTag("Envelope").test(bodyText)) return;',
|
|
302084
|
+
` pm.expect(bodyText.indexOf(${JSON.stringify(envelopeNs)}) !== -1, "SOAP ${operation.soapVersion} envelopes must declare the ${envelopeNs} namespace").to.equal(true);`,
|
|
302085
|
+
"});",
|
|
302086
|
+
"",
|
|
301932
302087
|
"pm.test('SOAP Body element is present', function () {",
|
|
301933
302088
|
' pm.expect(bodyText, "SOAP envelope has no Body element").to.match(matchTag("Body"));',
|
|
301934
302089
|
"});",
|
|
@@ -301946,7 +302101,33 @@ function createSoapScript(operation, warnings = []) {
|
|
|
301946
302101
|
" var code = pm.response.code;",
|
|
301947
302102
|
faultStatusLine,
|
|
301948
302103
|
' if (!faulted && code === 500) pm.expect.fail("HTTP 500 from a SOAP endpoint must carry a SOAP Fault in the body");',
|
|
301949
|
-
"});"
|
|
302104
|
+
"});",
|
|
302105
|
+
// Fault well-formedness (diagnostic companion to the Fault-absence test: a
|
|
302106
|
+
// faulted run already fails, this pinpoints a malformed Fault). SOAP 1.1
|
|
302107
|
+
// section 4.4 requires faultcode + faultstring children; SOAP 1.2 Part 1
|
|
302108
|
+
// section 5.4 requires Code/Value + Reason/Text and pins the top-level
|
|
302109
|
+
// Value QName to the five defined fault codes.
|
|
302110
|
+
...operation.soapVersion === "1.2" ? [
|
|
302111
|
+
"",
|
|
302112
|
+
"pm.test('SOAP Fault is well-formed for SOAP 1.2', function () {",
|
|
302113
|
+
' if (!matchTag("Fault").test(bodyText)) return;',
|
|
302114
|
+
' if (!matchTag("Code").test(bodyText)) { pm.expect.fail("a SOAP 1.2 Fault must carry an env:Code child (SOAP 1.2 Part 1 section 5.4)"); return; }',
|
|
302115
|
+
' if (!matchTag("Value").test(bodyText)) { pm.expect.fail("a SOAP 1.2 Fault Code must carry an env:Value child (SOAP 1.2 Part 1 section 5.4.1)"); return; }',
|
|
302116
|
+
' if (!matchTag("Reason").test(bodyText)) pm.expect.fail("a SOAP 1.2 Fault must carry an env:Reason child (SOAP 1.2 Part 1 section 5.4)");',
|
|
302117
|
+
' else if (!matchTag("Text").test(bodyText)) pm.expect.fail("a SOAP 1.2 Fault Reason must carry an env:Text child (SOAP 1.2 Part 1 section 5.4.2)");',
|
|
302118
|
+
' var faultValue = (bodyText.match(/<(?:[A-Za-z_][\\w.-]*:)?Value[^>]*>([\\s\\S]*?)<\\//) || [])[1] || "";',
|
|
302119
|
+
' var faultLocal = faultValue.trim().split(":").pop();',
|
|
302120
|
+
' var faultCodes = ["VersionMismatch", "MustUnderstand", "DataEncodingUnknown", "Sender", "Receiver"];',
|
|
302121
|
+
' if (faultLocal && faultCodes.indexOf(faultLocal) === -1) pm.expect.fail("the SOAP 1.2 Fault Code Value must be one of " + faultCodes.join(", ") + " (SOAP 1.2 Part 1 table 4); got " + faultValue.trim());',
|
|
302122
|
+
"});"
|
|
302123
|
+
] : [
|
|
302124
|
+
"",
|
|
302125
|
+
"pm.test('SOAP Fault is well-formed for SOAP 1.1', function () {",
|
|
302126
|
+
' if (!matchTag("Fault").test(bodyText)) return;',
|
|
302127
|
+
' if (!matchTag("faultcode").test(bodyText)) pm.expect.fail("a SOAP 1.1 Fault must carry a faultcode child (SOAP 1.1 section 4.4)");',
|
|
302128
|
+
' if (!matchTag("faultstring").test(bodyText)) pm.expect.fail("a SOAP 1.1 Fault must carry a faultstring child (SOAP 1.1 section 4.4)");',
|
|
302129
|
+
"});"
|
|
302130
|
+
]
|
|
301950
302131
|
];
|
|
301951
302132
|
if (responseRegex) {
|
|
301952
302133
|
lines.push(
|
|
@@ -302123,7 +302304,8 @@ function wsBindingKeyValues(channel) {
|
|
|
302123
302304
|
const value = asRecord15(wsBinding.value()) ?? {};
|
|
302124
302305
|
return {
|
|
302125
302306
|
headers: bindingKeyValues(value.headers),
|
|
302126
|
-
queryParams: bindingKeyValues(value.query)
|
|
302307
|
+
queryParams: bindingKeyValues(value.query),
|
|
302308
|
+
binding: value
|
|
302127
302309
|
};
|
|
302128
302310
|
}
|
|
302129
302311
|
function collectMqttInfo(channel, servers, messagesRaw, documentJson) {
|
|
@@ -302197,6 +302379,8 @@ function messageDescriptor2(message, warnings, channelId, defaultContentType, re
|
|
|
302197
302379
|
const replySchema = replyByMessageId.get(message.id());
|
|
302198
302380
|
const ackSchema = xAckSchema ?? replySchema;
|
|
302199
302381
|
const ackSource = xAckSchema ? "x-ack" : replySchema ? "reply" : void 0;
|
|
302382
|
+
const correlationRaw = asRecord15(rawMessage.correlationId)?.location;
|
|
302383
|
+
const correlationLocation = typeof correlationRaw === "string" ? correlationRaw : void 0;
|
|
302200
302384
|
const examples = message.examples().all().filter((example) => example.hasPayload());
|
|
302201
302385
|
const hasExample = examples.length > 0;
|
|
302202
302386
|
let sample;
|
|
@@ -302218,6 +302402,7 @@ function messageDescriptor2(message, warnings, channelId, defaultContentType, re
|
|
|
302218
302402
|
payloadSchema,
|
|
302219
302403
|
ackSchema,
|
|
302220
302404
|
ackSource,
|
|
302405
|
+
correlationLocation,
|
|
302221
302406
|
sample,
|
|
302222
302407
|
hasExample,
|
|
302223
302408
|
contentKind,
|
|
@@ -302230,6 +302415,7 @@ function channelDescriptor(channel, document2, documentJson, defaultContentType,
|
|
|
302230
302415
|
const servers = resolveServers(channel, document2);
|
|
302231
302416
|
const messagesRaw = channel.messages().all();
|
|
302232
302417
|
const transport = detectTransport(channel, servers, messagesRaw, documentJson, warnings);
|
|
302418
|
+
const parameterNames = Object.keys(asRecord15(channel.json().parameters) ?? {}).sort();
|
|
302233
302419
|
const serverUrl = servers.find((server) => server.url())?.url() || options.endpointUrl?.trim() || "";
|
|
302234
302420
|
if (!serverUrl) {
|
|
302235
302421
|
warnings.push(`ASYNCAPI_NO_SERVER_URL: channel ${channel.id()} has no resolvable server url; the generated request url is derived from the channel address only and must be completed before use`);
|
|
@@ -302249,6 +302435,7 @@ function channelDescriptor(channel, document2, documentJson, defaultContentType,
|
|
|
302249
302435
|
headers: [],
|
|
302250
302436
|
queryParams: [],
|
|
302251
302437
|
mqtt: collectMqttInfo(channel, servers, messagesRaw, documentJson),
|
|
302438
|
+
parameterNames,
|
|
302252
302439
|
messages,
|
|
302253
302440
|
warnings
|
|
302254
302441
|
};
|
|
@@ -302263,11 +302450,12 @@ function channelDescriptor(channel, document2, documentJson, defaultContentType,
|
|
|
302263
302450
|
queryParams: [],
|
|
302264
302451
|
socketioNamespace: address.startsWith("/") ? address : `/${address}`,
|
|
302265
302452
|
socketioPath: DEFAULT_SOCKETIO_PATH,
|
|
302453
|
+
parameterNames,
|
|
302266
302454
|
messages,
|
|
302267
302455
|
warnings
|
|
302268
302456
|
};
|
|
302269
302457
|
}
|
|
302270
|
-
const { headers, queryParams } = wsBindingKeyValues(channel);
|
|
302458
|
+
const { headers, queryParams, binding } = wsBindingKeyValues(channel);
|
|
302271
302459
|
return {
|
|
302272
302460
|
id: channel.id(),
|
|
302273
302461
|
address,
|
|
@@ -302275,6 +302463,8 @@ function channelDescriptor(channel, document2, documentJson, defaultContentType,
|
|
|
302275
302463
|
url: joinUrl(serverUrl, address),
|
|
302276
302464
|
headers,
|
|
302277
302465
|
queryParams,
|
|
302466
|
+
parameterNames,
|
|
302467
|
+
wsBinding: binding,
|
|
302278
302468
|
messages,
|
|
302279
302469
|
warnings
|
|
302280
302470
|
};
|
|
@@ -302712,14 +302902,68 @@ function collectMessageNodeIds(node, ids, path8) {
|
|
|
302712
302902
|
if (record) collectMessageNodeIds(record, ids, `${path8}/${i}`);
|
|
302713
302903
|
});
|
|
302714
302904
|
}
|
|
302905
|
+
function validateChannelParameters(channel, warnings) {
|
|
302906
|
+
const declared = new Set(channel.parameterNames ?? []);
|
|
302907
|
+
const used = /* @__PURE__ */ new Set();
|
|
302908
|
+
for (const match of channel.address.matchAll(/\{([^{}]*)\}/g)) {
|
|
302909
|
+
const name = match[1] ?? "";
|
|
302910
|
+
if (!name) {
|
|
302911
|
+
warnings.push(`ASYNCAPI_CHANNEL_PARAMETER_INVALID: channel ${channel.id} address ${channel.address} contains an empty {} parameter expression`);
|
|
302912
|
+
continue;
|
|
302913
|
+
}
|
|
302914
|
+
used.add(name);
|
|
302915
|
+
if (!declared.has(name)) {
|
|
302916
|
+
warnings.push(`ASYNCAPI_CHANNEL_PARAMETER_UNDECLARED: channel ${channel.id} address parameter {${name}} has no entry in the channel parameters object; AsyncAPI requires every address parameter to be declared`);
|
|
302917
|
+
}
|
|
302918
|
+
}
|
|
302919
|
+
for (const name of declared) {
|
|
302920
|
+
if (!used.has(name)) {
|
|
302921
|
+
warnings.push(`ASYNCAPI_CHANNEL_PARAMETER_UNUSED: channel ${channel.id} declares parameter ${name} that never appears in the channel address ${channel.address}`);
|
|
302922
|
+
}
|
|
302923
|
+
}
|
|
302924
|
+
}
|
|
302925
|
+
var CORRELATION_LOCATION_GRAMMAR = /^\$message\.(header|payload)#(\/(?:[^~/]|~[01])*)+$/;
|
|
302926
|
+
function validateCorrelationLocation(channelId, message, warnings) {
|
|
302927
|
+
if (message.correlationLocation === void 0) return;
|
|
302928
|
+
if (!CORRELATION_LOCATION_GRAMMAR.test(message.correlationLocation)) {
|
|
302929
|
+
warnings.push(
|
|
302930
|
+
`ASYNCAPI_CORRELATION_LOCATION_INVALID: message ${message.id} on channel ${channelId} correlationId location ${JSON.stringify(message.correlationLocation)} is not a valid AsyncAPI runtime expression ($message.header#/<pointer> or $message.payload#/<pointer>)`
|
|
302931
|
+
);
|
|
302932
|
+
}
|
|
302933
|
+
}
|
|
302934
|
+
var SOCKETIO_RESERVED_EVENTS = /* @__PURE__ */ new Set(["connect", "connect_error", "disconnect", "disconnecting", "newListener", "removeListener"]);
|
|
302935
|
+
function validateWsBinding(channel, warnings) {
|
|
302936
|
+
const binding = channel.wsBinding;
|
|
302937
|
+
if (!binding) return;
|
|
302938
|
+
const method = binding.method;
|
|
302939
|
+
if (method !== void 0 && (typeof method !== "string" || method !== "GET" && method !== "POST")) {
|
|
302940
|
+
warnings.push(`ASYNCAPI_WS_BINDING_INVALID: channel ${channel.id} ws binding method must be "GET" or "POST" but was ${JSON.stringify(method)}`);
|
|
302941
|
+
}
|
|
302942
|
+
for (const key of ["query", "headers"]) {
|
|
302943
|
+
const schema = binding[key];
|
|
302944
|
+
if (schema === void 0) continue;
|
|
302945
|
+
const record = asRecord16(schema);
|
|
302946
|
+
if (!record || record.type !== void 0 && record.type !== "object") {
|
|
302947
|
+
warnings.push(`ASYNCAPI_WS_BINDING_INVALID: channel ${channel.id} ws binding ${key} must be a Schema Object of type object`);
|
|
302948
|
+
}
|
|
302949
|
+
}
|
|
302950
|
+
}
|
|
302715
302951
|
function instrumentAsyncApiCollection(collection, index) {
|
|
302716
302952
|
const warnings = [
|
|
302717
302953
|
...index.warnings,
|
|
302718
302954
|
...index.channels.flatMap((channel) => channel.warnings)
|
|
302719
302955
|
];
|
|
302720
302956
|
for (const channel of index.channels) {
|
|
302957
|
+
validateChannelParameters(channel, warnings);
|
|
302721
302958
|
if (channel.transport === "mqtt") validateMqttChannel(channel, warnings);
|
|
302959
|
+
if (channel.transport === "ws-raw") validateWsBinding(channel, warnings);
|
|
302722
302960
|
for (const message of channel.messages) {
|
|
302961
|
+
if (channel.transport === "socketio" && SOCKETIO_RESERVED_EVENTS.has(message.eventName)) {
|
|
302962
|
+
warnings.push(
|
|
302963
|
+
`ASYNCAPI_SOCKETIO_RESERVED_EVENT: message ${message.id} on channel ${channel.id} uses the reserved Socket.IO event name "${message.eventName}"; reserved lifecycle events cannot be emitted or received as application events`
|
|
302964
|
+
);
|
|
302965
|
+
}
|
|
302966
|
+
validateCorrelationLocation(channel.id, message, warnings);
|
|
302723
302967
|
validateMessage(index, channel.id, message, warnings);
|
|
302724
302968
|
}
|
|
302725
302969
|
}
|
|
@@ -302897,6 +303141,7 @@ function toolDescriptor(tool, warnings) {
|
|
|
302897
303141
|
description: typeof tool.description === "string" ? tool.description : void 0,
|
|
302898
303142
|
inputSchema,
|
|
302899
303143
|
outputSchema: asRecord17(tool.outputSchema) ?? void 0,
|
|
303144
|
+
annotations: asRecord17(tool.annotations) ?? void 0,
|
|
302900
303145
|
sampleArguments: inputSchema ? sampleFromSchema2(inputSchema, 0) : {},
|
|
302901
303146
|
warnings: toolWarnings
|
|
302902
303147
|
};
|
|
@@ -303097,10 +303342,41 @@ function validateServer(server, warnings) {
|
|
|
303097
303342
|
}
|
|
303098
303343
|
}
|
|
303099
303344
|
}
|
|
303345
|
+
var TOOL_ANNOTATION_BOOLEAN_HINTS = ["readOnlyHint", "destructiveHint", "idempotentHint", "openWorldHint"];
|
|
303346
|
+
function validateToolAnnotations(tool, warnings) {
|
|
303347
|
+
if (!tool.annotations) return;
|
|
303348
|
+
for (const hint of TOOL_ANNOTATION_BOOLEAN_HINTS) {
|
|
303349
|
+
const value = tool.annotations[hint];
|
|
303350
|
+
if (value !== void 0 && typeof value !== "boolean") {
|
|
303351
|
+
warnings.push(`MCP_TOOL_ANNOTATION_INVALID: tool ${tool.name} annotations.${hint} must be a boolean (MCP ToolAnnotations); got ${JSON.stringify(value)}`);
|
|
303352
|
+
}
|
|
303353
|
+
}
|
|
303354
|
+
if (tool.annotations.title !== void 0 && typeof tool.annotations.title !== "string") {
|
|
303355
|
+
warnings.push(`MCP_TOOL_ANNOTATION_INVALID: tool ${tool.name} annotations.title must be a string (MCP ToolAnnotations); got ${JSON.stringify(tool.annotations.title)}`);
|
|
303356
|
+
}
|
|
303357
|
+
}
|
|
303358
|
+
function validateToolOutputSchema(index, tool, warnings) {
|
|
303359
|
+
if (!tool.outputSchema) return;
|
|
303360
|
+
const declaredType = tool.outputSchema.type;
|
|
303361
|
+
if (declaredType !== void 0 && declaredType !== "object") {
|
|
303362
|
+
warnings.push(`MCP_TOOL_OUTPUT_SCHEMA_INVALID: tool ${tool.name} outputSchema type is ${JSON.stringify(declaredType)}; the MCP specification requires tool output schemas to describe the structuredContent object`);
|
|
303363
|
+
}
|
|
303364
|
+
const packed = packSchema(index.documentJson, tool.outputSchema, "3.0", "response");
|
|
303365
|
+
if (packed.unsupported) {
|
|
303366
|
+
const code = isSchemaGraphOverflow(packed) ? "MCP_SCHEMA_NOT_COMPILED" : "MCP_TOOL_OUTPUT_SCHEMA_NOT_VALIDATED";
|
|
303367
|
+
warnings.push(`${code}: tool ${tool.name} outputSchema is not validated (${packed.unsupported})`);
|
|
303368
|
+
return;
|
|
303369
|
+
}
|
|
303370
|
+
if (!compileSchemaValidator(packed.schema)) {
|
|
303371
|
+
warnings.push(`MCP_TOOL_OUTPUT_SCHEMA_NOT_VALIDATED: tool ${tool.name} outputSchema could not be compiled to a validator`);
|
|
303372
|
+
}
|
|
303373
|
+
}
|
|
303100
303374
|
function validateTool(index, tool, warnings) {
|
|
303101
303375
|
if (!TOOL_NAME_RE.test(tool.name)) {
|
|
303102
303376
|
warnings.push(`MCP_TOOL_NAME_UNCONVENTIONAL: tool name "${tool.name}" is outside the conventional [A-Za-z0-9_./-]{1,128} identifier set`);
|
|
303103
303377
|
}
|
|
303378
|
+
validateToolAnnotations(tool, warnings);
|
|
303379
|
+
validateToolOutputSchema(index, tool, warnings);
|
|
303104
303380
|
if (!tool.inputSchema) return;
|
|
303105
303381
|
const declaredType = tool.inputSchema.type;
|
|
303106
303382
|
if (declaredType !== void 0 && declaredType !== "object") {
|