@scalar/workspace-store 0.68.3 → 0.68.5

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.
Files changed (69) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +20 -0
  3. package/dist/channel-example/build-connection-url.d.ts.map +1 -1
  4. package/dist/channel-example/build-connection-url.js +6 -5
  5. package/dist/channel-example/get-all-channel-messages.js +2 -2
  6. package/dist/channel-example/get-async-api-protocols.js +3 -3
  7. package/dist/channel-example/get-asyncapi-security-requirements.d.ts.map +1 -1
  8. package/dist/channel-example/get-asyncapi-security-requirements.js +14 -14
  9. package/dist/channel-example/get-channel-operations.js +2 -2
  10. package/dist/channel-example/get-channel-parameters.js +2 -2
  11. package/dist/channel-example/resolve-channel.js +2 -2
  12. package/dist/channel-example/resolve-operation-channel.js +4 -4
  13. package/dist/channel-example/servers.js +2 -2
  14. package/dist/entities/auth/schema.d.ts +20 -0
  15. package/dist/entities/auth/schema.d.ts.map +1 -1
  16. package/dist/entities/auth/schema.js +2 -0
  17. package/dist/helpers/get-async-api-schema-view.d.ts +8 -0
  18. package/dist/helpers/get-async-api-schema-view.d.ts.map +1 -0
  19. package/dist/helpers/get-async-api-schema-view.js +82 -0
  20. package/dist/helpers/get-resolved-async-api-ref.d.ts +10 -0
  21. package/dist/helpers/get-resolved-async-api-ref.d.ts.map +1 -0
  22. package/dist/helpers/get-resolved-async-api-ref.js +18 -0
  23. package/dist/helpers/resolve-traits.d.ts.map +1 -1
  24. package/dist/helpers/resolve-traits.js +23 -15
  25. package/dist/helpers/snapshot-schema.d.ts +9 -0
  26. package/dist/helpers/snapshot-schema.d.ts.map +1 -0
  27. package/dist/helpers/snapshot-schema.js +38 -0
  28. package/dist/mutators/auth.d.ts +2 -1
  29. package/dist/mutators/auth.d.ts.map +1 -1
  30. package/dist/mutators/auth.js +30 -1
  31. package/dist/mutators/index.d.ts +2 -2
  32. package/dist/navigation/get-navigation-options.d.ts.map +1 -1
  33. package/dist/navigation/get-navigation-options.js +3 -0
  34. package/dist/navigation/helpers/get-tag-external-docs.d.ts +4 -0
  35. package/dist/navigation/helpers/get-tag-external-docs.d.ts.map +1 -0
  36. package/dist/navigation/helpers/get-tag-external-docs.js +6 -0
  37. package/dist/navigation/helpers/traverse-asyncapi-document.d.ts.map +1 -1
  38. package/dist/navigation/helpers/traverse-asyncapi-document.js +51 -19
  39. package/dist/navigation/helpers/traverse-tags.d.ts.map +1 -1
  40. package/dist/navigation/helpers/traverse-tags.js +3 -0
  41. package/dist/request-example/builder/body/get-request-body-example.d.ts +2 -2
  42. package/dist/request-example/builder/body/get-request-body-example.d.ts.map +1 -1
  43. package/dist/request-example/builder/body/get-request-body-example.js +6 -6
  44. package/dist/request-example/builder/helpers/get-example-from-schema.d.ts.map +1 -1
  45. package/dist/request-example/builder/helpers/get-example-from-schema.js +41 -1
  46. package/dist/request-example/context/security/extract-security-scheme-secrets.d.ts.map +1 -1
  47. package/dist/request-example/context/security/extract-security-scheme-secrets.js +2 -0
  48. package/dist/request-example/context/security/merge-security.d.ts.map +1 -1
  49. package/dist/request-example/context/security/merge-security.js +10 -1
  50. package/dist/request-example/context/security/uses-api-key-name-override.d.ts +9 -0
  51. package/dist/request-example/context/security/uses-api-key-name-override.d.ts.map +1 -0
  52. package/dist/request-example/context/security/uses-api-key-name-override.js +9 -0
  53. package/dist/request-example/xml/write-xml.d.ts.map +1 -1
  54. package/dist/request-example/xml/write-xml.js +1 -0
  55. package/dist/schemas/navigation.d.ts +4 -0
  56. package/dist/schemas/navigation.d.ts.map +1 -1
  57. package/dist/schemas/navigation.js +2 -1
  58. package/dist/schemas/reference-config/index.d.ts +2 -0
  59. package/dist/schemas/reference-config/index.d.ts.map +1 -1
  60. package/dist/schemas/reference-config/settings.d.ts +2 -0
  61. package/dist/schemas/reference-config/settings.d.ts.map +1 -1
  62. package/dist/schemas/v3.1/strict/openapi-document.d.ts +70 -0
  63. package/dist/schemas/v3.1/strict/openapi-document.d.ts.map +1 -1
  64. package/dist/schemas/v3.2/strict/openapi-document.d.ts +70 -0
  65. package/dist/schemas/v3.2/strict/openapi-document.d.ts.map +1 -1
  66. package/dist/server.d.ts +7 -0
  67. package/dist/server.d.ts.map +1 -1
  68. package/dist/server.js +12 -5
  69. package/package.json +8 -8
@@ -0,0 +1,82 @@
1
+ import { isObject } from '@scalar/helpers/object/is-object';
2
+ import { getResolvedAsyncApiRef } from './get-resolved-async-api-ref.js';
3
+ const schemaMaps = new Set(['properties', 'patternProperties', 'definitions', '$defs', 'dependentSchemas']);
4
+ const schemaArrays = new Set(['allOf', 'anyOf', 'oneOf', 'prefixItems']);
5
+ const schemaFields = new Set([
6
+ 'items',
7
+ 'additionalItems',
8
+ 'additionalProperties',
9
+ 'contains',
10
+ 'propertyNames',
11
+ 'not',
12
+ 'if',
13
+ 'then',
14
+ 'else',
15
+ 'unevaluatedItems',
16
+ 'unevaluatedProperties',
17
+ ]);
18
+ /**
19
+ * Give shared schema renderers and example generation an AsyncAPI view without authored
20
+ * reference siblings. Keep reference wrappers for model links and traverse only schema
21
+ * positions: examples, defaults, extensions, and property names can contain literal `$ref`s.
22
+ * The snapshot is local to a read so subsequent reactive edits are not hidden by a cache.
23
+ */
24
+ export const getAsyncApiSchemaView = (source, schemaFormat) => {
25
+ // Foreign schema formats own their reference semantics. AsyncAPI's native schemas and
26
+ // its required JSON Schema draft-07 format both ignore reference siblings.
27
+ if (schemaFormat &&
28
+ !/^application\/(?:vnd\.aai\.asyncapi(?:\+json|\+yaml)?(?:;|$)|schema\+(?:json|yaml)(?:;version=draft-07)?$)/i.test(schemaFormat)) {
29
+ return source;
30
+ }
31
+ const seen = new WeakMap();
32
+ const visit = (value) => {
33
+ if (!isObject(value)) {
34
+ return value;
35
+ }
36
+ const existing = seen.get(value);
37
+ if (existing) {
38
+ return existing;
39
+ }
40
+ const result = {};
41
+ seen.set(value, result);
42
+ if (typeof value.$ref === 'string') {
43
+ result.$ref = value.$ref;
44
+ // Bookkeeping belongs to the store, not the authored Reference Object.
45
+ for (const key of ['$global', '$status']) {
46
+ if (Object.hasOwn(value, key)) {
47
+ result[key] = value[key];
48
+ }
49
+ }
50
+ Object.defineProperty(result, '$ref-value', {
51
+ value: visit(getResolvedAsyncApiRef(value)),
52
+ enumerable: true,
53
+ });
54
+ return result;
55
+ }
56
+ for (const [key, child] of Object.entries(value)) {
57
+ Object.defineProperty(result, key, {
58
+ value: visitChild(key, child),
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ });
63
+ }
64
+ return result;
65
+ };
66
+ const visitChild = (key, child) => {
67
+ if (schemaMaps.has(key) && isObject(child)) {
68
+ return Object.fromEntries(Object.entries(child).map(([name, schema]) => [name, visit(schema)]));
69
+ }
70
+ if (key === 'dependencies' && isObject(child)) {
71
+ return Object.fromEntries(Object.entries(child).map(([name, dependency]) => [
72
+ name,
73
+ Array.isArray(dependency) ? dependency : visit(dependency),
74
+ ]));
75
+ }
76
+ if ((schemaArrays.has(key) || key === 'items') && Array.isArray(child)) {
77
+ return child.map(visit);
78
+ }
79
+ return schemaFields.has(key) ? visit(child) : child;
80
+ };
81
+ return visit(source);
82
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * AsyncAPI Reference Objects have no authored siblings. Follow every hop, including
3
+ * references with ignored siblings, and leave missing or circular aliases unresolved.
4
+ * Keep the shared OpenAPI resolver unchanged: its schema resources have different rules.
5
+ */
6
+ export declare const getResolvedAsyncApiRef: <Node>(node: Node | {
7
+ $ref: string;
8
+ "$ref-value"?: Node;
9
+ }) => Node | undefined;
10
+ //# sourceMappingURL=get-resolved-async-api-ref.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-resolved-async-api-ref.d.ts","sourceRoot":"","sources":["../../src/helpers/get-resolved-async-api-ref.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,IAAI,EAAE,MAAM,IAAI,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,IAAI,CAAA;CAAE,KAAG,IAAI,GAAG,SAWxG,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { isObject } from '@scalar/helpers/object/is-object';
2
+ /**
3
+ * AsyncAPI Reference Objects have no authored siblings. Follow every hop, including
4
+ * references with ignored siblings, and leave missing or circular aliases unresolved.
5
+ * Keep the shared OpenAPI resolver unchanged: its schema resources have different rules.
6
+ */
7
+ export const getResolvedAsyncApiRef = (node) => {
8
+ const seen = new Set();
9
+ let current = node;
10
+ while (isObject(current) && typeof current.$ref === 'string') {
11
+ if (seen.has(current)) {
12
+ return undefined;
13
+ }
14
+ seen.add(current);
15
+ current = current['$ref-value'];
16
+ }
17
+ return current;
18
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-traits.d.ts","sourceRoot":"","sources":["../../src/helpers/resolve-traits.ts"],"names":[],"mappings":"AAoEA,uFAAuF;AACvF,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,SAAS,MAAM,EAAE,KAAG,CAetF,CAAA"}
1
+ {"version":3,"file":"resolve-traits.d.ts","sourceRoot":"","sources":["../../src/helpers/resolve-traits.ts"],"names":[],"mappings":"AA4EA,uFAAuF;AACvF,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,SAAS,MAAM,EAAE,KAAG,CAetF,CAAA"}
@@ -1,7 +1,23 @@
1
1
  import { isObject } from '@scalar/helpers/object/is-object';
2
- import { getResolvedRef } from './get-resolved-ref.js';
2
+ import { getResolvedAsyncApiRef } from './get-resolved-async-api-ref.js';
3
3
  const schemaMaps = new Set(['properties', 'patternProperties', '$defs', 'definitions', 'dependentSchemas']);
4
4
  const dataFields = new Set(['example', 'examples', 'default', 'enum', 'const', 'value', 'dataValue']);
5
+ /** Select how the next trait field treats schema references and literal data. */
6
+ const getChildContext = (context, key) => {
7
+ if (context === 'data') {
8
+ return 'data';
9
+ }
10
+ if (context === 'map') {
11
+ return 'object';
12
+ }
13
+ if (key === 'channel') {
14
+ return 'reference';
15
+ }
16
+ if (dataFields.has(key) || key.startsWith('x-')) {
17
+ return 'data';
18
+ }
19
+ return schemaMaps.has(key) ? 'map' : 'object';
20
+ };
5
21
  /**
6
22
  * Apply JSON Merge Patch to resolved trait fields. Unlike mergeObjects, null removes a key.
7
23
  * Resolve schema references before merging so a message can extend referenced trait headers.
@@ -11,7 +27,7 @@ const mergeTraitFields = (target, patch, context = 'object', ancestors = new Wea
11
27
  if (context === 'reference') {
12
28
  return patch;
13
29
  }
14
- const resolvedPatch = context === 'object' && isObject(patch) && typeof patch.$ref === 'string' ? getResolvedRef(patch) : patch;
30
+ const resolvedPatch = context === 'object' && isObject(patch) && typeof patch.$ref === 'string' ? getResolvedAsyncApiRef(patch) : patch;
15
31
  if (!isObject(resolvedPatch)) {
16
32
  return resolvedPatch;
17
33
  }
@@ -19,7 +35,9 @@ const mergeTraitFields = (target, patch, context = 'object', ancestors = new Wea
19
35
  if (ancestors.has(resolvedPatch)) {
20
36
  return ancestors.get(resolvedPatch);
21
37
  }
22
- const resolvedTarget = context === 'object' && isObject(target) && typeof target.$ref === 'string' ? getResolvedRef(target) : target;
38
+ const resolvedTarget = context === 'object' && isObject(target) && typeof target.$ref === 'string'
39
+ ? getResolvedAsyncApiRef(target)
40
+ : target;
23
41
  const result = isObject(resolvedTarget) ? { ...resolvedTarget } : {};
24
42
  ancestors.set(resolvedPatch, result);
25
43
  for (const [key, value] of Object.entries(resolvedPatch)) {
@@ -28,17 +46,7 @@ const mergeTraitFields = (target, patch, context = 'object', ancestors = new Wea
28
46
  }
29
47
  else if (value !== undefined) {
30
48
  // Schema names and example data can contain literal $ref keys without being references.
31
- const childContext = context === 'data'
32
- ? 'data'
33
- : context === 'map'
34
- ? 'object'
35
- : key === 'channel'
36
- ? 'reference'
37
- : dataFields.has(key) || key.startsWith('x-')
38
- ? 'data'
39
- : schemaMaps.has(key)
40
- ? 'map'
41
- : 'object';
49
+ const childContext = getChildContext(context, key);
42
50
  // Define an own property even for schema properties named __proto__.
43
51
  Object.defineProperty(result, key, {
44
52
  value: mergeTraitFields(Object.hasOwn(result, key) ? result[key] : undefined, value, childContext, ancestors),
@@ -57,7 +65,7 @@ export const resolveTraits = (target, traits) => {
57
65
  return target;
58
66
  }
59
67
  const inherited = traits.reduce((fields, trait) => {
60
- const resolved = getResolvedRef(trait);
68
+ const resolved = getResolvedAsyncApiRef(trait);
61
69
  return resolved ? mergeTraitFields(fields, resolved) : fields;
62
70
  }, {});
63
71
  // Only overlay fields supplied by traits. Unrelated fields keep their references and identity.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Snapshot each schema object once, retaining shared and recursive references.
3
+ * Unpacking is shallow: use the raw object only for identity and ownership, then
4
+ * read through the proxy so reactive edits remain tracked and references resolve.
5
+ * Synthetic reference targets stay accessible to the generator but are omitted
6
+ * when literal example data is serialized.
7
+ */
8
+ export declare const snapshotSchema: <T>(source: T, seen?: WeakMap<object, object>) => T;
9
+ //# sourceMappingURL=snapshot-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-schema.d.ts","sourceRoot":"","sources":["../../src/helpers/snapshot-schema.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,8BAAoC,KAAG,CA+BnF,CAAA"}
@@ -0,0 +1,38 @@
1
+ import { unpackProxyShallow } from '../helpers/unpack-proxy.js';
2
+ /**
3
+ * Snapshot each schema object once, retaining shared and recursive references.
4
+ * Unpacking is shallow: use the raw object only for identity and ownership, then
5
+ * read through the proxy so reactive edits remain tracked and references resolve.
6
+ * Synthetic reference targets stay accessible to the generator but are omitted
7
+ * when literal example data is serialized.
8
+ */
9
+ export const snapshotSchema = (source, seen = new WeakMap()) => {
10
+ if (typeof source !== 'object' || source === null) {
11
+ return source;
12
+ }
13
+ const raw = unpackProxyShallow(source);
14
+ const existing = seen.get(raw);
15
+ if (existing) {
16
+ return existing;
17
+ }
18
+ const snapshot = Array.isArray(source) ? [] : {};
19
+ seen.set(raw, snapshot);
20
+ for (const key of Object.keys(source)) {
21
+ // Data descriptors also preserve literal __proto__ and inherited accessor names.
22
+ Object.defineProperty(snapshot, key, {
23
+ value: snapshotSchema(Reflect.get(source, key), seen),
24
+ enumerable: key !== '$ref-value' || Object.hasOwn(raw, key),
25
+ configurable: true,
26
+ writable: true,
27
+ });
28
+ }
29
+ // Static document loaders can keep reference targets non-enumerable.
30
+ if ('$ref' in source && '$ref-value' in source && !Object.hasOwn(snapshot, '$ref-value')) {
31
+ Object.defineProperty(snapshot, '$ref-value', {
32
+ value: snapshotSchema(Reflect.get(source, '$ref-value'), seen),
33
+ configurable: true,
34
+ writable: true,
35
+ });
36
+ }
37
+ return snapshot;
38
+ };
@@ -1,3 +1,4 @@
1
+ import type { AuthenticationConfiguration } from '@scalar/types/api-reference';
1
2
  import type { WorkspaceStore } from '../client.js';
2
3
  import type { AuthEvents } from '../events/definitions/auth.js';
3
4
  import type { WorkspaceDocument } from '../schemas.js';
@@ -155,7 +156,7 @@ export declare const authMutatorsFactory: ({ document, store, }: {
155
156
  }) => {
156
157
  updateSelectedSecuritySchemes: (payload: AuthEvents["auth:update:selected-security-schemes"]) => Promise<void>;
157
158
  clearSelectedSecuritySchemes: (payload: AuthEvents["auth:clear:selected-security-schemes"]) => void;
158
- updateSecurityScheme: (payload: AuthEvents["auth:update:security-scheme"]) => SecuritySchemeObject | undefined;
159
+ updateSecurityScheme: (data: AuthEvents["auth:update:security-scheme"], configuredSchemes?: AuthenticationConfiguration["securitySchemes"]) => SecuritySchemeObject | undefined;
159
160
  updateSecuritySchemeSecrets: (payload: AuthEvents["auth:update:security-scheme-secrets"]) => void;
160
161
  resetSecuritySchemeSecret: (payload: AuthEvents["auth:reset:security-scheme-secret"]) => void;
161
162
  clearSecuritySchemeSecrets: (payload: AuthEvents["auth:clear:security-scheme-secrets"]) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/mutators/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAU3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAGlD,OAAO,KAAK,EAAgB,oBAAoB,EAAE,MAAM,uCAAuC,CAAA;AAuC/F;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,6BAA6B,GACxC,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,4CAA4C,UAAU,CAAC,uCAAuC,CAAC,kBAgFhG,CAAA;AAwBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,iBAAiB,GAAG,IAAI,EAClC,mBAAmB,UAAU,CAAC,6BAA6B,CAAC,qCAwB7D,CAAA;AAqED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,qBAAqB,GAChC,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,iBAAiB,UAAU,CAAC,0BAA0B,CAAC,SAgDxD,CAAA;AAaD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,6CAA6C,UAAU,CAAC,6BAA6B,CAAC,SA0EvF,CAAA;AAqED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,GACtB,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,0DAA0D,UAAU,CAAC,oBAAoB,CAAC,SA2D3F,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,GACtB,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,2BAA2B,UAAU,CAAC,oBAAoB,CAAC,SAwB5D,CAAA;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,WAAW,UAAU,CAAC,6BAA6B,CAAC,SAsFrD,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,sBAGjC;IACD,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAA;IAClC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAA;CAC7B;6CAE4C,UAAU,CAAC,uCAAuC,CAAC;4CAEpD,UAAU,CAAC,sCAAsC,CAAC;oCAE1D,UAAU,CAAC,6BAA6B,CAAC;2CAElC,UAAU,CAAC,qCAAqC,CAAC;yCAEnD,UAAU,CAAC,mCAAmC,CAAC;0CAE9C,UAAU,CAAC,oCAAoC,CAAC;qCAErD,UAAU,CAAC,0BAA0B,CAAC;oCAEvC,UAAU,CAAC,6BAA6B,CAAC;2BAElD,UAAU,CAAC,oBAAoB,CAAC;2BAChC,UAAU,CAAC,oBAAoB,CAAC;oCACvB,UAAU,CAAC,6BAA6B,CAAC;CAG5E,CAAA"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/mutators/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAA;AAE9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAW3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAGlD,OAAO,KAAK,EAAgB,oBAAoB,EAAE,MAAM,uCAAuC,CAAA;AAuC/F;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,6BAA6B,GACxC,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,4CAA4C,UAAU,CAAC,uCAAuC,CAAC,kBAgFhG,CAAA;AAwBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,iBAAiB,GAAG,IAAI,EAClC,mBAAmB,UAAU,CAAC,6BAA6B,CAAC,qCAwB7D,CAAA;AAqED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,qBAAqB,GAChC,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,iBAAiB,UAAU,CAAC,0BAA0B,CAAC,SAgDxD,CAAA;AAaD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,6CAA6C,UAAU,CAAC,6BAA6B,CAAC,SA0EvF,CAAA;AAqED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,GACtB,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,0DAA0D,UAAU,CAAC,oBAAoB,CAAC,SA2D3F,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,GACtB,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,2BAA2B,UAAU,CAAC,oBAAoB,CAAC,SAwB5D,CAAA;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,cAAc,GAAG,IAAI,EAC5B,UAAU,iBAAiB,GAAG,IAAI,EAClC,WAAW,UAAU,CAAC,6BAA6B,CAAC,SAsFrD,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,sBAGjC;IACD,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAA;IAClC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAA;CAC7B;6CAE4C,UAAU,CAAC,uCAAuC,CAAC;4CAEpD,UAAU,CAAC,sCAAsC,CAAC;iCAGlF,UAAU,CAAC,6BAA6B,CAAC,sBAC5B,2BAA2B,CAAC,iBAAiB,CAAC,KAChE,oBAAoB,GAAG,SAAS;2CAgCI,UAAU,CAAC,qCAAqC,CAAC;yCAEnD,UAAU,CAAC,mCAAmC,CAAC;0CAE9C,UAAU,CAAC,oCAAoC,CAAC;qCAErD,UAAU,CAAC,0BAA0B,CAAC;oCAEvC,UAAU,CAAC,6BAA6B,CAAC;2BAElD,UAAU,CAAC,oBAAoB,CAAC;2BAChC,UAAU,CAAC,oBAAoB,CAAC;oCACvB,UAAU,CAAC,6BAA6B,CAAC;CAG5E,CAAA"}
@@ -7,6 +7,7 @@ import { isNonOptionalSecurityRequirement } from '../helpers/is-non-optional-sec
7
7
  import { mergeObjects } from '../helpers/merge-object.js';
8
8
  import { unpackProxyObject } from '../helpers/unpack-proxy.js';
9
9
  import { getSelectedSecurity } from '../request-example/context/security/get-selected-security.js';
10
+ import { usesApiKeyNameOverride } from '../request-example/context/security/uses-api-key-name-override.js';
10
11
  import { isAsyncApiDocument, isOpenApiDocument } from '../schemas/type-guards.js';
11
12
  /**
12
13
  * The auth-store key for a document's selection and secret state.
@@ -617,7 +618,35 @@ export const authMutatorsFactory = ({ document, store, }) => {
617
618
  return {
618
619
  updateSelectedSecuritySchemes: (payload) => updateSelectedSecuritySchemes(store, document, payload),
619
620
  clearSelectedSecuritySchemes: (payload) => clearSelectedSecuritySchemes(store, document, payload),
620
- updateSecurityScheme: (payload) => updateSecurityScheme(document, payload),
621
+ updateSecurityScheme: (data, configuredSchemes = {}) => {
622
+ const { payload, name } = data;
623
+ if (payload.type !== 'apiKey' || payload.name === undefined) {
624
+ return updateSecurityScheme(document, data);
625
+ }
626
+ const configured = Object.hasOwn(configuredSchemes, name) ? configuredSchemes[name] : undefined;
627
+ const documentScheme = getResolvedRef(getDocumentSecuritySchemes(document)[name]);
628
+ if (!configured || !usesApiKeyNameOverride(configured, documentScheme)) {
629
+ // Document-backed names must remain available to export and synchronization.
630
+ const updated = updateSecurityScheme(document, data);
631
+ const documentName = getAuthDocumentName(document);
632
+ const secrets = documentName ? store?.auth.getAuthSecrets(documentName, name) : undefined;
633
+ // Only release an existing override, so typing a name does not write secrets on every keystroke.
634
+ if (updated && secrets?.type === 'apiKey' && secrets.name !== undefined) {
635
+ updateSecuritySchemeSecrets(store, document, { name, payload: { type: 'apiKey', name: undefined } });
636
+ }
637
+ return updated;
638
+ }
639
+ const defaultName = ('name' in configured ? configured.name : undefined) ??
640
+ (documentScheme && typeof documentScheme === 'object' && 'name' in documentScheme
641
+ ? documentScheme.name
642
+ : undefined);
643
+ // Restoring the default releases the override without clearing the API key token.
644
+ updateSecuritySchemeSecrets(store, document, {
645
+ name,
646
+ payload: { type: 'apiKey', name: payload.name === defaultName ? undefined : payload.name },
647
+ });
648
+ return undefined;
649
+ },
621
650
  updateSecuritySchemeSecrets: (payload) => updateSecuritySchemeSecrets(store, document, payload),
622
651
  resetSecuritySchemeSecret: (payload) => resetSecuritySchemeSecret(store, document, payload),
623
652
  clearSecuritySchemeSecrets: (payload) => clearSecuritySchemeSecrets(store, document, payload),
@@ -66,7 +66,7 @@ export declare function generateClientMutators(store: WorkspaceStore | null): {
66
66
  auth: {
67
67
  updateSelectedSecuritySchemes: (payload: import("../events/definitions/auth.js").AuthEvents["auth:update:selected-security-schemes"]) => Promise<void>;
68
68
  clearSelectedSecuritySchemes: (payload: import("../events/definitions/auth.js").AuthEvents["auth:clear:selected-security-schemes"]) => void;
69
- updateSecurityScheme: (payload: import("../events/definitions/auth.js").AuthEvents["auth:update:security-scheme"]) => import("../schemas/v3.2/strict/security-scheme.js").SecuritySchemeObject | undefined;
69
+ updateSecurityScheme: (data: import("../events/definitions/auth.js").AuthEvents["auth:update:security-scheme"], configuredSchemes?: import("@scalar/types/api-reference").AuthenticationConfiguration["securitySchemes"]) => import("../schemas/v3.2/strict/security-scheme.js").SecuritySchemeObject | undefined;
70
70
  updateSecuritySchemeSecrets: (payload: import("../events/definitions/auth.js").AuthEvents["auth:update:security-scheme-secrets"]) => void;
71
71
  resetSecuritySchemeSecret: (payload: import("../events/definitions/auth.js").AuthEvents["auth:reset:security-scheme-secret"]) => void;
72
72
  clearSecuritySchemeSecrets: (payload: import("../events/definitions/auth.js").AuthEvents["auth:clear:security-scheme-secrets"]) => void;
@@ -158,7 +158,7 @@ export declare function generateClientMutators(store: WorkspaceStore | null): {
158
158
  auth: {
159
159
  updateSelectedSecuritySchemes: (payload: import("../events/definitions/auth.js").AuthEvents["auth:update:selected-security-schemes"]) => Promise<void>;
160
160
  clearSelectedSecuritySchemes: (payload: import("../events/definitions/auth.js").AuthEvents["auth:clear:selected-security-schemes"]) => void;
161
- updateSecurityScheme: (payload: import("../events/definitions/auth.js").AuthEvents["auth:update:security-scheme"]) => import("../schemas/v3.2/strict/security-scheme.js").SecuritySchemeObject | undefined;
161
+ updateSecurityScheme: (data: import("../events/definitions/auth.js").AuthEvents["auth:update:security-scheme"], configuredSchemes?: import("@scalar/types/api-reference").AuthenticationConfiguration["securitySchemes"]) => import("../schemas/v3.2/strict/security-scheme.js").SecuritySchemeObject | undefined;
162
162
  updateSecuritySchemeSecrets: (payload: import("../events/definitions/auth.js").AuthEvents["auth:update:security-scheme-secrets"]) => void;
163
163
  resetSecuritySchemeSecret: (payload: import("../events/definitions/auth.js").AuthEvents["auth:reset:security-scheme-secret"]) => void;
164
164
  clearSecuritySchemeSecrets: (payload: import("../events/definitions/auth.js").AuthEvents["auth:clear:security-scheme-secrets"]) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"get-navigation-options.d.ts","sourceRoot":"","sources":["../../src/navigation/get-navigation-options.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,4BAA4B,EAAgC,MAAM,6BAA6B,CAAA;AAE7G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAe7D,MAAM,MAAM,iBAAiB,GACzB,OAAO,CACL,IAAI,CACF,4BAA4B,EAC1B,qBAAqB,GACrB,iBAAiB,GACjB,uBAAuB,GACvB,qBAAqB,GACrB,mBAAmB,GACnB,kBAAkB,GAClB,YAAY,GACZ,YAAY,GACZ,oBAAoB,GACpB,sBAAsB,CACzB,CACF,GACD,SAAS,CAAA;AAEb;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,cAAc,MAAM,EAAE,UAAU,iBAAiB,KAAG,mBAyJxF,CAAA"}
1
+ {"version":3,"file":"get-navigation-options.d.ts","sourceRoot":"","sources":["../../src/navigation/get-navigation-options.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,4BAA4B,EAAgC,MAAM,6BAA6B,CAAA;AAE7G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAe7D,MAAM,MAAM,iBAAiB,GACzB,OAAO,CACL,IAAI,CACF,4BAA4B,EAC1B,qBAAqB,GACrB,iBAAiB,GACjB,uBAAuB,GACvB,qBAAqB,GACrB,mBAAmB,GACnB,kBAAkB,GAClB,YAAY,GACZ,YAAY,GACZ,oBAAoB,GACpB,sBAAsB,CACzB,CACF,GACD,SAAS,CAAA;AAEb;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,cAAc,MAAM,EAAE,UAAU,iBAAiB,KAAG,mBA6JxF,CAAA"}
@@ -87,6 +87,9 @@ export const getNavigationOptions = (documentName, options) => {
87
87
  }
88
88
  // -------- Default webhook id generation logic --------
89
89
  if (props.type === 'webhook') {
90
+ if (!props.name && props.method === undefined) {
91
+ return `${documentId}/webhooks`;
92
+ }
90
93
  const prefixTag = props.parentTag
91
94
  ? `${generateId({
92
95
  type: 'tag',
@@ -0,0 +1,4 @@
1
+ import type { ExternalDocumentationObject, TagObject } from '../../schemas/v3.2/strict/openapi-document.js';
2
+ /** Navigation is cloned and persisted, so keep documentation as plain display metadata. */
3
+ export declare const getTagExternalDocs: (tag: TagObject) => ExternalDocumentationObject | undefined;
4
+ //# sourceMappingURL=get-tag-external-docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-tag-external-docs.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/get-tag-external-docs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAA;AAEpG,2FAA2F;AAC3F,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,KAAG,2BAA2B,GAAG,SAGjF,CAAA"}
@@ -0,0 +1,6 @@
1
+ import { getResolvedRef } from '../../helpers/get-resolved-ref.js';
2
+ /** Navigation is cloned and persisted, so keep documentation as plain display metadata. */
3
+ export const getTagExternalDocs = (tag) => {
4
+ const documentation = getResolvedRef(tag.externalDocs);
5
+ return documentation ? { url: documentation.url, description: documentation.description } : undefined;
6
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"traverse-asyncapi-document.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/traverse-asyncapi-document.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAyB,gBAAgB,EAA2B,MAAM,4BAA4B,CAAA;AAOlH,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,qCAAqC,CAAA;AAOlG,OAAO,KAAK,EAKV,iBAAiB,EAGlB,MAAM,sBAAsB,CAAA;AAM7B,oFAAoF;AACpF,KAAK,wCAAwC,GAAG,gBAAgB,GAAG;IACjE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AA0iBD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,GACnC,cAAc,MAAM,EACpB,UAAU,wCAAwC,EAClD,UAAU,iBAAiB,KAC1B,iBA+HF,CAAA"}
1
+ {"version":3,"file":"traverse-asyncapi-document.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/traverse-asyncapi-document.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAyB,gBAAgB,EAA2B,MAAM,4BAA4B,CAAA;AAOlH,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,qCAAqC,CAAA;AAQlG,OAAO,KAAK,EAKV,iBAAiB,EAGlB,MAAM,sBAAsB,CAAA;AAM7B,oFAAoF;AACpF,KAAK,wCAAwC,GAAG,gBAAgB,GAAG;IACjE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAqjBD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,GACnC,cAAc,MAAM,EACpB,UAAU,wCAAwC,EAClD,UAAU,iBAAiB,KAC1B,iBAsJF,CAAA"}
@@ -2,11 +2,12 @@ import { sortByOrder } from '@scalar/helpers/array/sort-by-order';
2
2
  import { objectKeys } from '@scalar/helpers/object/object-keys';
3
3
  import { resolveOperationWithTraits } from '../../channel-example/resolve-operation-with-traits.js';
4
4
  import { getNameFromRef } from '../../helpers/get-name-from-ref.js';
5
- import { getResolvedRef, mergeSiblingReferences } from '../../helpers/get-resolved-ref.js';
5
+ import { getResolvedAsyncApiRef } from '../../helpers/get-resolved-async-api-ref.js';
6
6
  import { isHidden } from '../../helpers/is-hidden.js';
7
7
  import { unpackProxyObject } from '../../helpers/unpack-proxy.js';
8
8
  import { getNavigationOptions } from '../../navigation/get-navigation-options.js';
9
9
  import { getTag } from '../../navigation/helpers/get-tag.js';
10
+ import { getTagExternalDocs } from '../../navigation/helpers/get-tag-external-docs.js';
10
11
  import { traverseDescription } from '../../navigation/helpers/traverse-description.js';
11
12
  import { traverseSchemas } from '../../navigation/helpers/traverse-schemas.js';
12
13
  /**
@@ -63,10 +64,8 @@ const resolveOperationChannel = (document, operation) => {
63
64
  if (!channelEntry) {
64
65
  return undefined;
65
66
  }
66
- return {
67
- channelName,
68
- channel: getResolvedRef(channelEntry, mergeSiblingReferences),
69
- };
67
+ const channel = getResolvedAsyncApiRef(channelEntry);
68
+ return channel ? { channelName, channel } : undefined;
70
69
  };
71
70
  /**
72
71
  * Resolves which channel message names an operation references.
@@ -108,11 +107,18 @@ const resolveOperationMessageNames = (operation, channel, channelName) => {
108
107
  * used by the shared tag navigation helpers.
109
108
  */
110
109
  const toTagObject = (tag) => {
111
- const resolved = getResolvedRef(tag, mergeSiblingReferences);
112
- return {
113
- name: resolved.name,
114
- description: resolved.description,
115
- };
110
+ const resolved = getResolvedAsyncApiRef(tag);
111
+ if (!resolved) {
112
+ return [];
113
+ }
114
+ const externalDocs = getResolvedAsyncApiRef(resolved.externalDocs);
115
+ return [
116
+ {
117
+ name: resolved.name,
118
+ ...(resolved.description !== undefined ? { description: resolved.description } : {}),
119
+ ...(externalDocs ? { externalDocs } : {}),
120
+ },
121
+ ];
116
122
  };
117
123
  /**
118
124
  * Sorts operation navigation entries in place using the workspace `operationsSorter` option.
@@ -145,8 +151,8 @@ const createMessageEntries = ({ channelName, channel, parentId, messageNames, ge
145
151
  if (!messageNode) {
146
152
  return [];
147
153
  }
148
- const message = getResolvedRef(messageNode, mergeSiblingReferences);
149
- if (isHidden(message)) {
154
+ const message = getResolvedAsyncApiRef(messageNode);
155
+ if (!message || isHidden(message)) {
150
156
  return [];
151
157
  }
152
158
  return [
@@ -269,6 +275,7 @@ const createTagEntry = ({ tag, generateId, children, parentId, }) => {
269
275
  parentId,
270
276
  isGroup: false,
271
277
  });
278
+ const externalDocs = getTagExternalDocs(tag);
272
279
  const title = tag['x-displayName'] ?? tag.name ?? 'Untitled Tag';
273
280
  tag['x-scalar-order'] = children.map((child) => child.id);
274
281
  return {
@@ -277,6 +284,7 @@ const createTagEntry = ({ tag, generateId, children, parentId, }) => {
277
284
  title,
278
285
  name: tag.name || title,
279
286
  description: tag.description,
287
+ ...(externalDocs ? { externalDocs } : {}),
280
288
  children,
281
289
  isGroup: false,
282
290
  isWebhooks: false,
@@ -325,7 +333,7 @@ const getOrCreateChannelBucket = (channelBuckets, channelName, channel) => {
325
333
  channelName,
326
334
  channel,
327
335
  channelAddress: getChannelAddress(channelName, channel),
328
- channelTags: channel.tags?.map(toTagObject) ?? [],
336
+ channelTags: channel.tags?.flatMap(toTagObject) ?? [],
329
337
  operations: [],
330
338
  };
331
339
  channelBuckets.set(channelName, bucket);
@@ -344,8 +352,8 @@ const collectChannelBuckets = (document) => {
344
352
  if (!channelNode) {
345
353
  continue;
346
354
  }
347
- const channel = getResolvedRef(channelNode, mergeSiblingReferences);
348
- if (isHidden(channel)) {
355
+ const channel = getResolvedAsyncApiRef(channelNode);
356
+ if (!channel || isHidden(channel)) {
349
357
  continue;
350
358
  }
351
359
  getOrCreateChannelBucket(channelBuckets, channelName, channel);
@@ -354,7 +362,11 @@ const collectChannelBuckets = (document) => {
354
362
  if (!operationNode) {
355
363
  continue;
356
364
  }
357
- const operation = resolveOperationWithTraits(getResolvedRef(operationNode, mergeSiblingReferences));
365
+ const resolvedOperation = getResolvedAsyncApiRef(operationNode);
366
+ if (!resolvedOperation) {
367
+ continue;
368
+ }
369
+ const operation = resolveOperationWithTraits(resolvedOperation);
358
370
  const resolved = resolveOperationChannel(document, operation);
359
371
  if (!resolved) {
360
372
  continue;
@@ -391,6 +403,14 @@ export const traverseAsyncApiDocument = (documentName, document, options) => {
391
403
  const channelBuckets = collectChannelBuckets(document);
392
404
  const tagsMap = new Map();
393
405
  const untaggedChannels = [];
406
+ // Info-level tags own their metadata and links, rather than contributing introduction links.
407
+ for (const tag of (document.info.tags ?? []).flatMap(toTagObject)) {
408
+ if (!tag.name) {
409
+ continue;
410
+ }
411
+ const entry = getTag({ tagsMap, name: tag.name, documentId, generateId });
412
+ entry.tag = tag;
413
+ }
394
414
  for (const bucket of channelBuckets.values()) {
395
415
  // Operation-level tags are intentionally skipped for now: every operation is rendered
396
416
  // under its channel, and only the channel's own tags drive tag grouping below.
@@ -410,7 +430,9 @@ export const traverseAsyncApiDocument = (documentName, document, options) => {
410
430
  // Channels can declare their own tags independently of any operation tags.
411
431
  for (const tag of bucket.channelTags) {
412
432
  const tagName = tag.name ?? 'Untitled Tag';
413
- const { id: tagId, entries } = getTag({ tagsMap, name: tagName, documentId, generateId });
433
+ const tagEntry = getTag({ tagsMap, name: tagName, documentId, generateId });
434
+ tagEntry.tag = { ...tagEntry.tag, ...tag };
435
+ const { id: tagId, entries } = tagEntry;
414
436
  const alreadyRegistered = entries.some((entry) => entry.type === 'asyncapi-channel' && entry.channelName === bucket.channelName);
415
437
  if (alreadyRegistered) {
416
438
  continue;
@@ -438,9 +460,19 @@ export const traverseAsyncApiDocument = (documentName, document, options) => {
438
460
  // typed against the OpenAPI document. We hand it the resolved `components` (so a `$ref`-only
439
461
  // wrapper still exposes its schemas) wrapped in a minimal document; the cast bridges the single
440
462
  // overlapping field, since AsyncAPI and OpenAPI documents are otherwise distinct types.
441
- const components = document.components ? getResolvedRef(document.components, mergeSiblingReferences) : undefined;
463
+ const components = document.components ? getResolvedAsyncApiRef(document.components) : undefined;
442
464
  const untaggedModels = !hideModels && components?.schemas
443
- ? traverseSchemas({ documentId, document: { components }, generateId, tagsMap })
465
+ ? traverseSchemas({
466
+ documentId,
467
+ document: {
468
+ components: {
469
+ ...components,
470
+ schemas: Object.fromEntries(Object.entries(components.schemas).map(([name, schema]) => [name, getResolvedAsyncApiRef(schema)])),
471
+ },
472
+ },
473
+ generateId,
474
+ tagsMap,
475
+ })
444
476
  : [];
445
477
  // Surface the Introduction entry plus any headings extracted from `info.description`
446
478
  // before the channel/tag entries, mirroring how OpenAPI documents are traversed.
@@ -1 +1 @@
1
- {"version":3,"file":"traverse-tags.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/traverse-tags.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACtE,OAAO,KAAK,EAAE,cAAc,EAAgB,MAAM,sBAAsB,CAAA;AACxE,OAAO,KAAK,EAAE,eAAe,EAAa,MAAM,wCAAwC,CAAA;AAIxF,KAAK,OAAO,GAAG,IAAI,CAAC,mBAAmB,EAAE,YAAY,GAAG,kBAAkB,GAAG,YAAY,CAAC,CAAA;AAmS1F;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAI,2FAK1B;IACD,QAAQ,EAAE,eAAe,CAAA;IACzB,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;CACjB,KAAG,cAAc,EAuEjB,CAAA"}
1
+ {"version":3,"file":"traverse-tags.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/traverse-tags.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACtE,OAAO,KAAK,EAAE,cAAc,EAAgB,MAAM,sBAAsB,CAAA;AACxE,OAAO,KAAK,EAAE,eAAe,EAAa,MAAM,wCAAwC,CAAA;AAIxF,KAAK,OAAO,GAAG,IAAI,CAAC,mBAAmB,EAAE,YAAY,GAAG,kBAAkB,GAAG,YAAY,CAAC,CAAA;AAqS1F;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAI,2FAK1B;IACD,QAAQ,EAAE,eAAe,CAAA;IACzB,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;CACjB,KAAG,cAAc,EAuEjB,CAAA"}
@@ -2,6 +2,7 @@ import { sortByOrder } from '@scalar/helpers/array/sort-by-order';
2
2
  import { getTagKind } from '../../helpers/get-tag-kind.js';
3
3
  import { isHidden } from '../../helpers/is-hidden.js';
4
4
  import { unpackProxyObject } from '../../helpers/unpack-proxy.js';
5
+ import { getTagExternalDocs } from '../../navigation/helpers/get-tag-external-docs.js';
5
6
  import { getXKeysFromObject } from '../../navigation/helpers/get-x-keys.js';
6
7
  import { getTag } from './get-tag.js';
7
8
  /** Creates a traversed tag entry from an OpenAPI tag object.
@@ -22,6 +23,7 @@ const createTagEntry = ({ tag, generateId, children, isGroup = false, isTagGroup
22
23
  isTagGroup,
23
24
  });
24
25
  // `summary` is the OpenAPI 3.2 display label; `x-displayName` keeps precedence for backwards compatibility.
26
+ const externalDocs = getTagExternalDocs(tag);
25
27
  const title = tag['x-displayName'] ?? tag.summary ?? tag.name ?? 'Untitled Tag';
26
28
  // Update the order of the children based on the items
27
29
  // This will ensure that the sort order is always in sync with the items
@@ -31,6 +33,7 @@ const createTagEntry = ({ tag, generateId, children, isGroup = false, isTagGroup
31
33
  title,
32
34
  name: tag.name || title,
33
35
  description: tag.description,
36
+ ...(externalDocs ? { externalDocs } : {}),
34
37
  children,
35
38
  isGroup,
36
39
  // Only tag on legacy `x-tagGroups` wrappers so the renderer can flatten them without a header.
@@ -5,8 +5,8 @@ import type { ExampleObject, RequestBodyObject } from '@scalar/workspace-store/s
5
5
  * This is the schema-generation half of {@link getExampleFromBody}. It is exposed on its own so
6
6
  * callers that need to regenerate a body for a freshly selected composition branch (rather than the
7
7
  * edited example that would otherwise shadow it) produce the exact same value the initial example
8
- * does. Data generation deep-resolves nested `$ref` members. XML retains reference sites so node
9
- * naming and version-specific wrappers survive serialization.
8
+ * does. Keep reference sites intact so the generator can detect cycles without losing the schema
9
+ * at the recursion point. XML also needs them for node naming and version-specific wrappers.
10
10
  *
11
11
  * Returns `undefined` when there is no schema for the content type.
12
12
  */
@@ -1 +1 @@
1
- {"version":3,"file":"get-request-body-example.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/body/get-request-body-example.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EAElB,MAAM,8DAA8D,CAAA;AASrE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GACnC,aAAa,iBAAiB,EAC9B,aAAa,MAAM,EACnB,kCAAkC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACxD,iBAAiB,MAAM,KACtB,OAgCF,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,aAAa,iBAAiB,EAC9B,aAAa,MAAM,EACnB,aAAa,MAAM,EACnB,kCAAkC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACxD,iBAAiB,MAAM,KACtB,aAAa,GAAG,IA4ClB,CAAA"}
1
+ {"version":3,"file":"get-request-body-example.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/body/get-request-body-example.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EAElB,MAAM,8DAA8D,CAAA;AAUrE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GACnC,aAAa,iBAAiB,EAC9B,aAAa,MAAM,EACnB,kCAAkC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACxD,iBAAiB,MAAM,KACtB,OA8BF,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,aAAa,iBAAiB,EAC9B,aAAa,MAAM,EACnB,aAAa,MAAM,EACnB,kCAAkC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACxD,iBAAiB,MAAM,KACtB,aAAa,GAAG,IA4ClB,CAAA"}
@@ -1,8 +1,9 @@
1
1
  import { isXmlMediaType } from '@scalar/helpers/http/is-xml-media-type';
2
2
  import { parseMimeType } from '@scalar/helpers/http/mime-type';
3
3
  import { getExampleValue } from '../../../helpers/get-example-value.js';
4
- import { getResolvedRefDeep } from '../../../helpers/get-resolved-ref-deep.js';
4
+ import { getResolvedRef } from '../../../helpers/get-resolved-ref.js';
5
5
  import { serializeStreamExample } from '../../../helpers/serialize-stream-example.js';
6
+ import { snapshotSchema } from '../../../helpers/snapshot-schema.js';
6
7
  import { getExample } from '../../../request-example/builder/helpers/get-example.js';
7
8
  import { getExampleFromSchema } from '../../../request-example/builder/helpers/get-example-from-schema.js';
8
9
  import { getXmlBodyExample } from '../../../request-example/xml/get-xml-body-example.js';
@@ -12,8 +13,8 @@ import { getXmlBodyExample } from '../../../request-example/xml/get-xml-body-exa
12
13
  * This is the schema-generation half of {@link getExampleFromBody}. It is exposed on its own so
13
14
  * callers that need to regenerate a body for a freshly selected composition branch (rather than the
14
15
  * edited example that would otherwise shadow it) produce the exact same value the initial example
15
- * does. Data generation deep-resolves nested `$ref` members. XML retains reference sites so node
16
- * naming and version-specific wrappers survive serialization.
16
+ * does. Keep reference sites intact so the generator can detect cycles without losing the schema
17
+ * at the recursion point. XML also needs them for node naming and version-specific wrappers.
17
18
  *
18
19
  * Returns `undefined` when there is no schema for the content type.
19
20
  */
@@ -31,11 +32,10 @@ export const getSchemaExampleFromBody = (requestBody, contentType, requestBodyCo
31
32
  schemaPath: ['requestBody'],
32
33
  }).xml;
33
34
  }
34
- if (!schema) {
35
+ if (!schema || getResolvedRef(schema) === undefined) {
35
36
  return undefined;
36
37
  }
37
- const resolvedSchema = getResolvedRefDeep(schema);
38
- const value = getExampleFromSchema(resolvedSchema, {
38
+ const value = getExampleFromSchema(snapshotSchema(schema), {
39
39
  mode: 'write',
40
40
  compositionSelection: requestBodyCompositionSelection,
41
41
  }, {