@scalar/workspace-store 0.49.2 → 0.51.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 +114 -0
- package/dist/client.d.ts +2 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +38 -15
- package/dist/entities/auth/schema.d.ts +10 -5
- package/dist/entities/auth/schema.d.ts.map +1 -1
- package/dist/events/bus.d.ts +70 -0
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/events/bus.js +48 -11
- package/dist/events/definitions/analytics.d.ts +0 -12
- package/dist/events/definitions/analytics.d.ts.map +1 -1
- package/dist/events/definitions/auth.d.ts +44 -6
- package/dist/events/definitions/auth.d.ts.map +1 -1
- package/dist/events/definitions/index.d.ts +3 -2
- package/dist/events/definitions/index.d.ts.map +1 -1
- package/dist/events/definitions/log.d.ts +18 -0
- package/dist/events/definitions/log.d.ts.map +1 -0
- package/dist/events/definitions/log.js +1 -0
- package/dist/events/definitions/operation.d.ts +1 -1
- package/dist/events/definitions/operation.d.ts.map +1 -1
- package/dist/events/definitions/ui.d.ts +18 -1
- package/dist/events/definitions/ui.d.ts.map +1 -1
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.d.ts.map +1 -1
- package/dist/helpers/get-resolved-ref.d.ts +6 -0
- package/dist/helpers/get-resolved-ref.d.ts.map +1 -1
- package/dist/helpers/get-resolved-ref.js +9 -0
- package/dist/helpers/is-hidden.d.ts +8 -0
- package/dist/helpers/is-hidden.d.ts.map +1 -0
- package/dist/helpers/is-hidden.js +5 -0
- package/dist/mutators/auth.d.ts +22 -3
- package/dist/mutators/auth.d.ts.map +1 -1
- package/dist/mutators/auth.js +213 -37
- package/dist/mutators/cookie.d.ts.map +1 -1
- package/dist/mutators/cookie.js +3 -2
- package/dist/mutators/document.d.ts.map +1 -1
- package/dist/mutators/document.js +5 -4
- package/dist/mutators/environment.d.ts.map +1 -1
- package/dist/mutators/environment.js +12 -5
- package/dist/mutators/index.d.ts +4 -0
- package/dist/mutators/index.d.ts.map +1 -1
- package/dist/mutators/operation/body.d.ts.map +1 -1
- package/dist/mutators/operation/body.js +6 -2
- package/dist/mutators/operation/extensions.d.ts.map +1 -1
- package/dist/mutators/operation/extensions.js +5 -1
- package/dist/mutators/operation/history.d.ts.map +1 -1
- package/dist/mutators/operation/history.js +7 -3
- package/dist/mutators/operation/operation.d.ts.map +1 -1
- package/dist/mutators/operation/operation.js +15 -10
- package/dist/mutators/operation/parameters.d.ts.map +1 -1
- package/dist/mutators/operation/parameters.js +12 -5
- package/dist/mutators/server.d.ts.map +1 -1
- package/dist/mutators/server.js +2 -1
- package/dist/mutators/tag.d.ts.map +1 -1
- package/dist/mutators/tag.js +9 -4
- package/dist/navigation/helpers/get-openapi-object.d.ts.map +1 -1
- package/dist/navigation/helpers/get-openapi-object.js +5 -0
- package/dist/navigation/helpers/traverse-paths.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-paths.js +4 -3
- package/dist/navigation/helpers/traverse-schemas.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-schemas.js +9 -4
- package/dist/navigation/helpers/traverse-tags.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-tags.js +2 -1
- package/dist/navigation/helpers/traverse-webhooks.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-webhooks.js +4 -3
- package/dist/navigation/helpers/update-order-ids.d.ts.map +1 -1
- package/dist/navigation/helpers/update-order-ids.js +4 -1
- package/dist/persistence/index.d.ts +123 -80
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +233 -167
- package/dist/persistence/migrations/v2-team-to-local.d.ts +22 -5
- package/dist/persistence/migrations/v2-team-to-local.d.ts.map +1 -1
- package/dist/persistence/migrations/v2-team-to-local.js +195 -137
- package/dist/request-example/builder/body/build-request-body.d.ts.map +1 -1
- package/dist/request-example/builder/body/build-request-body.js +48 -5
- package/dist/request-example/builder/build-request.d.ts +24 -3
- package/dist/request-example/builder/build-request.d.ts.map +1 -1
- package/dist/request-example/builder/build-request.js +89 -18
- package/dist/request-example/builder/index.d.ts +2 -1
- package/dist/request-example/builder/index.d.ts.map +1 -1
- package/dist/request-example/builder/index.js +2 -1
- package/dist/request-example/builder/request-factory.d.ts.map +1 -1
- package/dist/request-example/builder/request-factory.js +5 -8
- package/dist/request-example/builder/resolve-request-factory-url.d.ts +18 -1
- package/dist/request-example/builder/resolve-request-factory-url.d.ts.map +1 -1
- package/dist/request-example/builder/resolve-request-factory-url.js +29 -4
- package/dist/request-example/context/environment.d.ts.map +1 -1
- package/dist/request-example/context/environment.js +2 -1
- package/dist/request-example/context/get-request-example-context.d.ts.map +1 -1
- package/dist/request-example/context/get-request-example-context.js +7 -0
- package/dist/request-example/context/headers.d.ts +28 -13
- package/dist/request-example/context/headers.d.ts.map +1 -1
- package/dist/request-example/context/headers.js +84 -19
- package/dist/request-example/context/index.d.ts +1 -0
- package/dist/request-example/context/index.d.ts.map +1 -1
- package/dist/request-example/context/index.js +1 -0
- package/dist/request-example/context/security/get-selected-security.d.ts.map +1 -1
- package/dist/request-example/context/security/get-selected-security.js +3 -6
- package/dist/request-example/context/servers.d.ts.map +1 -1
- package/dist/request-example/context/servers.js +3 -3
- package/dist/request-example/index.d.ts +3 -3
- package/dist/request-example/index.d.ts.map +1 -1
- package/dist/request-example/index.js +2 -2
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +1 -8
- package/dist/schemas/asyncapi/asyncapi-document.d.ts +79 -0
- package/dist/schemas/asyncapi/asyncapi-document.d.ts.map +1 -0
- package/dist/schemas/asyncapi/asyncapi-document.js +58 -0
- package/dist/schemas/extensions/document/workspace-managed-extensions.d.ts +25 -0
- package/dist/schemas/extensions/document/workspace-managed-extensions.d.ts.map +1 -0
- package/dist/schemas/extensions/document/workspace-managed-extensions.js +26 -0
- package/dist/schemas/inmemory-workspace.d.ts +3 -4631
- package/dist/schemas/inmemory-workspace.d.ts.map +1 -1
- package/dist/schemas/inmemory-workspace.js +1 -15
- package/dist/schemas/reference-config/index.d.ts +3 -2
- package/dist/schemas/reference-config/index.d.ts.map +1 -1
- package/dist/schemas/reference-config/settings.d.ts +2 -1
- package/dist/schemas/reference-config/settings.d.ts.map +1 -1
- package/dist/schemas/type-guards.d.ts +24 -0
- package/dist/schemas/type-guards.d.ts.map +1 -0
- package/dist/schemas/type-guards.js +35 -0
- package/dist/schemas/v3.1/openapi/index.d.ts +2 -1
- package/dist/schemas/v3.1/openapi/index.d.ts.map +1 -1
- package/dist/schemas/v3.1/openapi/index.js +3 -3
- package/dist/schemas/v3.1/strict/openapi-document.d.ts +74 -39
- package/dist/schemas/v3.1/strict/openapi-document.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/openapi-document.js +6 -2
- package/dist/schemas/workspace-specification/index.d.ts +1 -1
- package/dist/schemas/workspace.d.ts +15 -4377
- package/dist/schemas/workspace.d.ts.map +1 -1
- package/dist/schemas/workspace.js +13 -8
- package/dist/schemas.d.ts +3 -1
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +3 -1
- package/package.json +6 -6
|
@@ -1,18 +1,79 @@
|
|
|
1
|
+
import { X_SCALAR_DATE, X_SCALAR_DNT, X_SCALAR_REFERER, X_SCALAR_USER_AGENT } from '@scalar/helpers/http/scalar-headers';
|
|
1
2
|
import { replaceEnvVariables } from '@scalar/helpers/regex/replace-variables';
|
|
3
|
+
import { err, ok } from '@scalar/helpers/types/result';
|
|
4
|
+
import { safeRun } from '@scalar/helpers/types/safe-run';
|
|
2
5
|
import { redirectToProxy, shouldUseProxy } from '@scalar/helpers/url/redirect-to-proxy';
|
|
3
6
|
import { encode as encodeBase64 } from 'js-base64';
|
|
4
7
|
import { buildRequestCookieHeader } from '../../request-example/builder/header/build-request-cookie-header.js';
|
|
5
8
|
import { applyAllowReservedToUrl } from '../../request-example/builder/helpers/apply-allow-reserved-to-url.js';
|
|
6
|
-
import { resolveRequestFactoryUrl } from '../../request-example/builder/resolve-request-factory-url.js';
|
|
9
|
+
import { resolveRequestFactoryUrl, } from '../../request-example/builder/resolve-request-factory-url.js';
|
|
7
10
|
import { contextFunctions, isContextFunctionName } from '../../request-example/functions.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
const FORBIDDEN_HEADERS = [
|
|
12
|
+
{ header: 'date', scalarHeader: X_SCALAR_DATE },
|
|
13
|
+
{ header: 'dnt', scalarHeader: X_SCALAR_DNT },
|
|
14
|
+
{ header: 'referer', scalarHeader: X_SCALAR_REFERER },
|
|
15
|
+
{ header: 'user-agent', scalarHeader: X_SCALAR_USER_AGENT },
|
|
16
|
+
];
|
|
17
|
+
const formatSecurityValue = (security, replace) => {
|
|
18
|
+
const substitutedValue = replaceEnvVariables(security.value, replace);
|
|
19
|
+
if (security.format === 'basic') {
|
|
20
|
+
return `Basic ${encodeBase64(substitutedValue)}`;
|
|
21
|
+
}
|
|
22
|
+
if (security.format === 'bearer') {
|
|
23
|
+
return `Bearer ${substitutedValue}`;
|
|
24
|
+
}
|
|
25
|
+
return substitutedValue;
|
|
26
|
+
};
|
|
27
|
+
const createEnvReplaceFn = (envVariables) => {
|
|
28
|
+
return (value) => {
|
|
11
29
|
if (isContextFunctionName(value)) {
|
|
12
30
|
return contextFunctions[value].fn() ?? null;
|
|
13
31
|
}
|
|
14
|
-
return
|
|
32
|
+
return envVariables[value] ?? null;
|
|
15
33
|
};
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Resolved request URL string (path vars, operation query, **security query**
|
|
37
|
+
* params, env substitution, reserved-query rules) without proxy rewriting —
|
|
38
|
+
* aligned with {@link buildRequest} before `redirectToProxy`.
|
|
39
|
+
*
|
|
40
|
+
* By default allows incomplete merged URLs (same as permissive copy / preview); pass
|
|
41
|
+
* `allowMissingRequestServerBase: false` to enforce a complete absolute URL.
|
|
42
|
+
*/
|
|
43
|
+
export const resolveExecutableRequestUrl = (request, envVariables, resolveOptions) => {
|
|
44
|
+
const replace = createEnvReplaceFn(envVariables);
|
|
45
|
+
const securityQueryParams = new URLSearchParams();
|
|
46
|
+
if (!request.options?.disableSecurity) {
|
|
47
|
+
request.security.forEach((security) => {
|
|
48
|
+
if (security.in !== 'query') {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const name = replaceEnvVariables(security.name, replace);
|
|
52
|
+
securityQueryParams.append(name, formatSecurityValue(security, replace));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const requestUrl = resolveRequestFactoryUrl(request, {
|
|
56
|
+
envVariables: replace,
|
|
57
|
+
securityQueryParams,
|
|
58
|
+
allowMissingRequestServerBase: resolveOptions?.allowMissingRequestServerBase ?? true,
|
|
59
|
+
});
|
|
60
|
+
if (!requestUrl.ok) {
|
|
61
|
+
throw new Error(requestUrl.message ?? requestUrl.error);
|
|
62
|
+
}
|
|
63
|
+
return applyAllowReservedToUrl(requestUrl.data, request.allowedReservedQueryParameters ?? new Set());
|
|
64
|
+
};
|
|
65
|
+
/** Catch-all code when an unexpected synchronous error escapes a helper during request construction. */
|
|
66
|
+
export const BUILD_REQUEST_FAILED = 'BUILD_REQUEST_FAILED';
|
|
67
|
+
export const buildRequest = (request, options) => {
|
|
68
|
+
const guarded = safeRun(() => buildRequestInner(request, options));
|
|
69
|
+
if (!guarded.ok) {
|
|
70
|
+
return err(BUILD_REQUEST_FAILED, guarded.error);
|
|
71
|
+
}
|
|
72
|
+
return guarded.data;
|
|
73
|
+
};
|
|
74
|
+
const buildRequestInner = (request, options) => {
|
|
75
|
+
/** Replace the value with the environment variable or context function */
|
|
76
|
+
const replace = createEnvReplaceFn(options.envVariables);
|
|
16
77
|
/** Create a new abort controller */
|
|
17
78
|
const controller = new AbortController();
|
|
18
79
|
/** Create a new headers object with the replaced values */
|
|
@@ -60,16 +121,7 @@ export const buildRequest = (request, options) => {
|
|
|
60
121
|
// - For 'basic': prefix with 'Basic' and base64-encode the value (username:password).
|
|
61
122
|
// - For 'bearer': prefix with 'Bearer'.
|
|
62
123
|
// - Otherwise: use the substituted value as is (for API keys, etc).
|
|
63
|
-
const securityValue = (
|
|
64
|
-
const substitutedValue = replaceEnvVariables(security.value, replace);
|
|
65
|
-
if (security.format === 'basic') {
|
|
66
|
-
return `Basic ${encodeBase64(substitutedValue)}`;
|
|
67
|
-
}
|
|
68
|
-
if (security.format === 'bearer') {
|
|
69
|
-
return `Bearer ${substitutedValue}`;
|
|
70
|
-
}
|
|
71
|
-
return substitutedValue;
|
|
72
|
-
})();
|
|
124
|
+
const securityValue = formatSecurityValue(security, replace);
|
|
73
125
|
if (security.in === 'header') {
|
|
74
126
|
// Set the header (use replaced header name so {{ env }} placeholders work)
|
|
75
127
|
headers.append(name, securityValue);
|
|
@@ -89,10 +141,15 @@ export const buildRequest = (request, options) => {
|
|
|
89
141
|
});
|
|
90
142
|
}
|
|
91
143
|
/** Resolve the request URL with the replaced values */
|
|
92
|
-
const
|
|
144
|
+
const requestUrlResult = resolveRequestFactoryUrl(request, {
|
|
93
145
|
envVariables: replace,
|
|
94
146
|
securityQueryParams: securityQueryParams,
|
|
147
|
+
allowMissingRequestServerBase: options.allowMissingRequestServerBase,
|
|
95
148
|
});
|
|
149
|
+
if (!requestUrlResult.ok) {
|
|
150
|
+
return err(requestUrlResult.error, requestUrlResult.message);
|
|
151
|
+
}
|
|
152
|
+
const requestUrl = requestUrlResult.data;
|
|
96
153
|
/** Check if the request should be proxied */
|
|
97
154
|
const isUsingProxy = shouldUseProxy(request.proxyUrl, requestUrl);
|
|
98
155
|
/** Create a new cookies array with the replaced values */
|
|
@@ -112,10 +169,24 @@ export const buildRequest = (request, options) => {
|
|
|
112
169
|
if (cookieHeader) {
|
|
113
170
|
headers.set(cookieHeader.name, cookieHeader.value);
|
|
114
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Browsers strip some forbidden headers from outgoing requests.
|
|
174
|
+
* For a small, explicit allowlist we mirror those values to `X-Scalar-*`
|
|
175
|
+
* so proxy/Electron can apply them server-side.
|
|
176
|
+
*/
|
|
177
|
+
if (isUsingProxy || request.options?.isElectron) {
|
|
178
|
+
FORBIDDEN_HEADERS.forEach(({ header, scalarHeader }) => {
|
|
179
|
+
const headerValue = headers.get(header);
|
|
180
|
+
if (headerValue) {
|
|
181
|
+
headers.set(scalarHeader, headerValue);
|
|
182
|
+
headers.delete(header);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
115
186
|
/** Encode the URL with the allowed reserved query parameters */
|
|
116
187
|
const encodedUrl = applyAllowReservedToUrl(requestUrl, request.allowedReservedQueryParameters ?? new Set());
|
|
117
188
|
const finalUrl = isUsingProxy ? redirectToProxy(request.proxyUrl, encodedUrl) : encodedUrl;
|
|
118
|
-
return {
|
|
189
|
+
return ok({
|
|
119
190
|
requestPayload: [
|
|
120
191
|
finalUrl,
|
|
121
192
|
{
|
|
@@ -133,5 +204,5 @@ export const buildRequest = (request, options) => {
|
|
|
133
204
|
],
|
|
134
205
|
controller,
|
|
135
206
|
isUsingProxy,
|
|
136
|
-
};
|
|
207
|
+
});
|
|
137
208
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { getExampleFromBody } from './body/get-request-body-example.js';
|
|
2
2
|
export { getSelectedBodyContentType } from './body/get-selected-body-content-type.js';
|
|
3
|
-
export { type RequestPayload, buildRequest } from './build-request.js';
|
|
3
|
+
export { BUILD_REQUEST_FAILED, type BuildRequestData, type BuildRequestFailureCode, type BuildRequestResult, type RequestPayload, buildRequest, resolveExecutableRequestUrl, } from './build-request.js';
|
|
4
4
|
export { deSerializeParameter } from './header/de-serialize-parameter.js';
|
|
5
5
|
export { filterGlobalCookie } from './header/filter-global-cookies.js';
|
|
6
6
|
export { serializeContentValue, serializeDeepObjectStyle, serializeFormStyle, serializeFormStyleForCookies, serializePipeDelimitedStyle, serializeSimpleStyle, serializeSpaceDelimitedStyle, } from './header/serialize-parameter.js';
|
|
@@ -11,6 +11,7 @@ export { getResolvedUrl } from './helpers/get-resolved-url.js';
|
|
|
11
11
|
export { getServerVariables } from './helpers/get-server-variables.js';
|
|
12
12
|
export type { RequestFactory } from './request-factory.js';
|
|
13
13
|
export { requestFactory } from './request-factory.js';
|
|
14
|
+
export { INVALID_REQUEST_FACTORY_URL, MISSING_REQUEST_SERVER_BASE, type ResolveRequestFactoryUrlError, type ResolveRequestFactoryUrlResult, resolveRequestFactoryUrl, } from './resolve-request-factory-url.js';
|
|
14
15
|
export { buildRequestSecurity } from './security/build-request-security.js';
|
|
15
16
|
export type { ApiKeyObjectSecret, HttpObjectSecret, OAuth2ObjectSecret, OAuthFlowAuthorizationCodeSecret, OAuthFlowClientCredentialsSecret, OAuthFlowImplicitSecret, OAuthFlowPasswordSecret, OAuthFlowsObjectSecret, OpenIdConnectObjectSecret, SecuritySchemeObjectSecret, } from './security/secret-types.js';
|
|
16
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/request-example/builder/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAA;AAClF,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/request-example/builder/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAA;AAClF,OAAO,EACL,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,YAAY,EACZ,2BAA2B,GAC5B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAA;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnE,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,kBAAkB,EAClB,4BAA4B,EAC5B,2BAA2B,EAC3B,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAA;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EACL,2BAA2B,EAC3B,2BAA2B,EAC3B,KAAK,6BAA6B,EAClC,KAAK,8BAA8B,EACnC,wBAAwB,GACzB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AACxE,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,gCAAgC,EAChC,gCAAgC,EAChC,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,yBAAyB,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { getExampleFromBody } from './body/get-request-body-example.js';
|
|
2
2
|
export { getSelectedBodyContentType } from './body/get-selected-body-content-type.js';
|
|
3
|
-
export { buildRequest } from './build-request.js';
|
|
3
|
+
export { BUILD_REQUEST_FAILED, buildRequest, resolveExecutableRequestUrl, } from './build-request.js';
|
|
4
4
|
export { deSerializeParameter } from './header/de-serialize-parameter.js';
|
|
5
5
|
export { filterGlobalCookie } from './header/filter-global-cookies.js';
|
|
6
6
|
export { serializeContentValue, serializeDeepObjectStyle, serializeFormStyle, serializeFormStyleForCookies, serializePipeDelimitedStyle, serializeSimpleStyle, serializeSpaceDelimitedStyle, } from './header/serialize-parameter.js';
|
|
@@ -10,4 +10,5 @@ export { getExampleFromSchema } from './helpers/get-example-from-schema.js';
|
|
|
10
10
|
export { getResolvedUrl } from './helpers/get-resolved-url.js';
|
|
11
11
|
export { getServerVariables } from './helpers/get-server-variables.js';
|
|
12
12
|
export { requestFactory } from './request-factory.js';
|
|
13
|
+
export { INVALID_REQUEST_FACTORY_URL, MISSING_REQUEST_SERVER_BASE, resolveRequestFactoryUrl, } from './resolve-request-factory-url.js';
|
|
13
14
|
export { buildRequestSecurity } from './security/build-request-security.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-factory.d.ts","sourceRoot":"","sources":["../../../src/request-example/builder/request-factory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"request-factory.d.ts","sourceRoot":"","sources":["../../../src/request-example/builder/request-factory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAA;AACxG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AAChG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uDAAuD,CAAA;AAG5F,OAAO,EACL,KAAK,0BAA0B,EAEhC,MAAM,2DAA2D,CAAA;AAClE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAA;AACjG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,EAAE,KAAK,WAAW,EAAoB,MAAM,2BAA2B,CAAA;AAG9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAA;IAEf;;OAEG;IACH,IAAI,EAAE;QACJ;;;;;WAKG;QACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACjC;;;;;WAKG;QACH,GAAG,EAAE,MAAM,CAAA;KACZ,CAAA;IAED;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;OAGG;IACH,KAAK,EAAE,eAAe,CAAA;IAEtB;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAA;IAEhB;;;;OAIG;IACH,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;IAExB;;;;OAIG;IACH,OAAO,EAAE,aAAa,EAAE,CAAA;IAExB;;;OAGG;IACH,KAAK,EAAE,YAAY,CAAA;IAEnB;;;;OAIG;IACH,QAAQ,EAAE,0BAA0B,EAAE,CAAA;IAEtC;;;OAGG;IACH,8BAA8B,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAE5C;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAC;QACf;;;WAGG;QACH,UAAU,EAAE,OAAO,CAAA;QACnB;;;WAGG;QACH,eAAe,EAAE,OAAO,CAAA;KACzB,CAAC,CAAA;CACH,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,kKAY5B,kBAAkB,GAAG;IACtB,2BAA2B;IAC3B,SAAS,EAAE,eAAe,CAAA;IAC1B,8CAA8C;IAC9C,WAAW,EAAE,kBAAkB,CAAA;IAC/B,mCAAmC;IACnC,aAAa,EAAE,aAAa,EAAE,CAAA;IAC9B,oDAAoD;IACpD,QAAQ,EAAE,MAAM,CAAA;IAChB,wBAAwB;IACxB,MAAM,EAAE,YAAY,GAAG,IAAI,CAAA;IAC3B,sBAAsB;IACtB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,qEAAqE;IACrE,UAAU,EAAE,OAAO,CAAA;IACnB,8DAA8D;IAC9D,uBAAuB,EAAE,0BAA0B,EAAE,CAAA;IACrD,sEAAsE;IACtE,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzD,KAAG;IACF,OAAO,EAAE,cAAc,CAAA;CAqExB,CAAA"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { canMethodHaveBody } from '@scalar/helpers/http/can-method-have-body';
|
|
2
|
-
import { X_SCALAR_USER_AGENT } from '@scalar/helpers/http/scalar-headers';
|
|
3
2
|
import { replacePathVariables } from '@scalar/helpers/regex/replace-variables';
|
|
4
3
|
import { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref';
|
|
5
4
|
import { getServerVariables } from '../../request-example/builder/helpers/get-server-variables.js';
|
|
6
5
|
import { buildRequestSecurity, } from '../../request-example/builder/security/build-request-security.js';
|
|
6
|
+
import { filterDisabledDefaultHeaders } from '../context/headers.js';
|
|
7
7
|
import { buildRequestBody } from './body/build-request-body.js';
|
|
8
8
|
import { buildRequestParameters } from './header/build-request-parameters.js';
|
|
9
9
|
/**
|
|
@@ -15,7 +15,10 @@ export const requestFactory = ({ exampleName, globalCookies, method, operation,
|
|
|
15
15
|
/** Build out the request parameters */
|
|
16
16
|
const params = buildRequestParameters(operation.parameters ?? [], exampleName);
|
|
17
17
|
const security = buildRequestSecurity(selectedSecuritySchemes);
|
|
18
|
-
const headers = new Headers({
|
|
18
|
+
const headers = new Headers({
|
|
19
|
+
...filterDisabledDefaultHeaders(operation, exampleName, defaultHeaders),
|
|
20
|
+
...params.headers,
|
|
21
|
+
});
|
|
19
22
|
// If the method can have a body, build the request body, otherwise set it to null
|
|
20
23
|
const body = canMethodHaveBody(method)
|
|
21
24
|
? buildRequestBody(requestBody, exampleName, requestBodyCompositionSelection)
|
|
@@ -27,12 +30,6 @@ export const requestFactory = ({ exampleName, globalCookies, method, operation,
|
|
|
27
30
|
/** Combine the server url, path and url params into a single url */
|
|
28
31
|
const serverVariables = getServerVariables(server);
|
|
29
32
|
const baseUrl = replacePathVariables(server?.url ?? '', serverVariables);
|
|
30
|
-
// If we are running in Electron, we need to add a custom header
|
|
31
|
-
// that's then forwarded as a `User-Agent` header.
|
|
32
|
-
const userAgentHeader = headers.get('User-Agent');
|
|
33
|
-
if (isElectron && userAgentHeader) {
|
|
34
|
-
headers.set(X_SCALAR_USER_AGENT, userAgentHeader);
|
|
35
|
-
}
|
|
36
33
|
const globalCookieFilter = operation['x-scalar-disable-parameters']?.['global-cookies']?.[exampleName] ?? {};
|
|
37
34
|
const cookiesList = [
|
|
38
35
|
...globalCookies.map((c) => ({
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
+
import { type Result } from '@scalar/helpers/types/result';
|
|
1
2
|
import type { RequestFactory } from '../../request-example/builder/request-factory.js';
|
|
3
|
+
/**
|
|
4
|
+
* Discriminated error code when the merged request URL is not a complete absolute target
|
|
5
|
+
* (for example no OpenAPI server, or unresolved `{{environment}}` segments left in the merged URL).
|
|
6
|
+
*/
|
|
7
|
+
export declare const MISSING_REQUEST_SERVER_BASE: "MISSING_REQUEST_SERVER_BASE";
|
|
8
|
+
/**
|
|
9
|
+
* Discriminated error code when the merged URL cannot be encoded or parsed (invalid path params, malformed URL).
|
|
10
|
+
*/
|
|
11
|
+
export declare const INVALID_REQUEST_FACTORY_URL: "INVALID_REQUEST_FACTORY_URL";
|
|
12
|
+
export type ResolveRequestFactoryUrlError = typeof MISSING_REQUEST_SERVER_BASE | typeof INVALID_REQUEST_FACTORY_URL;
|
|
13
|
+
export type ResolveRequestFactoryUrlResult = Result<string, ResolveRequestFactoryUrlError>;
|
|
2
14
|
/**
|
|
3
15
|
* Resolves the request URL string from a {@link RequestFactory} using the same
|
|
4
16
|
* rules as {@link buildRequest} (path variables, query, security query params),
|
|
@@ -7,5 +19,10 @@ import type { RequestFactory } from '../../request-example/builder/request-facto
|
|
|
7
19
|
export declare const resolveRequestFactoryUrl: (request: RequestFactory, options: {
|
|
8
20
|
envVariables: Record<string, string> | ((value: string) => string | null);
|
|
9
21
|
securityQueryParams: URLSearchParams;
|
|
10
|
-
|
|
22
|
+
/**
|
|
23
|
+
* When true, skips incomplete-URL validation (embedded modal, copy URL, tests).
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
allowMissingRequestServerBase?: boolean;
|
|
27
|
+
}) => ResolveRequestFactoryUrlResult;
|
|
11
28
|
//# sourceMappingURL=resolve-request-factory-url.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-request-factory-url.d.ts","sourceRoot":"","sources":["../../../src/request-example/builder/resolve-request-factory-url.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolve-request-factory-url.d.ts","sourceRoot":"","sources":["../../../src/request-example/builder/resolve-request-factory-url.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAW,MAAM,8BAA8B,CAAA;AAKnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAA;AAE/E;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAG,6BAAsC,CAAA;AAEjF;;GAEG;AACH,eAAO,MAAM,2BAA2B,EAAG,6BAAsC,CAAA;AAEjF,MAAM,MAAM,6BAA6B,GAAG,OAAO,2BAA2B,GAAG,OAAO,2BAA2B,CAAA;AAEnH,MAAM,MAAM,8BAA8B,GAAG,MAAM,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAA;AAK1F;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GACnC,SAAS,cAAc,EACvB,SAAS;IACP,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC,CAAA;IACzE,mBAAmB,EAAE,eAAe,CAAA;IACpC;;;OAGG;IACH,6BAA6B,CAAC,EAAE,OAAO,CAAA;CACxC,KACA,8BAqDF,CAAA"}
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import { replaceEnvVariables, replacePathVariables } from '@scalar/helpers/regex/replace-variables';
|
|
2
|
+
import { err, ok } from '@scalar/helpers/types/result';
|
|
3
|
+
import { safeRun } from '@scalar/helpers/types/safe-run';
|
|
4
|
+
import { isRelativePath } from '@scalar/helpers/url/is-relative-path';
|
|
2
5
|
import { mergeSearchParams, mergeUrls } from '@scalar/helpers/url/merge-urls';
|
|
6
|
+
/**
|
|
7
|
+
* Discriminated error code when the merged request URL is not a complete absolute target
|
|
8
|
+
* (for example no OpenAPI server, or unresolved `{{environment}}` segments left in the merged URL).
|
|
9
|
+
*/
|
|
10
|
+
export const MISSING_REQUEST_SERVER_BASE = 'MISSING_REQUEST_SERVER_BASE';
|
|
11
|
+
/**
|
|
12
|
+
* Discriminated error code when the merged URL cannot be encoded or parsed (invalid path params, malformed URL).
|
|
13
|
+
*/
|
|
14
|
+
export const INVALID_REQUEST_FACTORY_URL = 'INVALID_REQUEST_FACTORY_URL';
|
|
15
|
+
const INCOMPLETE_MERGED_URL_MESSAGE = 'No server URL is configured for this request. Add a servers entry to your OpenAPI document (or set a server in the client) before sending.';
|
|
3
16
|
/**
|
|
4
17
|
* Resolves the request URL string from a {@link RequestFactory} using the same
|
|
5
18
|
* rules as {@link buildRequest} (path variables, query, security query params),
|
|
@@ -7,20 +20,32 @@ import { mergeSearchParams, mergeUrls } from '@scalar/helpers/url/merge-urls';
|
|
|
7
20
|
*/
|
|
8
21
|
export const resolveRequestFactoryUrl = (request, options) => {
|
|
9
22
|
const variables = options.envVariables;
|
|
10
|
-
const
|
|
23
|
+
const pathVariablesEncoded = safeRun(() => Object.fromEntries(Object.entries(request.path.variables).map(([key, value]) => [
|
|
11
24
|
key,
|
|
12
25
|
encodeURIComponent(replaceEnvVariables(value, variables)),
|
|
13
|
-
]));
|
|
26
|
+
])));
|
|
27
|
+
if (!pathVariablesEncoded.ok) {
|
|
28
|
+
return err(INVALID_REQUEST_FACTORY_URL, 'The request URL contains invalid characters in path parameters.');
|
|
29
|
+
}
|
|
30
|
+
const pathVariables = pathVariablesEncoded.data;
|
|
14
31
|
const baseUrl = replaceEnvVariables(request.baseUrl, variables);
|
|
15
32
|
const rawPath = replaceEnvVariables(request.path.raw, variables);
|
|
16
33
|
const path = replacePathVariables(rawPath, pathVariables);
|
|
17
34
|
const mergedUrl = mergeUrls(baseUrl, path);
|
|
35
|
+
if (!options.allowMissingRequestServerBase && isRelativePath(mergedUrl)) {
|
|
36
|
+
return err(MISSING_REQUEST_SERVER_BASE, INCOMPLETE_MERGED_URL_MESSAGE);
|
|
37
|
+
}
|
|
18
38
|
// When rendered inside an iframe with srcdoc, the browser reports
|
|
19
39
|
// window.location.origin as the string "null" instead of a real origin.
|
|
20
40
|
// Fall back to localhost so relative URLs can still be resolved.
|
|
21
41
|
const origin = globalThis.window?.location?.origin;
|
|
22
42
|
const urlBase = origin && origin !== 'null' ? origin : 'http://localhost:3000';
|
|
23
|
-
|
|
43
|
+
// Fallback for modal layout without a base server url (it should use the current origin)
|
|
44
|
+
const urlParsed = safeRun(() => new URL(mergedUrl, urlBase));
|
|
45
|
+
if (!urlParsed.ok) {
|
|
46
|
+
return err(INVALID_REQUEST_FACTORY_URL, 'The request URL could not be parsed. Check the server URL and path for invalid characters.');
|
|
47
|
+
}
|
|
48
|
+
const url = urlParsed.data;
|
|
24
49
|
const operationQueryParams = new URLSearchParams();
|
|
25
50
|
for (const [key, value] of request.query.entries()) {
|
|
26
51
|
operationQueryParams.append(replaceEnvVariables(key, variables), replaceEnvVariables(value, variables));
|
|
@@ -30,5 +55,5 @@ export const resolveRequestFactoryUrl = (request, options) => {
|
|
|
30
55
|
securityQueryParams.append(key, value);
|
|
31
56
|
}
|
|
32
57
|
url.search = mergeSearchParams(url.searchParams, operationQueryParams, securityQueryParams).toString();
|
|
33
|
-
return url.toString();
|
|
58
|
+
return ok(url.toString());
|
|
34
59
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../../src/request-example/context/environment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,EAAE,KAAK,kBAAkB,EAA4B,MAAM,qDAAqD,CAAA;
|
|
1
|
+
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../../src/request-example/context/environment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,EAAE,KAAK,kBAAkB,EAA4B,MAAM,qDAAqD,CAAA;AAGvH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,GAC/B,WAAW,cAAc,GAAG,IAAI,EAChC,UAAU,iBAAiB,GAAG,IAAI,KACjC;IACD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,WAAW,EAAE,kBAAkB,CAAA;CAqChC,CAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { xScalarEnvironmentSchema } from '../../schemas/extensions/document/x-scalar-environments.js';
|
|
2
|
+
import { isOpenApiDocument } from '../../schemas/type-guards.js';
|
|
2
3
|
import { coerceValue } from '../../schemas/typebox-coerce.js';
|
|
3
4
|
/**
|
|
4
5
|
* Returns the active environment context for a given workspace and document.
|
|
@@ -34,7 +35,7 @@ export const getActiveEnvironment = (workspace, document) => {
|
|
|
34
35
|
const workspaceEnv = workspace.workspace['x-scalar-environments']?.[activeEnv] ?? {
|
|
35
36
|
variables: [],
|
|
36
37
|
};
|
|
37
|
-
const documentEnv = document
|
|
38
|
+
const documentEnv = (isOpenApiDocument(document) ? document['x-scalar-environments']?.[activeEnv] : undefined) ?? {
|
|
38
39
|
variables: [],
|
|
39
40
|
};
|
|
40
41
|
// Merge workspace and document variables, with document variables appended
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-request-example-context.d.ts","sourceRoot":"","sources":["../../../src/request-example/context/get-request-example-context.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,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAEpD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAA;AAIjG,OAAO,EAAE,KAAK,MAAM,EAAqB,MAAM,iCAAiC,CAAA;AAIhF,OAAO,EAAE,KAAK,qBAAqB,EAAiB,MAAM,mDAAmD,CAAA;AAE7G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qDAAqD,CAAA;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAA;
|
|
1
|
+
{"version":3,"file":"get-request-example-context.d.ts","sourceRoot":"","sources":["../../../src/request-example/context/get-request-example-context.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,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAEpD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAA;AAIjG,OAAO,EAAE,KAAK,MAAM,EAAqB,MAAM,iCAAiC,CAAA;AAIhF,OAAO,EAAE,KAAK,qBAAqB,EAAiB,MAAM,mDAAmD,CAAA;AAE7G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qDAAqD,CAAA;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAA;AAElF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACtE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAA;AAC3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,eAAe,CAAA;IAC1B,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;QACnB,WAAW,EAAE,kBAAkB,CAAA;KAChC,CAAA;IACD,OAAO,EAAE;QACP,SAAS,EAAE,aAAa,EAAE,CAAA;QAC1B,QAAQ,EAAE,aAAa,EAAE,CAAA;KAC1B,CAAA;IACD,OAAO,EAAE;QACP,IAAI,EAAE,YAAY,EAAE,CAAA;QACpB,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;QAC7B,IAAI,EAAE,UAAU,CAAA;KACjB,CAAA;IACD,KAAK,EAAE;QACL,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KACnB,CAAA;IACD,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAChC,CAAA;IACD,QAAQ,EAAE;QACR,OAAO,EAAE,qBAAqB,CAAA;QAC9B,YAAY,EAAE,yBAAyB,EAAE,CAAA;QACzC,QAAQ,EAAE,gBAAgB,CAAA;QAC1B,eAAe,EAAE,0BAA0B,EAAE,CAAA;QAC7C,IAAI,EAAE,QAAQ,CAAA;KACf,CAAA;CACF,CAAA;AAED,eAAO,MAAM,wBAAwB,GACnC,gBAAgB,cAAc,EAC9B,cAAc,MAAM,EACpB,oBAAoB,kBAAkB,EACtC,UAAS,OAAO,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,OAAO,CAAA;IACnB,+CAA+C;IAC/C,cAAc,EAAE,2BAA2B,CAAA;IAC3C;;;;OAIG;IACH,gBAAgB,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAC3C,CAAM,KACN,MAAM,CAAC,0BAA0B,CA6InC,CAAA"}
|
|
@@ -8,6 +8,7 @@ import { getSecuritySchemes } from '../../request-example/context/security/get-s
|
|
|
8
8
|
import { getSelectedSecurity } from '../../request-example/context/security/get-selected-security.js';
|
|
9
9
|
import { mergeSecurity } from '../../request-example/context/security/merge-security.js';
|
|
10
10
|
import { getSelectedServer, getServers } from '../../request-example/context/servers.js';
|
|
11
|
+
import { isOpenApiDocument } from '../../schemas/type-guards.js';
|
|
11
12
|
export const getRequestExampleContext = (workspaceStore, documentName, requestExampleMeta, options = {}) => {
|
|
12
13
|
const { path, method, exampleName } = requestExampleMeta;
|
|
13
14
|
const document = workspaceStore.workspace.documents[documentName] ?? options.fallbackDocument ?? undefined;
|
|
@@ -17,6 +18,12 @@ export const getRequestExampleContext = (workspaceStore, documentName, requestEx
|
|
|
17
18
|
error: `Document ${documentName} not found`,
|
|
18
19
|
};
|
|
19
20
|
}
|
|
21
|
+
if (!isOpenApiDocument(document)) {
|
|
22
|
+
return {
|
|
23
|
+
ok: false,
|
|
24
|
+
error: `Document ${documentName} is not an OpenAPI document`,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
20
27
|
const pathItem = getResolvedRef(document.paths?.[path]);
|
|
21
28
|
if (!pathItem) {
|
|
22
29
|
return {
|
|
@@ -1,30 +1,45 @@
|
|
|
1
1
|
import type { HttpMethod } from '@scalar/helpers/http/http-methods';
|
|
2
2
|
import type { OperationObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Restores conventional casing for well-known default headers.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* We keep this intentionally scoped to the defaults we auto-generate so we do not
|
|
7
|
+
* unexpectedly rewrite user-defined header parameter names.
|
|
8
|
+
*/
|
|
9
|
+
export declare const restoreConventionalHeaderName: (headerName: string) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Restores conventional casing for default header keys.
|
|
12
|
+
*/
|
|
13
|
+
export declare const restoreConventionalDefaultHeaderNames: (headers: Record<string, string>) => Record<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
* Drops default header entries that are disabled for this example via
|
|
16
|
+
* `operation['x-scalar-disable-parameters']['default-headers'][exampleName]`.
|
|
17
|
+
*
|
|
18
|
+
* Context builders keep the full default header map for the UI; call this when merging into the
|
|
19
|
+
* outbound request (for example in `requestFactory`).
|
|
20
|
+
*/
|
|
21
|
+
export declare const filterDisabledDefaultHeaders: (operation: OperationObject, exampleName: string, headers: Record<string, string>) => Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Generates default headers for an OpenAPI operation and HTTP method.
|
|
24
|
+
*
|
|
25
|
+
* This function adds standard HTTP headers based on the request context:
|
|
7
26
|
* - Content-Type: Added only if the HTTP method supports a request body and the OpenAPI operation
|
|
8
27
|
* defines a request body content type. Uses the selected content type from the operation or the
|
|
9
|
-
* first defined request body content type.
|
|
28
|
+
* first defined request body content type. Omitted when the selection is `none` or `other`.
|
|
10
29
|
* - Accept: Derived from the 2xx response content types in the spec (joined as a comma-separated list), falling back to a wildcard.
|
|
11
30
|
* - User-Agent: Added in Electron environments (desktop app or proxy) to identify the client.
|
|
12
31
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* @param method The HTTP method of the operation (GET, POST, etc.)
|
|
18
|
-
* @param operation The OpenAPI OperationObject describing the endpoint
|
|
19
|
-
* @param exampleKey The current request example key
|
|
20
|
-
* @param hideDisabledHeaders If true, filters out headers marked as disabled for this example
|
|
21
|
-
* @returns Array of default header objects with their values and override status
|
|
32
|
+
* @param hideDisabledHeaders If true, filters out headers marked as disabled for this example via
|
|
33
|
+
* `x-scalar-disable-parameters.default-headers`.
|
|
34
|
+
* @param hideOverriddenHeaders If true, omits any default header whose name matches an **enabled**
|
|
35
|
+
* operation parameter with `in: header` (disabled optional header parameters do not shadow defaults).
|
|
22
36
|
*/
|
|
23
|
-
export declare const getDefaultHeaders: ({ method, operation, exampleName, hideDisabledHeaders, options, }: {
|
|
37
|
+
export declare const getDefaultHeaders: ({ method, operation, exampleName, hideDisabledHeaders, hideOverriddenHeaders, options, }: {
|
|
24
38
|
method: HttpMethod;
|
|
25
39
|
operation: OperationObject;
|
|
26
40
|
exampleName: string;
|
|
27
41
|
hideDisabledHeaders?: boolean;
|
|
42
|
+
hideOverriddenHeaders?: boolean;
|
|
28
43
|
options?: {
|
|
29
44
|
appVersion: string;
|
|
30
45
|
isElectron: boolean;
|
|
@@ -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;AAanG;;;;;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;AAkDlH;;;;;;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,39 +1,100 @@
|
|
|
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
|
+
import { isParamDisabled } from '../../request-example/builder/header/is-param-disabled.js';
|
|
3
4
|
/** Default Accept header value to accept all response types. */
|
|
4
5
|
const DEFAULT_ACCEPT = '*/*';
|
|
6
|
+
const CONVENTIONAL_DEFAULT_HEADER_NAMES = {
|
|
7
|
+
accept: 'Accept',
|
|
8
|
+
'content-type': 'Content-Type',
|
|
9
|
+
'user-agent': 'User-Agent',
|
|
10
|
+
};
|
|
5
11
|
/**
|
|
6
|
-
*
|
|
12
|
+
* Restores conventional casing for well-known default headers.
|
|
7
13
|
*
|
|
8
|
-
*
|
|
14
|
+
* We keep this intentionally scoped to the defaults we auto-generate so we do not
|
|
15
|
+
* unexpectedly rewrite user-defined header parameter names.
|
|
16
|
+
*/
|
|
17
|
+
export const restoreConventionalHeaderName = (headerName) => CONVENTIONAL_DEFAULT_HEADER_NAMES[headerName.toLowerCase()] ?? headerName;
|
|
18
|
+
/**
|
|
19
|
+
* Restores conventional casing for default header keys.
|
|
20
|
+
*/
|
|
21
|
+
export const restoreConventionalDefaultHeaderNames = (headers) => Object.fromEntries(Object.entries(headers).map(([name, value]) => [restoreConventionalHeaderName(name), value]));
|
|
22
|
+
/**
|
|
23
|
+
* Lowercase names of **enabled** operation parameters with `in: header` for the given example.
|
|
24
|
+
* Uses the same rules as the request builder (`isParamDisabled`): optional parameters are treated
|
|
25
|
+
* as disabled unless `examples[exampleName]['x-disabled']` is explicitly `false`.
|
|
26
|
+
*/
|
|
27
|
+
const getEnabledOperationHeaderParameterNames = (operation, exampleName) => {
|
|
28
|
+
const names = new Set();
|
|
29
|
+
for (const ref of operation.parameters ?? []) {
|
|
30
|
+
const param = getResolvedRef(ref);
|
|
31
|
+
if (param.in !== 'header') {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const rawExample = 'examples' in param && param.examples?.[exampleName] ? param.examples[exampleName] : undefined;
|
|
35
|
+
const example = rawExample ? getResolvedRef(rawExample) : undefined;
|
|
36
|
+
if (!isParamDisabled(param, example)) {
|
|
37
|
+
names.add(param.name.toLowerCase());
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return names;
|
|
41
|
+
};
|
|
42
|
+
const filterDefaultHeadersByVisibility = (operation, exampleName, headers, flags) => {
|
|
43
|
+
const headerParamNames = flags.hideOverriddenHeaders
|
|
44
|
+
? getEnabledOperationHeaderParameterNames(operation, exampleName)
|
|
45
|
+
: null;
|
|
46
|
+
const disabledHeaders = flags.hideDisabledHeaders
|
|
47
|
+
? (operation['x-scalar-disable-parameters']?.['default-headers']?.[exampleName] ?? {})
|
|
48
|
+
: null;
|
|
49
|
+
return Object.fromEntries(Object.entries(headers).filter(([name]) => {
|
|
50
|
+
const key = name.toLowerCase();
|
|
51
|
+
if (headerParamNames?.has(key)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (disabledHeaders && disabledHeaders[key] === true) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}));
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Drops default header entries that are disabled for this example via
|
|
62
|
+
* `operation['x-scalar-disable-parameters']['default-headers'][exampleName]`.
|
|
63
|
+
*
|
|
64
|
+
* Context builders keep the full default header map for the UI; call this when merging into the
|
|
65
|
+
* outbound request (for example in `requestFactory`).
|
|
66
|
+
*/
|
|
67
|
+
export const filterDisabledDefaultHeaders = (operation, exampleName, headers) => filterDefaultHeadersByVisibility(operation, exampleName, headers, {
|
|
68
|
+
hideOverriddenHeaders: false,
|
|
69
|
+
hideDisabledHeaders: true,
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* Generates default headers for an OpenAPI operation and HTTP method.
|
|
73
|
+
*
|
|
74
|
+
* This function adds standard HTTP headers based on the request context:
|
|
9
75
|
* - Content-Type: Added only if the HTTP method supports a request body and the OpenAPI operation
|
|
10
76
|
* defines a request body content type. Uses the selected content type from the operation or the
|
|
11
|
-
* first defined request body content type.
|
|
77
|
+
* first defined request body content type. Omitted when the selection is `none` or `other`.
|
|
12
78
|
* - Accept: Derived from the 2xx response content types in the spec (joined as a comma-separated list), falling back to a wildcard.
|
|
13
79
|
* - User-Agent: Added in Electron environments (desktop app or proxy) to identify the client.
|
|
14
80
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @param method The HTTP method of the operation (GET, POST, etc.)
|
|
20
|
-
* @param operation The OpenAPI OperationObject describing the endpoint
|
|
21
|
-
* @param exampleKey The current request example key
|
|
22
|
-
* @param hideDisabledHeaders If true, filters out headers marked as disabled for this example
|
|
23
|
-
* @returns Array of default header objects with their values and override status
|
|
81
|
+
* @param hideDisabledHeaders If true, filters out headers marked as disabled for this example via
|
|
82
|
+
* `x-scalar-disable-parameters.default-headers`.
|
|
83
|
+
* @param hideOverriddenHeaders If true, omits any default header whose name matches an **enabled**
|
|
84
|
+
* operation parameter with `in: header` (disabled optional header parameters do not shadow defaults).
|
|
24
85
|
*/
|
|
25
|
-
export const getDefaultHeaders = ({ method, operation, exampleName, hideDisabledHeaders = false, options = {
|
|
86
|
+
export const getDefaultHeaders = ({ method, operation, exampleName, hideDisabledHeaders = false, hideOverriddenHeaders = false, options = {
|
|
26
87
|
isElectron: false,
|
|
27
88
|
appVersion: '0.0.0',
|
|
28
89
|
}, }) => {
|
|
29
|
-
const disabledHeaders = operation['x-scalar-disable-parameters']?.['default-headers']?.[exampleName] ?? {};
|
|
30
90
|
const headers = new Headers();
|
|
31
91
|
const requestBody = getResolvedRef(operation.requestBody);
|
|
32
92
|
// Add Content-Type header only for methods that support a request body
|
|
33
93
|
if (canMethodHaveBody(method) && requestBody) {
|
|
34
94
|
const contentType = requestBody['x-scalar-selected-content-type']?.[exampleName] ?? Object.keys(requestBody.content ?? {})[0];
|
|
35
95
|
// We never want to add a content type of 'none' or invent one when the schema defines no body.
|
|
36
|
-
|
|
96
|
+
// 'other' is a UI-only choice for a raw body without an auto-added Content-Type header.
|
|
97
|
+
if (contentType && contentType !== 'none' && contentType !== 'other') {
|
|
37
98
|
headers.set('Content-Type', contentType);
|
|
38
99
|
}
|
|
39
100
|
}
|
|
@@ -46,9 +107,13 @@ export const getDefaultHeaders = ({ method, operation, exampleName, hideDisabled
|
|
|
46
107
|
if (options.isElectron && options.appVersion) {
|
|
47
108
|
headers.set('User-Agent', `Scalar/${options.appVersion}`);
|
|
48
109
|
}
|
|
49
|
-
|
|
50
|
-
if (hideDisabledHeaders) {
|
|
51
|
-
return
|
|
110
|
+
const result = Object.fromEntries(headers.entries());
|
|
111
|
+
if (hideOverriddenHeaders || hideDisabledHeaders) {
|
|
112
|
+
// return a new object with the filtered headers
|
|
113
|
+
return filterDefaultHeadersByVisibility(operation, exampleName, result, {
|
|
114
|
+
hideOverriddenHeaders,
|
|
115
|
+
hideDisabledHeaders,
|
|
116
|
+
});
|
|
52
117
|
}
|
|
53
|
-
return
|
|
118
|
+
return result;
|
|
54
119
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { getActiveEnvironment } from './environment.js';
|
|
2
2
|
export { type BuildRequestExampleContext, getRequestExampleContext } from './get-request-example-context.js';
|
|
3
|
+
export { filterDisabledDefaultHeaders, getDefaultHeaders, restoreConventionalDefaultHeaderNames, restoreConventionalHeaderName, } from './headers.js';
|
|
3
4
|
export { combineParams } from './helpers/combine-params.js';
|
|
4
5
|
export { getActiveProxyUrl } from './proxy.js';
|
|
5
6
|
export { getSecurityRequirements } from './security/get-security-requirements.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/request-example/context/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,EAAE,KAAK,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AACzG,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,YAAY,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/request-example/context/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,EAAE,KAAK,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AACzG,OAAO,EACL,4BAA4B,EAC5B,iBAAiB,EACjB,qCAAqC,EACrC,6BAA6B,GAC9B,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,YAAY,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { getActiveEnvironment } from './environment.js';
|
|
2
2
|
export { getRequestExampleContext } from './get-request-example-context.js';
|
|
3
|
+
export { filterDisabledDefaultHeaders, getDefaultHeaders, restoreConventionalDefaultHeaderNames, restoreConventionalHeaderName, } from './headers.js';
|
|
3
4
|
export { combineParams } from './helpers/combine-params.js';
|
|
4
5
|
export { getActiveProxyUrl } from './proxy.js';
|
|
5
6
|
export { getSecurityRequirements } from './security/get-security-requirements.js';
|