@scalar/mock-server 0.14.0 → 0.14.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @scalar/mock-server
2
2
 
3
+ ## 0.14.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#10190](https://github.com/scalar/scalar/pull/10190): Update Hono to allow HTTP QUERY requests in default CORS preflight responses.
8
+ - [#10164](https://github.com/scalar/scalar/pull/10164): Serve deprecated response schemas from the mock instead of answering a declared JSON response with an empty body, and generate a deprecated AsyncAPI message payload instead of sending `null`. `getExampleFromSchema` takes a new `includeDeprecated` option for callers that must produce a value satisfying the schema. A declared response header that generates no value is now skipped rather than clearing a header of the same name the mock already set, such as the CORS headers.
9
+ - [#10140](https://github.com/scalar/scalar/pull/10140): Replace redundant type assertions with compiler-checked annotations, typed accumulators, and existing guards across helpers, API conversion, request handling, and schema rendering.
10
+
11
+ Narrow DOM elements and caught errors before accessing their properties. Correct header lookup to include missing values and handle them during PowerShell snippet generation.
12
+
13
+ Validate release-note provider responses, represent unresolved references and absent groups in helper return types, and require narrowing merged object values. Preserve AsyncAPI broker credentials separately from HTTP authentication schemes.
14
+
3
15
  ## 0.14.0
4
16
 
5
17
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"file":"create-mock-server.d.ts","sourceRoot":"","sources":["../src/create-mock-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,IAAI,EAA0B,MAAM,MAAM,CAAA;AAIjE,OAAO,KAAK,EAAc,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAwD5D;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,aAAa,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8NtF"}
1
+ {"version":3,"file":"create-mock-server.d.ts","sourceRoot":"","sources":["../src/create-mock-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,IAAI,EAA0B,MAAM,MAAM,CAAA;AAIjE,OAAO,KAAK,EAAc,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAwD5D;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,aAAa,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2NtF"}
@@ -1 +1 @@
1
- {"version":3,"file":"mock-any-response.d.ts","sourceRoot":"","sources":["../../src/routes/mock-any-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAIxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAanC;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,CAAC,eAAe,YA6HjF"}
1
+ {"version":3,"file":"mock-any-response.d.ts","sourceRoot":"","sources":["../../src/routes/mock-any-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAIxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAcnC;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,CAAC,eAAe,YA4HjF"}
@@ -5,6 +5,7 @@ import { accepts } from 'hono/accepts';
5
5
  import { streamSSE } from 'hono/streaming';
6
6
  import { collectSseEvents, isEventStreamContentType } from '../utils/collect-sse-events.js';
7
7
  import { findPreferredResponseKey } from '../utils/find-preferred-response-key.js';
8
+ import { generateResponseExample } from '../utils/generate-response-example.js';
8
9
  import { normalizeResponseBody } from '../utils/normalize-response-body.js';
9
10
  import { parsePreferHeader } from '../utils/parse-prefer-header.js';
10
11
  import { pathParameters } from '../utils/path-parameters.js';
@@ -36,10 +37,15 @@ export function mockAnyResponse(c, operation) {
36
37
  const headers = selectedResponse?.headers ?? {};
37
38
  Object.keys(headers).forEach((header) => {
38
39
  const headerObject = getResolvedRef(headers[header]);
40
+ // Headers need `includeDeprecated` but none of `generateResponseExample`'s other options — see
41
+ // the note on that helper for why passing them would change what declared headers emit.
39
42
  const value = headerObject?.schema
40
- ? getExampleFromSchema(getResolvedRefDeep(headerObject.schema))
43
+ ? getExampleFromSchema(getResolvedRefDeep(headerObject.schema), { includeDeprecated: true })
41
44
  : null;
42
- if (value !== null) {
45
+ // Loose check on purpose: Hono *deletes* a header when handed `undefined`. This loop is the first
46
+ // thing to set the declared headers, so in practice a delete removes a header set earlier by
47
+ // middleware — `cors()` sets `Access-Control-Allow-Origin` before the handler runs.
48
+ if (value != null) {
43
49
  c.header(header, value);
44
50
  }
45
51
  });
@@ -66,13 +72,7 @@ export function mockAnyResponse(c, operation) {
66
72
  const acceptedResponse = selectedResponse?.content?.[acceptedContentType];
67
73
  const responseSchema = acceptedResponse?.schema ? getResolvedRefDeep(acceptedResponse.schema) : undefined;
68
74
  /** Generates the response body from the schema, or returns `undefined` when there is no schema. */
69
- const generateFromSchema = () => responseSchema
70
- ? getExampleFromSchema(responseSchema, {
71
- emptyString: 'string',
72
- variables: pathParameters(c),
73
- mode: 'read',
74
- })
75
- : undefined;
75
+ const generateFromSchema = () => responseSchema ? generateResponseExample(responseSchema, pathParameters(c)) : undefined;
76
76
  // Server-Sent Events are a framed, multi-event wire format, so they cannot go out as one buffered
77
77
  // body: a client reading the stream expects `data:` lines terminated by a blank line. Everything
78
78
  // else (JSON, XML, text) keeps taking the single-body path below.
@@ -1 +1 @@
1
- {"version":3,"file":"mock-handler-response.d.ts","sourceRoot":"","sources":["../../src/routes/mock-handler-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAGxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAqIxD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,CAAC,eAAe,gMA8D3F"}
1
+ {"version":3,"file":"mock-handler-response.d.ts","sourceRoot":"","sources":["../../src/routes/mock-handler-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AA+HxD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,CAAC,eAAe,gMAyD3F"}
@@ -1,8 +1,8 @@
1
1
  import { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref';
2
- import { getExampleFromSchema } from '@scalar/workspace-store/request-example';
3
2
  import { accepts } from 'hono/accepts';
4
3
  import { buildHandlerContext } from '../utils/build-handler-context.js';
5
4
  import { executeHandler } from '../utils/execute-handler.js';
5
+ import { generateResponseExample } from '../utils/generate-response-example.js';
6
6
  import { normalizeResponseBody } from '../utils/normalize-response-body.js';
7
7
  import { parsePreferHeader } from '../utils/parse-prefer-header.js';
8
8
  import { pathParameters } from '../utils/path-parameters.js';
@@ -47,11 +47,7 @@ function getExampleFromResponse(c, statusCode, responses, exampleName) {
47
47
  return selectedExample
48
48
  ? normalizeResponseBody(selectedExample.value, responseSchema)
49
49
  : responseSchema
50
- ? normalizeResponseBody(getExampleFromSchema(responseSchema, {
51
- emptyString: 'string',
52
- variables: pathParameters(c),
53
- mode: 'read',
54
- }), responseSchema)
50
+ ? normalizeResponseBody(generateResponseExample(responseSchema, pathParameters(c)), responseSchema)
55
51
  : null;
56
52
  }
57
53
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"build-handler-context.d.ts","sourceRoot":"","sources":["../../src/utils/build-handler-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAIxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAMnC,OAAO,EAAE,KAAK,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEjF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,cAAc,CAAC,CAAA;IAC5D,GAAG,EAAE;QACH,IAAI,EAAE,GAAG,CAAA;QACT,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAChC,CAAA;IACD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CACzB,CAAA;AAED;;GAEG;AACH,KAAK,oBAAoB,GAAG;IAC1B,OAAO,EAAE,cAAc,CAAA;IACvB,QAAQ,EAAE,sBAAsB,CAAA;CACjC,CAAA;AA4DD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,CAAC,EAAE,OAAO,EACV,SAAS,CAAC,EAAE,WAAW,CAAC,eAAe,GACtC,OAAO,CAAC,oBAAoB,CAAC,CAgD/B"}
1
+ {"version":3,"file":"build-handler-context.d.ts","sourceRoot":"","sources":["../../src/utils/build-handler-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAGxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAOnC,OAAO,EAAE,KAAK,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEjF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,cAAc,CAAC,CAAA;IAC5D,GAAG,EAAE;QACH,IAAI,EAAE,GAAG,CAAA;QACT,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAChC,CAAA;IACD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CACzB,CAAA;AAED;;GAEG;AACH,KAAK,oBAAoB,GAAG;IAC1B,OAAO,EAAE,cAAc,CAAA;IACvB,QAAQ,EAAE,sBAAsB,CAAA;CACjC,CAAA;AAqDD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,CAAC,EAAE,OAAO,EACV,SAAS,CAAC,EAAE,WAAW,CAAC,eAAe,GACtC,OAAO,CAAC,oBAAoB,CAAC,CA4C/B"}
@@ -1,8 +1,8 @@
1
1
  import { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref';
2
2
  import { getResolvedRefDeep } from '@scalar/workspace-store/helpers/get-resolved-ref-deep';
3
- import { getExampleFromSchema } from '@scalar/workspace-store/request-example';
4
3
  import { accepts } from 'hono/accepts';
5
4
  import { store } from '../libs/store.js';
5
+ import { generateResponseExample } from './generate-response-example.js';
6
6
  import { normalizeResponseBody } from './normalize-response-body.js';
7
7
  import { pathParameters } from './path-parameters.js';
8
8
  import { createStoreWrapper } from './store-wrapper.js';
@@ -40,11 +40,7 @@ function getExampleFromResponse(c, statusCode, responses) {
40
40
  return acceptedResponse.example !== undefined
41
41
  ? normalizeResponseBody(acceptedResponse.example, responseSchema)
42
42
  : responseSchema
43
- ? normalizeResponseBody(getExampleFromSchema(responseSchema, {
44
- emptyString: 'string',
45
- variables: pathParameters(c),
46
- mode: 'read',
47
- }), responseSchema)
43
+ ? normalizeResponseBody(generateResponseExample(responseSchema, pathParameters(c)), responseSchema)
48
44
  : null;
49
45
  }
50
46
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"deserialize-parameter.d.ts","sourceRoot":"","sources":["../../src/utils/deserialize-parameter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,oFAAoF;AACpF,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAUtE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,iBAAiB,EAC3B,QAAQ,MAAM,EACd,UAAU,OAAO,KAChB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAGnC,CAAA;AA2BD,8GAA8G;AAC9G,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAG,OAU3E,CAAA;AAED,gHAAgH;AAChH,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAG,OAU5E,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAG,MAAM,EA4B1F,CAAA;AAgGD;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GAAI,oCAKvC;IACD,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,iGAAiG;IACjG,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,uFAAuF;IACvF,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;CAC7B,KAAG,MAAM,EAAE,GAAG,SAoBd,CAAA;AAgCD;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GAAI,qEAQxC;IACD,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,+FAA+F;IAC/F,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,CAAA;IACnD,IAAI,EAAE,MAAM,CAAA;IACZ,mGAAmG;IACnG,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;IACpC;;;;OAIG;IACH,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CAAA;CACvC,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,SAoEvC,CAAA"}
1
+ {"version":3,"file":"deserialize-parameter.d.ts","sourceRoot":"","sources":["../../src/utils/deserialize-parameter.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,oFAAoF;AACpF,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAUtE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,iBAAiB,EAC3B,QAAQ,MAAM,EACd,UAAU,OAAO,KAChB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAGnC,CAAA;AA2BD,8GAA8G;AAC9G,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAG,OAU3E,CAAA;AAED,gHAAgH;AAChH,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAG,OAU5E,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAG,MAAM,EA4B1F,CAAA;AAgGD;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GAAI,oCAKvC;IACD,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,iGAAiG;IACjG,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,uFAAuF;IACvF,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;CAC7B,KAAG,MAAM,EAAE,GAAG,SAoBd,CAAA;AAgCD;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GAAI,qEAQxC;IACD,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,+FAA+F;IAC/F,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,CAAA;IACnD,IAAI,EAAE,MAAM,CAAA;IACZ,mGAAmG;IACnG,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;IACpC;;;;OAIG;IACH,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CAAA;CACvC,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,SAoEvC,CAAA"}
@@ -1,9 +1,4 @@
1
- /**
2
- * Helpers for turning string-encoded request parameters back into the structured values that JSON
3
- * Schema validation expects, following the OpenAPI `style`/`explode` serialization rules.
4
- *
5
- * @see https://spec.openapis.org/oas/v3.1.1.html#style-values
6
- */
1
+ import { isObjectLike } from '@scalar/helpers/object/is-object';
7
2
  /** Default serialization style per parameter location. */
8
3
  const DEFAULT_STYLE = {
9
4
  query: 'form',
@@ -34,7 +29,7 @@ const matchesComposedSchema = (schema, predicate) => {
34
29
  const subSchemas = schema[keyword];
35
30
  if (Array.isArray(subSchemas)) {
36
31
  for (const subSchema of subSchemas) {
37
- if (subSchema && typeof subSchema === 'object' && predicate(subSchema)) {
32
+ if (isObjectLike(subSchema) && predicate(subSchema)) {
38
33
  return true;
39
34
  }
40
35
  }
@@ -87,7 +82,7 @@ export const getObjectPropertyNames = (schema) => {
87
82
  const subSchemas = schema[keyword];
88
83
  if (Array.isArray(subSchemas)) {
89
84
  for (const subSchema of subSchemas) {
90
- if (subSchema && typeof subSchema === 'object') {
85
+ if (isObjectLike(subSchema)) {
91
86
  for (const name of getObjectPropertyNames(subSchema)) {
92
87
  names.add(name);
93
88
  }
@@ -2,7 +2,7 @@ import type { MockMessage, ResolvedChannel } from '../transports/types.js';
2
2
  /**
3
3
  * Generate an encoded mock frame for a channel message — the AsyncAPI analogue of the REST
4
4
  * mocker's response generation. Prefers a defined example, otherwise generates a value from the
5
- * message payload schema with the same `getExampleFromSchema` the HTTP mocker uses.
5
+ * message payload schema through the same `generateResponseExample` the HTTP mocker uses.
6
6
  *
7
7
  * @param channel - The resolved channel to mock a message for.
8
8
  * @param messageId - Which message to emit; defaults to the channel's first message.
@@ -1 +1 @@
1
- {"version":3,"file":"generate-message.d.ts","sourceRoot":"","sources":["../../src/utils/generate-message.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAmB,MAAM,oBAAoB,CAAA;AAWvF;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAwBhG"}
1
+ {"version":3,"file":"generate-message.d.ts","sourceRoot":"","sources":["../../src/utils/generate-message.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAmB,MAAM,oBAAoB,CAAA;AAYvF;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAuBhG"}
@@ -1,5 +1,5 @@
1
1
  import { getResolvedRefDeep } from '@scalar/workspace-store/helpers/get-resolved-ref-deep';
2
- import { getExampleFromSchema } from '@scalar/workspace-store/request-example';
2
+ import { generateResponseExample } from '../utils/generate-response-example.js';
3
3
  /** Encode a generated value to a wire string. Strings pass through; everything else is JSON. */
4
4
  function encode(value) {
5
5
  if (typeof value === 'string') {
@@ -10,7 +10,7 @@ function encode(value) {
10
10
  /**
11
11
  * Generate an encoded mock frame for a channel message — the AsyncAPI analogue of the REST
12
12
  * mocker's response generation. Prefers a defined example, otherwise generates a value from the
13
- * message payload schema with the same `getExampleFromSchema` the HTTP mocker uses.
13
+ * message payload schema through the same `generateResponseExample` the HTTP mocker uses.
14
14
  *
15
15
  * @param channel - The resolved channel to mock a message for.
16
16
  * @param messageId - Which message to emit; defaults to the channel's first message.
@@ -29,10 +29,9 @@ export function generateMessage(channel, messageId) {
29
29
  value = message.examples[0];
30
30
  }
31
31
  else if (message.payload) {
32
- value = getExampleFromSchema(getResolvedRefDeep(message.payload), {
33
- emptyString: 'string',
34
- mode: 'read',
35
- });
32
+ // No `variables`: `generateMessage` is never handed the Hono context, so a channel route's path
33
+ // parameters are not in scope for `x-variable` substitution. It does run per request.
34
+ value = generateResponseExample(getResolvedRefDeep(message.payload));
36
35
  }
37
36
  return {
38
37
  data: encode(value),
@@ -0,0 +1,25 @@
1
+ import { getExampleFromSchema } from '@scalar/workspace-store/request-example';
2
+ /** The schema shape `getExampleFromSchema` accepts, so callers do not have to name it themselves. */
3
+ export type ExampleSchema = Parameters<typeof getExampleFromSchema>[0];
4
+ /**
5
+ * Generate a mocked response value from a schema the mock has declared.
6
+ *
7
+ * Every value the mock puts on the wire — an HTTP body, an SSE frame, a channel message — has to
8
+ * satisfy the schema it was declared with, which is why this passes `includeDeprecated: true`:
9
+ * `deprecated` marks a field as discouraged, not absent, so omitting it answered a declared JSON
10
+ * response with zero bytes and dropped required properties. Owning the option set in one place keeps
11
+ * a newly added response path from quietly missing that.
12
+ *
13
+ * Not for response headers. Two of the options here would change what an already-declared header
14
+ * emits: `emptyString` yields the literal `string` for a bare `type: 'string'` and switches on
15
+ * format-based generation (a `format: 'date-time'` header would emit a fabricated timestamp), and
16
+ * `mode: 'read'` drops a `writeOnly` header entirely. Headers set `includeDeprecated` on their own
17
+ * call instead.
18
+ *
19
+ * @param schema - The resolved schema to generate a value for.
20
+ * @param variables - Values for `x-variable` substitution, usually a request's path parameters.
21
+ * Omitted by callers that have no request in scope, such as channel messages.
22
+ * @returns The generated value, or `undefined` when the schema yields nothing.
23
+ */
24
+ export declare const generateResponseExample: (schema: ExampleSchema, variables?: Record<string, unknown>) => unknown;
25
+ //# sourceMappingURL=generate-response-example.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-response-example.d.ts","sourceRoot":"","sources":["../../src/utils/generate-response-example.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAA;AAE9E,qGAAqG;AACrG,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAA;AAEtE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,aAAa,EAAE,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,OAMjG,CAAA"}
@@ -0,0 +1,27 @@
1
+ import { getExampleFromSchema } from '@scalar/workspace-store/request-example';
2
+ /**
3
+ * Generate a mocked response value from a schema the mock has declared.
4
+ *
5
+ * Every value the mock puts on the wire — an HTTP body, an SSE frame, a channel message — has to
6
+ * satisfy the schema it was declared with, which is why this passes `includeDeprecated: true`:
7
+ * `deprecated` marks a field as discouraged, not absent, so omitting it answered a declared JSON
8
+ * response with zero bytes and dropped required properties. Owning the option set in one place keeps
9
+ * a newly added response path from quietly missing that.
10
+ *
11
+ * Not for response headers. Two of the options here would change what an already-declared header
12
+ * emits: `emptyString` yields the literal `string` for a bare `type: 'string'` and switches on
13
+ * format-based generation (a `format: 'date-time'` header would emit a fabricated timestamp), and
14
+ * `mode: 'read'` drops a `writeOnly` header entirely. Headers set `includeDeprecated` on their own
15
+ * call instead.
16
+ *
17
+ * @param schema - The resolved schema to generate a value for.
18
+ * @param variables - Values for `x-variable` substitution, usually a request's path parameters.
19
+ * Omitted by callers that have no request in scope, such as channel messages.
20
+ * @returns The generated value, or `undefined` when the schema yields nothing.
21
+ */
22
+ export const generateResponseExample = (schema, variables) => getExampleFromSchema(schema, {
23
+ emptyString: 'string',
24
+ variables,
25
+ mode: 'read',
26
+ includeDeprecated: true,
27
+ });
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "swagger",
17
17
  "cli"
18
18
  ],
19
- "version": "0.14.0",
19
+ "version": "0.14.1",
20
20
  "engines": {
21
21
  "node": ">=22"
22
22
  },
@@ -55,15 +55,15 @@
55
55
  "@hono/node-ws": "^1.2.0",
56
56
  "ajv": "^8.20.0",
57
57
  "ajv-formats": "^3.0.1",
58
- "hono": "^4.12.7",
58
+ "hono": "^4.13.7",
59
59
  "quickjs-emscripten": "0.32.0",
60
60
  "yaml": "^2.9.0",
61
- "@scalar/helpers": "0.11.3",
62
- "@scalar/json-magic": "0.13.4",
63
- "@scalar/openapi-types": "0.9.5",
64
- "@scalar/openapi-upgrader": "0.2.15",
65
- "@scalar/types": "0.19.0",
66
- "@scalar/workspace-store": "0.60.0"
61
+ "@scalar/helpers": "0.12.0",
62
+ "@scalar/json-magic": "0.13.5",
63
+ "@scalar/openapi-types": "0.9.6",
64
+ "@scalar/openapi-upgrader": "0.2.16",
65
+ "@scalar/workspace-store": "0.61.0",
66
+ "@scalar/types": "0.20.0"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@types/node": "^24.1.0",