@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.
- package/CHANGELOG.md +21 -0
- package/README.md +20 -0
- package/dist/channel-example/build-connection-url.d.ts.map +1 -1
- package/dist/channel-example/build-connection-url.js +6 -5
- package/dist/channel-example/get-all-channel-messages.js +2 -2
- package/dist/channel-example/get-async-api-protocols.js +3 -3
- package/dist/channel-example/get-asyncapi-security-requirements.d.ts.map +1 -1
- package/dist/channel-example/get-asyncapi-security-requirements.js +14 -14
- package/dist/channel-example/get-channel-operations.js +2 -2
- package/dist/channel-example/get-channel-parameters.js +2 -2
- package/dist/channel-example/resolve-channel.js +2 -2
- package/dist/channel-example/resolve-operation-channel.js +4 -4
- package/dist/channel-example/servers.js +2 -2
- package/dist/entities/auth/schema.d.ts +20 -0
- package/dist/entities/auth/schema.d.ts.map +1 -1
- package/dist/entities/auth/schema.js +2 -0
- package/dist/helpers/get-async-api-schema-view.d.ts +8 -0
- package/dist/helpers/get-async-api-schema-view.d.ts.map +1 -0
- package/dist/helpers/get-async-api-schema-view.js +82 -0
- package/dist/helpers/get-resolved-async-api-ref.d.ts +10 -0
- package/dist/helpers/get-resolved-async-api-ref.d.ts.map +1 -0
- package/dist/helpers/get-resolved-async-api-ref.js +18 -0
- package/dist/helpers/resolve-traits.d.ts.map +1 -1
- package/dist/helpers/resolve-traits.js +23 -15
- package/dist/helpers/snapshot-schema.d.ts +9 -0
- package/dist/helpers/snapshot-schema.d.ts.map +1 -0
- package/dist/helpers/snapshot-schema.js +38 -0
- package/dist/mutators/auth.d.ts +2 -1
- package/dist/mutators/auth.d.ts.map +1 -1
- package/dist/mutators/auth.js +30 -1
- package/dist/mutators/index.d.ts +2 -2
- package/dist/navigation/get-navigation-options.d.ts.map +1 -1
- package/dist/navigation/get-navigation-options.js +3 -0
- package/dist/navigation/helpers/get-tag-external-docs.d.ts +4 -0
- package/dist/navigation/helpers/get-tag-external-docs.d.ts.map +1 -0
- package/dist/navigation/helpers/get-tag-external-docs.js +6 -0
- package/dist/navigation/helpers/traverse-asyncapi-document.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-asyncapi-document.js +51 -19
- package/dist/navigation/helpers/traverse-tags.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-tags.js +3 -0
- package/dist/request-example/builder/body/get-request-body-example.d.ts +2 -2
- package/dist/request-example/builder/body/get-request-body-example.d.ts.map +1 -1
- package/dist/request-example/builder/body/get-request-body-example.js +6 -6
- package/dist/request-example/builder/helpers/get-example-from-schema.d.ts.map +1 -1
- package/dist/request-example/builder/helpers/get-example-from-schema.js +41 -1
- package/dist/request-example/context/security/extract-security-scheme-secrets.d.ts.map +1 -1
- package/dist/request-example/context/security/extract-security-scheme-secrets.js +2 -0
- package/dist/request-example/context/security/merge-security.d.ts.map +1 -1
- package/dist/request-example/context/security/merge-security.js +10 -1
- package/dist/request-example/context/security/uses-api-key-name-override.d.ts +9 -0
- package/dist/request-example/context/security/uses-api-key-name-override.d.ts.map +1 -0
- package/dist/request-example/context/security/uses-api-key-name-override.js +9 -0
- package/dist/request-example/xml/write-xml.d.ts.map +1 -1
- package/dist/request-example/xml/write-xml.js +1 -0
- package/dist/schemas/navigation.d.ts +4 -0
- package/dist/schemas/navigation.d.ts.map +1 -1
- package/dist/schemas/navigation.js +2 -1
- package/dist/schemas/reference-config/index.d.ts +2 -0
- package/dist/schemas/reference-config/index.d.ts.map +1 -1
- package/dist/schemas/reference-config/settings.d.ts +2 -0
- package/dist/schemas/reference-config/settings.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/openapi-document.d.ts +70 -0
- package/dist/schemas/v3.1/strict/openapi-document.d.ts.map +1 -1
- package/dist/schemas/v3.2/strict/openapi-document.d.ts +70 -0
- package/dist/schemas/v3.2/strict/openapi-document.d.ts.map +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +12 -5
- 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":"
|
|
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 {
|
|
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' ?
|
|
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'
|
|
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
|
|
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 =
|
|
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
|
+
};
|
package/dist/mutators/auth.d.ts
CHANGED
|
@@ -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: (
|
|
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;
|
|
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"}
|
package/dist/mutators/auth.js
CHANGED
|
@@ -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: (
|
|
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),
|
package/dist/mutators/index.d.ts
CHANGED
|
@@ -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: (
|
|
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: (
|
|
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,
|
|
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;
|
|
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 {
|
|
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
|
-
|
|
67
|
-
|
|
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 =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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 =
|
|
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?.
|
|
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 =
|
|
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
|
|
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
|
|
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 ?
|
|
463
|
+
const components = document.components ? getResolvedAsyncApiRef(document.components) : undefined;
|
|
442
464
|
const untaggedModels = !hideModels && components?.schemas
|
|
443
|
-
? traverseSchemas({
|
|
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":"
|
|
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.
|
|
9
|
-
* naming and version-specific wrappers
|
|
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;
|
|
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 {
|
|
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.
|
|
16
|
-
* naming and version-specific wrappers
|
|
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
|
|
38
|
-
const value = getExampleFromSchema(resolvedSchema, {
|
|
38
|
+
const value = getExampleFromSchema(snapshotSchema(schema), {
|
|
39
39
|
mode: 'write',
|
|
40
40
|
compositionSelection: requestBodyCompositionSelection,
|
|
41
41
|
}, {
|