@scalar/workspace-store 0.63.0 → 0.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +88 -0
- package/dist/client.d.ts +28 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +216 -139
- package/dist/helpers/chunk-index.d.ts +95 -0
- package/dist/helpers/chunk-index.d.ts.map +1 -0
- package/dist/helpers/chunk-index.js +139 -0
- package/dist/helpers/external-examples.d.ts +17 -0
- package/dist/helpers/external-examples.d.ts.map +1 -0
- package/dist/helpers/external-examples.js +50 -0
- package/dist/helpers/operation-examples.d.ts +6 -0
- package/dist/helpers/operation-examples.d.ts.map +1 -0
- package/dist/helpers/operation-examples.js +45 -0
- package/dist/helpers/use-external-examples.d.ts +15 -0
- package/dist/helpers/use-external-examples.d.ts.map +1 -0
- package/dist/helpers/use-external-examples.js +55 -0
- package/dist/mutators/operation/parameters.d.ts.map +1 -1
- package/dist/mutators/operation/parameters.js +28 -9
- package/dist/plugins/bundler/index.d.ts +5 -2
- package/dist/plugins/bundler/index.d.ts.map +1 -1
- package/dist/plugins/bundler/index.js +12 -3
- package/dist/request-example/builder/header/is-param-disabled.d.ts +2 -2
- package/dist/request-example/builder/header/is-param-disabled.d.ts.map +1 -1
- package/dist/request-example/builder/header/is-param-disabled.js +5 -4
- package/dist/request-example/builder/helpers/get-example.d.ts +2 -0
- package/dist/request-example/builder/helpers/get-example.d.ts.map +1 -1
- package/dist/request-example/builder/helpers/get-example.js +9 -7
- package/dist/request-example/context/headers.d.ts.map +1 -1
- package/dist/request-example/context/headers.js +3 -4
- package/dist/schemas/v3.2/strict/openapi-document.d.ts.map +1 -1
- package/dist/schemas/v3.2/strict/openapi-document.js +17 -1
- package/dist/server.d.ts +16 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +34 -9
- package/package.json +3 -3
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { isHttpMethod } from '@scalar/helpers/http/is-http-method';
|
|
2
|
+
import { isObject } from '@scalar/helpers/object/is-object';
|
|
3
|
+
import { escapeJsonPointer } from '@scalar/json-magic/helpers/escape-json-pointer';
|
|
4
|
+
import { encodeChunkName } from '../helpers/encode-chunk-name.js';
|
|
5
|
+
/**
|
|
6
|
+
* The extension key a compact sparse document carries its chunk index under.
|
|
7
|
+
*
|
|
8
|
+
* It exists on the wire only: the client expands the index back into per-node references while the
|
|
9
|
+
* document is ingested and removes the key, so nothing downstream ever sees it.
|
|
10
|
+
*/
|
|
11
|
+
export const CHUNK_INDEX_KEY = 'x-scalar-chunk-index';
|
|
12
|
+
/** Stands in for an externalized operation on a compact path item. */
|
|
13
|
+
const OPERATION_PLACEHOLDER = 0;
|
|
14
|
+
/** Matches a `{slot}` in a template, or a doubled brace standing for a literal one. */
|
|
15
|
+
const TEMPLATE_SLOT = /\{\{|\}\}|\{(\w+)\}/g;
|
|
16
|
+
/**
|
|
17
|
+
* Fills the `{slot}`s of a chunk-reference template.
|
|
18
|
+
*
|
|
19
|
+
* `{{` and `}}` stand for literal braces, so text the writer inlined into a template — a document
|
|
20
|
+
* name, a base URL — may contain braces without being read back as a slot. An unknown slot is left
|
|
21
|
+
* alone rather than blanked, so a template from a newer writer fails visibly instead of resolving
|
|
22
|
+
* to the wrong chunk.
|
|
23
|
+
*/
|
|
24
|
+
export const fillChunkRef = (template, values = {}) => template.replace(TEMPLATE_SLOT, (match, slot) => slot === undefined ? match.charAt(0) : (values[slot] ?? match));
|
|
25
|
+
/** Escapes text inlined into a template verbatim, so its braces are not read back as slots. */
|
|
26
|
+
const escapeTemplateLiteral = (text) => text.replaceAll('{', '{{').replaceAll('}', '}}');
|
|
27
|
+
const identity = (value) => value;
|
|
28
|
+
/**
|
|
29
|
+
* How each template slot is spelled, per mode.
|
|
30
|
+
*
|
|
31
|
+
* Static references name files, so their variable segments go through `encodeChunkName` — the same
|
|
32
|
+
* call `generateWorkspaceChunks` makes when it writes those files. SSR references name pointers
|
|
33
|
+
* into the store's in-memory assets, which `get()` looks up with JSON Pointer segments, so only the
|
|
34
|
+
* path is escaped. A method is never encoded in either mode: it is written as it was read, and
|
|
35
|
+
* `isHttpMethod` keeps it to letters.
|
|
36
|
+
*
|
|
37
|
+
* Both sides read the table from here. A reader that encoded a segment differently would build a
|
|
38
|
+
* reference to a chunk that does not exist.
|
|
39
|
+
*/
|
|
40
|
+
const SLOT_ENCODERS = {
|
|
41
|
+
static: { type: encodeChunkName, name: encodeChunkName, path: encodeChunkName, method: identity },
|
|
42
|
+
ssr: { type: identity, name: identity, path: escapeJsonPointer, method: identity },
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Builds the reference templates for one document.
|
|
46
|
+
*
|
|
47
|
+
* Filled, these produce exactly the references `externalizeComponentReferences` and
|
|
48
|
+
* `externalizePathReferences` write, so a client that expands the index lands on the same chunk.
|
|
49
|
+
*/
|
|
50
|
+
export const chunkRefTemplates = (meta) => {
|
|
51
|
+
if (meta.mode === 'ssr') {
|
|
52
|
+
const base = `${escapeTemplateLiteral(meta.baseUrl)}/${escapeTemplateLiteral(meta.name)}`;
|
|
53
|
+
return {
|
|
54
|
+
components: `${base}/components/{type}/{name}#`,
|
|
55
|
+
operations: `${base}/operations/{path}/{method}#`,
|
|
56
|
+
navigation: `${base}/navigation#`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const base = `./chunks/${escapeTemplateLiteral(encodeChunkName(meta.name))}`;
|
|
60
|
+
return {
|
|
61
|
+
components: `${base}/components/{type}/{name}.json#`,
|
|
62
|
+
operations: `${base}/operations/{path}/{method}.json#`,
|
|
63
|
+
navigation: `${base}/navigation.json#`,
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
/** The reference a lazily loaded chunk is reached through. */
|
|
67
|
+
export const chunkReference = (ref) => ({ '$ref': ref, $global: true });
|
|
68
|
+
/**
|
|
69
|
+
* Compacts a sparse document's `components` and `paths` into an index.
|
|
70
|
+
*
|
|
71
|
+
* Takes the sections the externalizers produced rather than the document itself, so the index is
|
|
72
|
+
* built from the very references it replaces and the two cannot come to describe different sets of
|
|
73
|
+
* chunks.
|
|
74
|
+
*/
|
|
75
|
+
export const buildChunkIndex = ({ mode, refs, components, paths, }) => ({
|
|
76
|
+
mode,
|
|
77
|
+
refs,
|
|
78
|
+
components: Object.fromEntries(Object.entries(components).map(([type, names]) => [type, Object.keys(names)])),
|
|
79
|
+
paths: Object.fromEntries(Object.entries(paths).map(([path, pathItem]) => [
|
|
80
|
+
path,
|
|
81
|
+
Object.fromEntries(Object.entries(pathItem).map(([key, value]) => [key, isHttpMethod(key) ? OPERATION_PLACEHOLDER : value])),
|
|
82
|
+
])),
|
|
83
|
+
});
|
|
84
|
+
/** Whether a value is shaped like an index this build knows how to expand. */
|
|
85
|
+
const isChunkIndex = (value) => isObject(value) &&
|
|
86
|
+
(value['mode'] === 'static' || value['mode'] === 'ssr') &&
|
|
87
|
+
isObject(value['refs']) &&
|
|
88
|
+
isObject(value['components']) &&
|
|
89
|
+
isObject(value['paths']);
|
|
90
|
+
/**
|
|
91
|
+
* Expands a compact sparse document into the one a non-compact server store would have sent.
|
|
92
|
+
*
|
|
93
|
+
* Mutates the document in place and drops the index key, so what the rest of the store sees is an
|
|
94
|
+
* ordinary sparse document: `resolve()`, the bundler and anything enumerating `paths` or
|
|
95
|
+
* `components` are looking at the shape they always have.
|
|
96
|
+
*
|
|
97
|
+
* A document without an index is left alone, which is every document a non-compact server store or
|
|
98
|
+
* an author produces.
|
|
99
|
+
*
|
|
100
|
+
* @param document - The document to expand, mutated in place
|
|
101
|
+
* @returns Whether an index was found and expanded
|
|
102
|
+
*/
|
|
103
|
+
export const expandChunkIndex = (document) => {
|
|
104
|
+
if (!isObject(document) || document[CHUNK_INDEX_KEY] === undefined) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const index = document[CHUNK_INDEX_KEY];
|
|
108
|
+
if (!isChunkIndex(index)) {
|
|
109
|
+
// The key is dropped rather than passed on: it is not part of any document a consumer should
|
|
110
|
+
// see, and the sections it stands for are missing either way, so there is nothing a partial
|
|
111
|
+
// expansion could recover.
|
|
112
|
+
delete document[CHUNK_INDEX_KEY];
|
|
113
|
+
console.warn(`Ignoring an unreadable "${CHUNK_INDEX_KEY}"; this document's chunks cannot be resolved.`);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const encoders = SLOT_ENCODERS[index.mode];
|
|
117
|
+
// Define own properties so document keys such as `__proto__` remain data, without invoking
|
|
118
|
+
// inherited setters or changing the prototype of any expanded object.
|
|
119
|
+
const components = Object.fromEntries(Object.entries(index.components).map(([type, names]) => [
|
|
120
|
+
type,
|
|
121
|
+
Object.fromEntries(names.map((name) => [
|
|
122
|
+
name,
|
|
123
|
+
chunkReference(fillChunkRef(index.refs.components, { type: encoders.type(type), name: encoders.name(name) })),
|
|
124
|
+
])),
|
|
125
|
+
]));
|
|
126
|
+
const paths = Object.fromEntries(Object.entries(index.paths).map(([path, pathItem]) => [
|
|
127
|
+
path,
|
|
128
|
+
Object.fromEntries(Object.entries(pathItem).map(([key, value]) => [
|
|
129
|
+
key,
|
|
130
|
+
isHttpMethod(key)
|
|
131
|
+
? chunkReference(fillChunkRef(index.refs.operations, { path: encoders.path(path), method: encoders.method(key) }))
|
|
132
|
+
: value,
|
|
133
|
+
])),
|
|
134
|
+
]));
|
|
135
|
+
document['components'] = components;
|
|
136
|
+
document['paths'] = paths;
|
|
137
|
+
delete document[CHUNK_INDEX_KEY];
|
|
138
|
+
return true;
|
|
139
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type LoaderPlugin } from '@scalar/json-magic/bundle';
|
|
2
|
+
import { fetchUrls } from '@scalar/json-magic/bundle/plugins/browser';
|
|
3
|
+
import type { ExampleObject } from '../schemas/v3.2/strict/openapi-document.js';
|
|
4
|
+
/** Download state lives outside the document so reading an example never creates an edit. */
|
|
5
|
+
export type ExternalExampleState = {
|
|
6
|
+
status: 'idle' | 'loading' | 'loaded' | 'error';
|
|
7
|
+
value?: unknown;
|
|
8
|
+
load: () => Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
/** A resolver belongs to one document revision and its configured transport. */
|
|
11
|
+
export type ExternalExampleResolver = (example: ExampleObject) => ExternalExampleState;
|
|
12
|
+
/** Cache external payloads and in-flight requests without changing authored examples. */
|
|
13
|
+
export declare const createExternalExampleResolver: (options?: Parameters<typeof fetchUrls>[0] & {
|
|
14
|
+
origin?: string;
|
|
15
|
+
fileLoader?: LoaderPlugin;
|
|
16
|
+
}) => ExternalExampleResolver;
|
|
17
|
+
//# sourceMappingURL=external-examples.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-examples.d.ts","sourceRoot":"","sources":["../../src/helpers/external-examples.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAwB,MAAM,2BAA2B,CAAA;AACnF,OAAO,EAAE,SAAS,EAAE,MAAM,2CAA2C,CAAA;AAGrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAE3E,6FAA6F;AAC7F,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAA;IAC/C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1B,CAAA;AAED,gFAAgF;AAChF,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,EAAE,aAAa,KAAK,oBAAoB,CAAA;AAEtF,yFAAyF;AACzF,eAAO,MAAM,6BAA6B,GACxC,UAAS,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,YAAY,CAAA;CAAO,KAC7F,uBAuCF,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { resolveReferencePath } from '@scalar/json-magic/bundle';
|
|
2
|
+
import { fetchUrls } from '@scalar/json-magic/bundle/plugins/browser';
|
|
3
|
+
import { shallowReactive } from 'vue';
|
|
4
|
+
/** Cache external payloads and in-flight requests without changing authored examples. */
|
|
5
|
+
export const createExternalExampleResolver = (options = {}) => {
|
|
6
|
+
const loader = fetchUrls({ ...options, limit: 10 });
|
|
7
|
+
const cache = new Map();
|
|
8
|
+
return (example) => {
|
|
9
|
+
if (example.value !== undefined || !example.externalValue) {
|
|
10
|
+
return { status: 'loaded', value: example.value, load: () => Promise.resolve() };
|
|
11
|
+
}
|
|
12
|
+
const url = resolveReferencePath(options.origin ?? '', example.externalValue) ?? example.externalValue;
|
|
13
|
+
const cached = cache.get(url);
|
|
14
|
+
if (cached)
|
|
15
|
+
return cached;
|
|
16
|
+
let pending;
|
|
17
|
+
const state = shallowReactive({
|
|
18
|
+
status: 'idle',
|
|
19
|
+
load: () => {
|
|
20
|
+
if (pending)
|
|
21
|
+
return pending;
|
|
22
|
+
if (state.status === 'loaded')
|
|
23
|
+
return Promise.resolve();
|
|
24
|
+
state.status = 'loading';
|
|
25
|
+
pending = (async () => {
|
|
26
|
+
try {
|
|
27
|
+
const selectedLoader = [loader, options.fileLoader].find((candidate) => candidate?.validate(url));
|
|
28
|
+
const result = await selectedLoader?.exec(url);
|
|
29
|
+
if (result?.ok) {
|
|
30
|
+
state.value = result.data === undefined ? result.raw : result.data;
|
|
31
|
+
state.status = 'loaded';
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
state.status = 'error';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
state.status = 'error';
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
pending = undefined;
|
|
42
|
+
}
|
|
43
|
+
})();
|
|
44
|
+
return pending;
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
cache.set(url, state);
|
|
48
|
+
return state;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ExampleObject, OperationObject } from '../schemas/v3.2/strict/openapi-document.js';
|
|
2
|
+
/** The request body and parameter examples needed by a single request, never its responses. */
|
|
3
|
+
export declare const getOperationExamples: (operation: OperationObject, key: string, contentType?: string) => (ExampleObject | undefined)[];
|
|
4
|
+
/** Overlay fetched values for request consumers without persisting them as document edits. */
|
|
5
|
+
export declare const resolveOperationExamples: (operation: OperationObject, key: string, contentType: string | undefined, resolve: (example: ExampleObject | undefined) => ExampleObject | undefined) => OperationObject;
|
|
6
|
+
//# sourceMappingURL=operation-examples.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operation-examples.d.ts","sourceRoot":"","sources":["../../src/helpers/operation-examples.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAmB,eAAe,EAAE,MAAM,wCAAwC,CAAA;AAE7G,+FAA+F;AAC/F,eAAO,MAAM,oBAAoB,GAC/B,WAAW,eAAe,EAC1B,KAAK,MAAM,EACX,cAAc,MAAM,KACnB,CAAC,aAAa,GAAG,SAAS,CAAC,EAS7B,CAAA;AAED,8FAA8F;AAC9F,eAAO,MAAM,wBAAwB,GACnC,WAAW,eAAe,EAC1B,KAAK,MAAM,EACX,aAAa,MAAM,GAAG,SAAS,EAC/B,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,KAAK,aAAa,GAAG,SAAS,KACzE,eA6BF,CAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { getResolvedRef } from '../helpers/get-resolved-ref.js';
|
|
2
|
+
import { getExample } from '../request-example/builder/helpers/get-example.js';
|
|
3
|
+
/** The request body and parameter examples needed by a single request, never its responses. */
|
|
4
|
+
export const getOperationExamples = (operation, key, contentType) => {
|
|
5
|
+
const body = getResolvedRef(operation.requestBody);
|
|
6
|
+
return [
|
|
7
|
+
body ? getExample(body, key, contentType) : undefined,
|
|
8
|
+
...(operation.parameters ?? []).map((parameter) => {
|
|
9
|
+
const resolved = getResolvedRef(parameter);
|
|
10
|
+
return resolved ? getExample(resolved, key, undefined) : undefined;
|
|
11
|
+
}),
|
|
12
|
+
];
|
|
13
|
+
};
|
|
14
|
+
/** Overlay fetched values for request consumers without persisting them as document edits. */
|
|
15
|
+
export const resolveOperationExamples = (operation, key, contentType, resolve) => {
|
|
16
|
+
const mapMedia = (media) => {
|
|
17
|
+
const selected = key || Object.keys(media.examples ?? {})[0];
|
|
18
|
+
const example = selected ? getResolvedRef(media.examples?.[selected]) : undefined;
|
|
19
|
+
const resolved = resolve(example);
|
|
20
|
+
return selected && resolved && resolved !== example
|
|
21
|
+
? { ...media, examples: { ...media.examples, [selected]: resolved } }
|
|
22
|
+
: media;
|
|
23
|
+
};
|
|
24
|
+
const body = getResolvedRef(operation.requestBody);
|
|
25
|
+
const type = contentType ?? Object.keys(body?.content ?? {})[0];
|
|
26
|
+
return {
|
|
27
|
+
...operation,
|
|
28
|
+
...(body && type && body.content[type]
|
|
29
|
+
? {
|
|
30
|
+
requestBody: { ...body, content: { ...body.content, [type]: mapMedia(body.content[type]) } },
|
|
31
|
+
}
|
|
32
|
+
: {}),
|
|
33
|
+
parameters: operation.parameters?.map((parameter) => {
|
|
34
|
+
const resolved = getResolvedRef(parameter);
|
|
35
|
+
if (!resolved)
|
|
36
|
+
return parameter;
|
|
37
|
+
const content = 'content' in resolved ? resolved.content : undefined;
|
|
38
|
+
const mediaType = Object.keys(content ?? {})[0];
|
|
39
|
+
if (mediaType && content?.[mediaType]) {
|
|
40
|
+
return { ...resolved, content: { ...content, [mediaType]: mapMedia(content[mediaType]) } };
|
|
41
|
+
}
|
|
42
|
+
return { ...resolved, ...mapMedia(resolved) };
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ComponentPublicInstance, type ComputedRef, type InjectionKey, type Ref } from 'vue';
|
|
2
|
+
import { type ExternalExampleResolver } from '../helpers/external-examples.js';
|
|
3
|
+
import type { ExampleObject } from '../schemas/v3.2/strict/openapi-document.js';
|
|
4
|
+
/** Supply the current document's resolver so consumers share downloads and invalidation. */
|
|
5
|
+
export declare const EXTERNAL_EXAMPLES: InjectionKey<() => ExternalExampleResolver>;
|
|
6
|
+
/** Observe current visibility, rather than mounting, to avoid fetching every operation on a long page. */
|
|
7
|
+
export declare const useExampleVisibility: (target: Ref<Element | ComponentPublicInstance | null>) => Ref<boolean>;
|
|
8
|
+
/** Resolve only the selected examples and expose immutable views of their downloaded values. */
|
|
9
|
+
export declare const useExternalExamples: (examples: () => (ExampleObject | undefined)[], enabled?: () => boolean, resolver?: () => ExternalExampleResolver) => {
|
|
10
|
+
pending: ComputedRef<boolean>;
|
|
11
|
+
failed: ComputedRef<boolean>;
|
|
12
|
+
resolve: (example: ExampleObject | undefined) => ExampleObject | undefined;
|
|
13
|
+
retry: () => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=use-external-examples.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-external-examples.d.ts","sourceRoot":"","sources":["../../src/helpers/use-external-examples.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,GAAG,EAOT,MAAM,KAAK,CAAA;AAEZ,OAAO,EAAE,KAAK,uBAAuB,EAAiC,MAAM,6BAA6B,CAAA;AACzG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAE3E,4FAA4F;AAC5F,eAAO,MAAM,iBAAiB,EAAE,YAAY,CAAC,MAAM,uBAAuB,CAA+B,CAAA;AAEzG,0GAA0G;AAC1G,eAAO,MAAM,oBAAoB,GAAI,QAAQ,GAAG,CAAC,OAAO,GAAG,uBAAuB,GAAG,IAAI,CAAC,KAAG,GAAG,CAAC,OAAO,CAuBvG,CAAA;AAED,gGAAgG;AAChG,eAAO,MAAM,mBAAmB,GAC9B,UAAU,MAAM,CAAC,aAAa,GAAG,SAAS,CAAC,EAAE,EAC7C,UAAS,MAAM,OAAoB,EACnC,WAAW,MAAM,uBAAuB,KACvC;IACD,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;IAC7B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;IAC5B,OAAO,EAAE,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,KAAK,aAAa,GAAG,SAAS,CAAA;IAC1E,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAgC3B,CAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { computed, inject, onScopeDispose, ref, watch, watchEffect, } from 'vue';
|
|
2
|
+
import { createExternalExampleResolver } from '../helpers/external-examples.js';
|
|
3
|
+
/** Supply the current document's resolver so consumers share downloads and invalidation. */
|
|
4
|
+
export const EXTERNAL_EXAMPLES = Symbol('external-examples');
|
|
5
|
+
/** Observe current visibility, rather than mounting, to avoid fetching every operation on a long page. */
|
|
6
|
+
export const useExampleVisibility = (target) => {
|
|
7
|
+
const visible = ref(false);
|
|
8
|
+
let observer;
|
|
9
|
+
watch(target, (element) => {
|
|
10
|
+
observer?.disconnect();
|
|
11
|
+
visible.value = false;
|
|
12
|
+
const node = element && ('$el' in element ? element.$el : element);
|
|
13
|
+
if (typeof Element === 'undefined' || !(node instanceof Element))
|
|
14
|
+
return;
|
|
15
|
+
if (typeof IntersectionObserver === 'undefined') {
|
|
16
|
+
visible.value = true;
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
observer = new IntersectionObserver(([entry]) => {
|
|
20
|
+
visible.value = entry?.isIntersecting ?? false;
|
|
21
|
+
});
|
|
22
|
+
observer.observe(node);
|
|
23
|
+
}, { flush: 'post' });
|
|
24
|
+
onScopeDispose(() => observer?.disconnect());
|
|
25
|
+
return visible;
|
|
26
|
+
};
|
|
27
|
+
/** Resolve only the selected examples and expose immutable views of their downloaded values. */
|
|
28
|
+
export const useExternalExamples = (examples, enabled = () => true, resolver) => {
|
|
29
|
+
const fallback = createExternalExampleResolver();
|
|
30
|
+
const getResolver = resolver ?? inject(EXTERNAL_EXAMPLES, () => fallback);
|
|
31
|
+
const states = computed(() => examples()
|
|
32
|
+
.filter((example) => example !== undefined && example.value === undefined && !!example.externalValue)
|
|
33
|
+
.map((example) => getResolver()(example)));
|
|
34
|
+
watchEffect(() => {
|
|
35
|
+
if (!enabled())
|
|
36
|
+
return;
|
|
37
|
+
for (const state of states.value) {
|
|
38
|
+
if (state.status === 'idle')
|
|
39
|
+
void state.load();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
pending: computed(() => states.value.some((state) => state.status !== 'loaded')),
|
|
44
|
+
failed: computed(() => states.value.some((state) => state.status === 'error')),
|
|
45
|
+
resolve: (example) => {
|
|
46
|
+
if (!example || example.value !== undefined || !example.externalValue)
|
|
47
|
+
return example;
|
|
48
|
+
const state = getResolver()(example);
|
|
49
|
+
return state.status === 'loaded' ? { ...example, value: state.value } : example;
|
|
50
|
+
},
|
|
51
|
+
retry: async () => {
|
|
52
|
+
await Promise.all(states.value.map((state) => state.load()));
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parameters.d.ts","sourceRoot":"","sources":["../../../src/mutators/operation/parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAIrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAmClD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,wBAAwB,GACnC,UAAU,iBAAiB,GAAG,IAAI,EAClC,4CAA4C,eAAe,CAAC,4BAA4B,CAAC,
|
|
1
|
+
{"version":3,"file":"parameters.d.ts","sourceRoot":"","sources":["../../../src/mutators/operation/parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAIrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAmClD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,wBAAwB,GACnC,UAAU,iBAAiB,GAAG,IAAI,EAClC,4CAA4C,eAAe,CAAC,4BAA4B,CAAC,SAuE1F,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,8BAA8B,GACzC,UAAU,iBAAiB,GAAG,IAAI,EAClC,uCAAuC,eAAe,CAAC,mCAAmC,CAAC,SA8C5F,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,GACnC,UAAU,iBAAiB,GAAG,IAAI,EAClC,6BAA6B,eAAe,CAAC,4BAA4B,CAAC,SAkC3E,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,4BAA4B,GACvC,UAAU,iBAAiB,GAAG,IAAI,EAClC,gBAAgB,eAAe,CAAC,iCAAiC,CAAC,SAanE,CAAA"}
|
|
@@ -2,6 +2,7 @@ import { getPathItemOperation } from '../../helpers/for-each-path-item-operation
|
|
|
2
2
|
import { getResolvedRef } from '../../helpers/get-resolved-ref.js';
|
|
3
3
|
import { unpackProxyObject } from '../../helpers/unpack-proxy.js';
|
|
4
4
|
import { isOpenApiDocument } from '../../schemas/type-guards.js';
|
|
5
|
+
import { isContentTypeParameterObject } from '../../schemas/v3.2/strict/type-guards.js';
|
|
5
6
|
const getPathItemsForParameterMutation = (pathItemRef) => {
|
|
6
7
|
if (!pathItemRef || typeof pathItemRef !== 'object') {
|
|
7
8
|
return [];
|
|
@@ -40,23 +41,41 @@ const getPathItemsForParameterMutation = (pathItemRef) => {
|
|
|
40
41
|
export const upsertOperationParameter = (document, { meta, type, payload, originalParameter }) => {
|
|
41
42
|
// We are editing an existing parameter
|
|
42
43
|
if (originalParameter) {
|
|
43
|
-
// To support content-type parameters in the API client, we just assume an
|
|
44
|
-
// examples property can be set.
|
|
45
44
|
const param = originalParameter;
|
|
45
|
+
const target = isContentTypeParameterObject(param) ? Object.values(param.content ?? {})[0] : param;
|
|
46
|
+
if (!target) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (target !== param) {
|
|
50
|
+
// Keep authored examples and migrate edits saved by older clients. Those edits
|
|
51
|
+
// already take precedence when reading, so they must also win during migration.
|
|
52
|
+
target.examples = {
|
|
53
|
+
...(target.example !== undefined ? { default: { value: target.example } } : {}),
|
|
54
|
+
...target.examples,
|
|
55
|
+
...('example' in param && param.example !== undefined ? { default: { value: param.example } } : {}),
|
|
56
|
+
...('examples' in param ? param.examples : {}),
|
|
57
|
+
};
|
|
58
|
+
// A media type cannot carry both the singular example and the examples map.
|
|
59
|
+
delete target.example;
|
|
60
|
+
if ('examples' in param) {
|
|
61
|
+
delete param.examples;
|
|
62
|
+
}
|
|
63
|
+
if ('example' in param) {
|
|
64
|
+
delete param.example;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
46
67
|
// Only update the name when the payload carries a non-empty value — an
|
|
47
68
|
// empty name in the payload means the key input blurred before rendering
|
|
48
69
|
// its initial value and should not overwrite the existing parameter name.
|
|
49
70
|
if (payload.name || !param.name) {
|
|
50
71
|
param.name = payload.name;
|
|
51
72
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
param.examples[meta.exampleKey] = {};
|
|
73
|
+
target.examples ??= {};
|
|
74
|
+
target.examples[meta.exampleKey] ??= {};
|
|
75
|
+
const example = getResolvedRef(target.examples[meta.exampleKey]);
|
|
76
|
+
if (!example) {
|
|
77
|
+
return;
|
|
58
78
|
}
|
|
59
|
-
const example = getResolvedRef(param.examples[meta.exampleKey]);
|
|
60
79
|
// Update the example value and disabled state
|
|
61
80
|
example.value = payload.value;
|
|
62
81
|
example['x-disabled'] = payload.isDisabled;
|
|
@@ -20,9 +20,12 @@ export declare const loadingStatus: () => LifecyclePlugin;
|
|
|
20
20
|
*
|
|
21
21
|
* This is useful for inlining external content (like examples or schemas) into the OpenAPI document during bundling.
|
|
22
22
|
*
|
|
23
|
-
*
|
|
23
|
+
* In lazy mode, preserve the absolute URL for on-demand client resolution without fetching a payload.
|
|
24
|
+
* The default eager mode remains available to existing bundler consumers.
|
|
24
25
|
*/
|
|
25
|
-
export declare const externalValueResolver: (
|
|
26
|
+
export declare const externalValueResolver: (options?: {
|
|
27
|
+
lazy?: boolean;
|
|
28
|
+
}) => LifecyclePlugin;
|
|
26
29
|
/**
|
|
27
30
|
* Lifecycle plugin to resolve $ref on any object, including non-standard locations like the info object.
|
|
28
31
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/bundler/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,KAAK,eAAe,EAAwB,MAAM,2BAA2B,CAAA;AAStF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,QAAO,eAahC,CAAA;AAED
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/bundler/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,KAAK,eAAe,EAAwB,MAAM,2BAA2B,CAAA;AAStF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,QAAO,eAahC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,GAAI,UAAU;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,KAAG,eA2CpE,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,QAAO,eAwCjC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,mBAAmB,QAAO,eAuBtC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,oBAAoB,QAAO,eAuBvC,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,QAAO,eAyBhC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,QAAO,eAkFrC,CAAA;AAKD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAO,eAaxC,CAAA"}
|
|
@@ -39,21 +39,30 @@ export const loadingStatus = () => {
|
|
|
39
39
|
*
|
|
40
40
|
* This is useful for inlining external content (like examples or schemas) into the OpenAPI document during bundling.
|
|
41
41
|
*
|
|
42
|
-
*
|
|
42
|
+
* In lazy mode, preserve the absolute URL for on-demand client resolution without fetching a payload.
|
|
43
|
+
* The default eager mode remains available to existing bundler consumers.
|
|
43
44
|
*/
|
|
44
|
-
export const externalValueResolver = () => {
|
|
45
|
+
export const externalValueResolver = (options) => {
|
|
45
46
|
return {
|
|
46
47
|
type: 'lifecycle',
|
|
47
48
|
onAfterNodeProcess: async (node, context) => {
|
|
48
49
|
const externalValue = node['externalValue'];
|
|
49
50
|
const cache = context.resolutionCache;
|
|
50
51
|
// Only process if 'externalValue' is a string
|
|
51
|
-
if (typeof externalValue !== 'string') {
|
|
52
|
+
if (typeof externalValue !== 'string' || node['value'] !== undefined) {
|
|
52
53
|
return;
|
|
53
54
|
}
|
|
54
55
|
// `externalValue` may be relative (for example `/examples/pet.json`). Resolve it against the
|
|
55
56
|
// origin of the document it lives in so it becomes an absolute URL a loader can fetch.
|
|
56
57
|
const resolvedValue = resolveReferencePath(context.origin, externalValue);
|
|
58
|
+
if (options?.lazy) {
|
|
59
|
+
const path = context.path.at(-2) === 'examples' ? context.path : (context.referencedFromPath ?? context.path);
|
|
60
|
+
if (path.at(-2) !== 'examples' || isSchemaPath(path))
|
|
61
|
+
return;
|
|
62
|
+
// Preserve the referenced document origin before bundling loses that context.
|
|
63
|
+
node['externalValue'] = resolvedValue;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
57
66
|
const loader = context.loaders.find((it) => it.validate(resolvedValue));
|
|
58
67
|
// We can not process the external value
|
|
59
68
|
if (!loader) {
|
|
@@ -3,11 +3,11 @@ import type { ExampleObject, ParameterObject } from '@scalar/workspace-store/sch
|
|
|
3
3
|
* Determines if a parameter is disabled
|
|
4
4
|
*
|
|
5
5
|
* First we explicitly check if its been disabled via the `x-disabled` extension.
|
|
6
|
-
*
|
|
6
|
+
* Populated examples are enabled unless explicitly disabled. Empty optional parameters stay disabled.
|
|
7
7
|
*
|
|
8
8
|
* @param param - The parameter to check.
|
|
9
9
|
* @param example - The example to check.
|
|
10
|
-
* @param defaultDisabled - When true (default), optional parameters are treated as disabled unless explicitly enabled. When false, only parameters explicitly marked `x-disabled: true` are disabled.
|
|
10
|
+
* @param defaultDisabled - When true (default), empty optional parameters are treated as disabled unless explicitly enabled. When false, only parameters explicitly marked `x-disabled: true` are disabled.
|
|
11
11
|
* @returns true if the parameter is disabled, false otherwise.
|
|
12
12
|
*/
|
|
13
13
|
export declare const isParamDisabled: (param: ParameterObject, example: ExampleObject | undefined, defaultDisabled?: boolean) => boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-param-disabled.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/header/is-param-disabled.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;AAElH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,eAAe,EACtB,SAAS,aAAa,GAAG,SAAS,EAClC,kBAAiB,OAAc,
|
|
1
|
+
{"version":3,"file":"is-param-disabled.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/header/is-param-disabled.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;AAElH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,eAAe,EACtB,SAAS,aAAa,GAAG,SAAS,EAClC,kBAAiB,OAAc,KAC9B,OAgBF,CAAA"}
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Determines if a parameter is disabled
|
|
3
3
|
*
|
|
4
4
|
* First we explicitly check if its been disabled via the `x-disabled` extension.
|
|
5
|
-
*
|
|
5
|
+
* Populated examples are enabled unless explicitly disabled. Empty optional parameters stay disabled.
|
|
6
6
|
*
|
|
7
7
|
* @param param - The parameter to check.
|
|
8
8
|
* @param example - The example to check.
|
|
9
|
-
* @param defaultDisabled - When true (default), optional parameters are treated as disabled unless explicitly enabled. When false, only parameters explicitly marked `x-disabled: true` are disabled.
|
|
9
|
+
* @param defaultDisabled - When true (default), empty optional parameters are treated as disabled unless explicitly enabled. When false, only parameters explicitly marked `x-disabled: true` are disabled.
|
|
10
10
|
* @returns true if the parameter is disabled, false otherwise.
|
|
11
11
|
*/
|
|
12
12
|
export const isParamDisabled = (param, example, defaultDisabled = true) => {
|
|
@@ -15,8 +15,9 @@ export const isParamDisabled = (param, example, defaultDisabled = true) => {
|
|
|
15
15
|
if (typeof xDisabled === 'boolean') {
|
|
16
16
|
return xDisabled;
|
|
17
17
|
}
|
|
18
|
-
//
|
|
19
|
-
|
|
18
|
+
// Keep the editor, generated snippets, and outgoing requests aligned for pre-populated values.
|
|
19
|
+
const hasValue = example?.value !== undefined && example.value !== '' && example.value !== null;
|
|
20
|
+
if (!defaultDisabled || hasValue) {
|
|
20
21
|
return false;
|
|
21
22
|
}
|
|
22
23
|
// Otherwise, disable optional parameters (except path parameters which are always required)
|
|
@@ -4,6 +4,8 @@ import type { ExampleObject, MediaTypeObject, ParameterObject, RequestBodyObject
|
|
|
4
4
|
* Or the [deprecated] `example` field.
|
|
5
5
|
* If no exampleKey is provided it will fallback to the first example in the examples object then the [deprecated]
|
|
6
6
|
* `example` field.
|
|
7
|
+
* When the parameter carries both its own `examples`/`example` and a `content` object, the parameter-level value
|
|
8
|
+
* takes priority to preserve edits saved by older clients before they are migrated into the media type.
|
|
7
9
|
* Used both for send-request and generating code snippets.
|
|
8
10
|
*/
|
|
9
11
|
export declare const getExample: (param: ParameterObject | RequestBodyObject | MediaTypeObject, exampleName: string | undefined, contentType: string | undefined) => ExampleObject | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-example.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/helpers/get-example.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,eAAe,EACf,iBAAiB,EAClB,MAAM,8DAA8D,CAAA;AAgCrE
|
|
1
|
+
{"version":3,"file":"get-example.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/helpers/get-example.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,eAAe,EACf,iBAAiB,EAClB,MAAM,8DAA8D,CAAA;AAgCrE;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,GACrB,OAAO,eAAe,GAAG,iBAAiB,GAAG,eAAe,EAC5D,aAAa,MAAM,GAAG,SAAS,EAC/B,aAAa,MAAM,GAAG,SAAS,KAC9B,aAAa,GAAG,SA6ClB,CAAA"}
|
|
@@ -23,20 +23,22 @@ const getExampleFromExamples = (examples, exampleField, exampleName) => {
|
|
|
23
23
|
* Or the [deprecated] `example` field.
|
|
24
24
|
* If no exampleKey is provided it will fallback to the first example in the examples object then the [deprecated]
|
|
25
25
|
* `example` field.
|
|
26
|
+
* When the parameter carries both its own `examples`/`example` and a `content` object, the parameter-level value
|
|
27
|
+
* takes priority to preserve edits saved by older clients before they are migrated into the media type.
|
|
26
28
|
* Used both for send-request and generating code snippets.
|
|
27
29
|
*/
|
|
28
30
|
export const getExample = (param, exampleName, contentType) => {
|
|
29
|
-
//
|
|
30
|
-
if ('
|
|
31
|
-
const
|
|
32
|
-
const result = getExampleFromExamples(content?.examples, content?.example, exampleName);
|
|
31
|
+
// Schema-based parameters and content-based parameter edits saved by older clients.
|
|
32
|
+
if ('examples' in param || 'example' in param) {
|
|
33
|
+
const result = getExampleFromExamples(param.examples, param.example, exampleName);
|
|
33
34
|
if (result !== undefined) {
|
|
34
35
|
return result;
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
|
-
//
|
|
38
|
-
if ('
|
|
39
|
-
const
|
|
38
|
+
// Content based parameters
|
|
39
|
+
if ('content' in param) {
|
|
40
|
+
const content = param.content?.[contentType ?? Object.keys(param.content)[0] ?? ''];
|
|
41
|
+
const result = getExampleFromExamples(content?.examples, content?.example, exampleName);
|
|
40
42
|
if (result !== undefined) {
|
|
41
43
|
return result;
|
|
42
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../../src/request-example/context/headers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;
|
|
1
|
+
{"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../../src/request-example/context/headers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;AAcnG;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,GAAI,YAAY,MAAM,KAAG,MACQ,CAAA;AAE3E;;GAEG;AACH,eAAO,MAAM,qCAAqC,GAAI,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CACK,CAAA;AAgDlH;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,GACvC,WAAW,eAAe,EAC1B,aAAa,MAAM,EACnB,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC9B,MAAM,CAAC,MAAM,EAAE,MAAM,CAIpB,CAAA;AAEJ;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,GAAI,0FAU/B;IACD,MAAM,EAAE,UAAU,CAAA;IAClB,SAAS,EAAE,eAAe,CAAA;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,OAAO,CAAC,EAAE;QACR,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,OAAO,CAAA;KACpB,CAAA;CACF,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAuCxB,CAAA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { canMethodHaveBody } from '@scalar/helpers/http/can-method-have-body';
|
|
2
2
|
import { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref';
|
|
3
3
|
import { isParamDisabled } from '../../request-example/builder/header/is-param-disabled.js';
|
|
4
|
+
import { getExample } from '../../request-example/builder/helpers/get-example.js';
|
|
4
5
|
/** Default Accept header value to accept all response types. */
|
|
5
6
|
const DEFAULT_ACCEPT = '*/*';
|
|
6
7
|
const CONVENTIONAL_DEFAULT_HEADER_NAMES = {
|
|
@@ -21,8 +22,7 @@ export const restoreConventionalHeaderName = (headerName) => CONVENTIONAL_DEFAUL
|
|
|
21
22
|
export const restoreConventionalDefaultHeaderNames = (headers) => Object.fromEntries(Object.entries(headers).map(([name, value]) => [restoreConventionalHeaderName(name), value]));
|
|
22
23
|
/**
|
|
23
24
|
* Lowercase names of **enabled** operation parameters with `in: header` for the given example.
|
|
24
|
-
* Uses the same rules as the request builder
|
|
25
|
-
* as disabled unless `examples[exampleName]['x-disabled']` is explicitly `false`.
|
|
25
|
+
* Uses the same example selection and enablement rules as the request builder, including schema defaults.
|
|
26
26
|
*/
|
|
27
27
|
const getEnabledOperationHeaderParameterNames = (operation, exampleName) => {
|
|
28
28
|
const names = new Set();
|
|
@@ -31,8 +31,7 @@ const getEnabledOperationHeaderParameterNames = (operation, exampleName) => {
|
|
|
31
31
|
if (!param || param.in !== 'header') {
|
|
32
32
|
continue;
|
|
33
33
|
}
|
|
34
|
-
const
|
|
35
|
-
const example = rawExample ? getResolvedRef(rawExample) : undefined;
|
|
34
|
+
const example = getExample(param, exampleName, undefined);
|
|
36
35
|
if (!isParamDisabled(param, example)) {
|
|
37
36
|
names.add(param.name.toLowerCase());
|
|
38
37
|
}
|