@scalar/workspace-store 0.64.0 → 0.66.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 +121 -0
- package/README.md +45 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +109 -10
- package/dist/entities/auth/schema.d.ts +351 -20
- package/dist/entities/auth/schema.d.ts.map +1 -1
- package/dist/entities/auth/schema.js +3 -1
- package/dist/events/definitions/auth.d.ts +1 -2
- package/dist/events/definitions/auth.d.ts.map +1 -1
- package/dist/events/definitions/operation.d.ts +3 -4
- package/dist/events/definitions/operation.d.ts.map +1 -1
- package/dist/events/definitions/server.d.ts +1 -2
- package/dist/events/definitions/server.d.ts.map +1 -1
- package/dist/events/definitions/ui.d.ts +3 -4
- package/dist/events/definitions/ui.d.ts.map +1 -1
- package/dist/events/old-definitions.d.ts +1 -2
- package/dist/events/old-definitions.d.ts.map +1 -1
- package/dist/helpers/chunk-index.d.ts +20 -2
- package/dist/helpers/chunk-index.d.ts.map +1 -1
- package/dist/helpers/chunk-index.js +14 -1
- package/dist/helpers/external-examples.d.ts +2 -0
- package/dist/helpers/external-examples.d.ts.map +1 -1
- package/dist/helpers/external-examples.js +1 -0
- package/dist/helpers/for-each-path-item-operation.d.ts +6 -5
- package/dist/helpers/for-each-path-item-operation.d.ts.map +1 -1
- package/dist/helpers/for-each-path-item-operation.js +40 -14
- package/dist/helpers/get-example-value.d.ts +15 -0
- package/dist/helpers/get-example-value.d.ts.map +1 -0
- package/dist/helpers/get-example-value.js +28 -0
- package/dist/helpers/get-parameter-example.d.ts +14 -0
- package/dist/helpers/get-parameter-example.d.ts.map +1 -0
- package/dist/helpers/get-parameter-example.js +19 -0
- package/dist/helpers/get-resolved-ref.d.ts.map +1 -1
- package/dist/helpers/get-resolved-ref.js +12 -1
- package/dist/helpers/normalize-boolean-schemas.d.ts +10 -0
- package/dist/helpers/normalize-boolean-schemas.d.ts.map +1 -0
- package/dist/helpers/normalize-boolean-schemas.js +193 -0
- package/dist/helpers/operation-examples.d.ts.map +1 -1
- package/dist/helpers/operation-examples.js +5 -2
- package/dist/helpers/querystring-parameter.d.ts +21 -0
- package/dist/helpers/querystring-parameter.d.ts.map +1 -0
- package/dist/helpers/querystring-parameter.js +108 -0
- package/dist/helpers/serialize-stream-example.d.ts +8 -0
- package/dist/helpers/serialize-stream-example.d.ts.map +1 -0
- package/dist/helpers/serialize-stream-example.js +52 -0
- package/dist/helpers/use-external-examples.d.ts.map +1 -1
- package/dist/helpers/use-external-examples.js +8 -1
- package/dist/mutators/index.d.ts +3 -3
- package/dist/mutators/operation/body.d.ts.map +1 -1
- package/dist/mutators/operation/body.js +9 -2
- package/dist/mutators/operation/operation.d.ts.map +1 -1
- package/dist/mutators/operation/operation.js +4 -7
- package/dist/mutators/operation/parameters.d.ts.map +1 -1
- package/dist/mutators/operation/parameters.js +43 -3
- package/dist/navigation/get-navigation-options.d.ts.map +1 -1
- package/dist/navigation/get-navigation-options.js +19 -4
- package/dist/navigation/helpers/traverse-paths.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-paths.js +2 -2
- package/dist/navigation/helpers/traverse-webhooks.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-webhooks.js +2 -2
- package/dist/navigation/helpers/update-order-ids.d.ts +1 -2
- package/dist/navigation/helpers/update-order-ids.d.ts.map +1 -1
- package/dist/plugins/bundler/index.d.ts +1 -0
- package/dist/plugins/bundler/index.d.ts.map +1 -1
- package/dist/plugins/bundler/index.js +11 -3
- package/dist/plugins/bundler/openapi-document.d.ts +6 -0
- package/dist/plugins/bundler/openapi-document.d.ts.map +1 -0
- package/dist/plugins/bundler/openapi-document.js +57 -0
- package/dist/request-example/builder/body/build-multipart.d.ts +29 -0
- package/dist/request-example/builder/body/build-multipart.d.ts.map +1 -0
- package/dist/request-example/builder/body/build-multipart.js +191 -0
- package/dist/request-example/builder/body/build-request-body.d.ts +6 -1
- package/dist/request-example/builder/body/build-request-body.d.ts.map +1 -1
- package/dist/request-example/builder/body/build-request-body.js +80 -23
- package/dist/request-example/builder/body/encode-multipart-body.d.ts +8 -8
- package/dist/request-example/builder/body/encode-multipart-body.d.ts.map +1 -1
- package/dist/request-example/builder/body/encode-multipart-body.js +56 -18
- package/dist/request-example/builder/body/get-request-body-example.d.ts.map +1 -1
- package/dist/request-example/builder/body/get-request-body-example.js +20 -6
- package/dist/request-example/builder/body/multipart-limits.d.ts +3 -0
- package/dist/request-example/builder/body/multipart-limits.d.ts.map +1 -0
- package/dist/request-example/builder/body/multipart-limits.js +2 -0
- package/dist/request-example/builder/body/serialize-form-property.d.ts +2 -0
- package/dist/request-example/builder/body/serialize-form-property.d.ts.map +1 -1
- package/dist/request-example/builder/body/serialize-form-property.js +3 -2
- package/dist/request-example/builder/body/serialize-multipart-array.d.ts +1 -1
- package/dist/request-example/builder/build-request.d.ts.map +1 -1
- package/dist/request-example/builder/build-request.js +7 -1
- package/dist/request-example/builder/header/build-request-parameters.d.ts +2 -0
- package/dist/request-example/builder/header/build-request-parameters.d.ts.map +1 -1
- package/dist/request-example/builder/header/build-request-parameters.js +54 -11
- package/dist/request-example/builder/header/is-param-disabled.d.ts.map +1 -1
- package/dist/request-example/builder/header/is-param-disabled.js +3 -1
- package/dist/request-example/builder/header/serialize-parameter.d.ts +11 -0
- package/dist/request-example/builder/header/serialize-parameter.d.ts.map +1 -1
- package/dist/request-example/builder/header/serialize-parameter.js +22 -0
- package/dist/request-example/builder/helpers/get-example-from-schema.d.ts.map +1 -1
- package/dist/request-example/builder/helpers/get-example-from-schema.js +42 -3
- package/dist/request-example/builder/helpers/get-example.d.ts.map +1 -1
- package/dist/request-example/builder/helpers/get-example.js +5 -2
- package/dist/request-example/builder/index.d.ts +2 -2
- package/dist/request-example/builder/index.d.ts.map +1 -1
- package/dist/request-example/builder/index.js +1 -1
- package/dist/request-example/builder/request-factory.d.ts +7 -0
- package/dist/request-example/builder/request-factory.d.ts.map +1 -1
- package/dist/request-example/builder/request-factory.js +10 -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 +18 -2
- package/dist/request-example/builder/security/secret-types.d.ts +4 -1
- package/dist/request-example/builder/security/secret-types.d.ts.map +1 -1
- package/dist/request-example/context/headers.d.ts +1 -2
- package/dist/request-example/context/headers.d.ts.map +1 -1
- package/dist/request-example/context/security/extract-security-scheme-secrets.d.ts.map +1 -1
- package/dist/request-example/context/security/extract-security-scheme-secrets.js +15 -0
- package/dist/request-example/index.d.ts +5 -2
- package/dist/request-example/index.d.ts.map +1 -1
- package/dist/request-example/index.js +4 -1
- package/dist/request-example/types.d.ts +1 -2
- package/dist/request-example/types.d.ts.map +1 -1
- package/dist/request-example/xml/serialize-xml-part.d.ts +9 -0
- package/dist/request-example/xml/serialize-xml-part.d.ts.map +1 -0
- package/dist/request-example/xml/serialize-xml-part.js +12 -0
- package/dist/schemas/extensions/operation/x-code-samples.d.ts +22 -0
- package/dist/schemas/extensions/operation/x-code-samples.d.ts.map +1 -1
- package/dist/schemas/extensions/operation/x-code-samples.js +4 -0
- package/dist/schemas/extensions.d.ts +9 -0
- package/dist/schemas/extensions.d.ts.map +1 -1
- package/dist/schemas/extensions.js +9 -0
- package/dist/schemas/navigation.d.ts +40 -34
- package/dist/schemas/navigation.d.ts.map +1 -1
- package/dist/schemas/navigation.js +2 -3
- package/dist/schemas/reference-config/index.d.ts +24 -4
- package/dist/schemas/reference-config/index.d.ts.map +1 -1
- package/dist/schemas/reference-config/settings.d.ts +24 -4
- package/dist/schemas/reference-config/settings.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/oauthflows.d.ts +26 -0
- package/dist/schemas/v3.1/strict/oauthflows.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/oauthflows.js +3 -0
- package/dist/schemas/v3.1/strict/openapi-document.d.ts +1582 -147
- package/dist/schemas/v3.1/strict/openapi-document.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/operation.d.ts +8 -0
- package/dist/schemas/v3.1/strict/operation.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/path-item.d.ts +19 -0
- package/dist/schemas/v3.1/strict/path-item.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/path-item.js +5 -0
- package/dist/schemas/v3.2/openapi/index.d.ts +5 -0
- package/dist/schemas/v3.2/openapi/index.d.ts.map +1 -1
- package/dist/schemas/v3.2/openapi/index.js +48 -12
- package/dist/schemas/v3.2/openapi/reference.d.ts.map +1 -1
- package/dist/schemas/v3.2/openapi/reference.js +11 -3
- package/dist/schemas/v3.2/strict/openapi-document.d.ts +842 -140
- package/dist/schemas/v3.2/strict/openapi-document.d.ts.map +1 -1
- package/dist/schemas/v3.2/strict/openapi-document.js +6 -14
- package/dist/schemas/v3.2/strict/operation.d.ts +8 -0
- package/dist/schemas/v3.2/strict/operation.d.ts.map +1 -1
- package/dist/schemas/v3.2/strict/parameter.d.ts +14 -0
- package/dist/schemas/v3.2/strict/parameter.d.ts.map +1 -1
- package/dist/schemas/v3.2/strict/parameter.js +2 -0
- package/dist/server.d.ts +10 -6
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +67 -45
- package/package.json +19 -9
- package/dist/schemas/v3.1/openapi/index.d.ts +0 -149
- package/dist/schemas/v3.1/openapi/index.d.ts.map +0 -1
- package/dist/schemas/v3.1/openapi/index.js +0 -732
- package/dist/schemas/v3.1/openapi/reference.d.ts +0 -4
- package/dist/schemas/v3.1/openapi/reference.d.ts.map +0 -1
- package/dist/schemas/v3.1/openapi/reference.js +0 -29
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { getPathItemOperation } from '../../helpers/for-each-path-item-operation.js';
|
|
2
|
+
import { getParameterExample } from '../../helpers/get-parameter-example.js';
|
|
2
3
|
import { getResolvedRef } from '../../helpers/get-resolved-ref.js';
|
|
4
|
+
import { getQuerystringParameter, serializeQuerystringParameter } from '../../helpers/querystring-parameter.js';
|
|
3
5
|
import { unpackProxyObject } from '../../helpers/unpack-proxy.js';
|
|
4
6
|
import { isOpenApiDocument } from '../../schemas/type-guards.js';
|
|
5
7
|
import { isContentTypeParameterObject } from '../../schemas/v3.2/strict/type-guards.js';
|
|
@@ -41,8 +43,13 @@ const getPathItemsForParameterMutation = (pathItemRef) => {
|
|
|
41
43
|
export const upsertOperationParameter = (document, { meta, type, payload, originalParameter }) => {
|
|
42
44
|
// We are editing an existing parameter
|
|
43
45
|
if (originalParameter) {
|
|
46
|
+
const querystring = getQuerystringParameter(originalParameter, meta.exampleKey, { includeDisabled: true });
|
|
47
|
+
const preserveQuerystringValue = querystring && payload.value === serializeQuerystringParameter(querystring);
|
|
44
48
|
const param = originalParameter;
|
|
45
|
-
const
|
|
49
|
+
const selected = getParameterExample(param, meta.exampleKey);
|
|
50
|
+
const target = param.in !== 'querystring' && !selected.serialized && isContentTypeParameterObject(param)
|
|
51
|
+
? Object.values(param.content ?? {})[0]
|
|
52
|
+
: param;
|
|
46
53
|
if (!target) {
|
|
47
54
|
return;
|
|
48
55
|
}
|
|
@@ -77,7 +84,39 @@ export const upsertOperationParameter = (document, { meta, type, payload, origin
|
|
|
77
84
|
return;
|
|
78
85
|
}
|
|
79
86
|
// Update the example value and disabled state
|
|
80
|
-
|
|
87
|
+
if (param.in === 'querystring') {
|
|
88
|
+
// The whole-query editor displays the URI-ready value, including percent encoding.
|
|
89
|
+
delete example.value;
|
|
90
|
+
delete example.dataValue;
|
|
91
|
+
// Inline edits replace the external example source as well as its cached representation.
|
|
92
|
+
delete example.externalValue;
|
|
93
|
+
delete example.serializedValue;
|
|
94
|
+
// Toggling an unchanged preview must preserve data and environment placeholders
|
|
95
|
+
// so future environment changes still happen before serialization.
|
|
96
|
+
if (preserveQuerystringValue && querystring.kind !== 'uri-ready') {
|
|
97
|
+
if (querystring.kind === 'serialized') {
|
|
98
|
+
example.value = querystring.value;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
example.dataValue = querystring.value;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
example.serializedValue = String(payload.value);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
delete example.dataValue;
|
|
110
|
+
delete example.serializedValue;
|
|
111
|
+
delete example.externalValue;
|
|
112
|
+
if (selected.serialized || selected.mediaSerialized) {
|
|
113
|
+
delete example.value;
|
|
114
|
+
example.serializedValue = String(payload.value);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
example.value = payload.value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
81
120
|
example['x-disabled'] = payload.isDisabled;
|
|
82
121
|
return;
|
|
83
122
|
}
|
|
@@ -212,5 +251,6 @@ export const deleteAllOperationParameters = (document, { meta, type }) => {
|
|
|
212
251
|
return;
|
|
213
252
|
}
|
|
214
253
|
// Filter out parameters of the specified type
|
|
215
|
-
operation.parameters =
|
|
254
|
+
operation.parameters =
|
|
255
|
+
operation.parameters?.filter((it) => getResolvedRef(it)?.in !== type && !(type === 'query' && getResolvedRef(it)?.in === 'querystring')) ?? [];
|
|
216
256
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-navigation-options.d.ts","sourceRoot":"","sources":["../../src/navigation/get-navigation-options.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"get-navigation-options.d.ts","sourceRoot":"","sources":["../../src/navigation/get-navigation-options.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,4BAA4B,EAAgC,MAAM,6BAA6B,CAAA;AAE7G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAe7D,MAAM,MAAM,iBAAiB,GACzB,OAAO,CACL,IAAI,CACF,4BAA4B,EAC1B,qBAAqB,GACrB,iBAAiB,GACjB,uBAAuB,GACvB,qBAAqB,GACrB,mBAAmB,GACnB,kBAAkB,GAClB,YAAY,GACZ,YAAY,GACZ,oBAAoB,GACpB,sBAAsB,CACzB,CACF,GACD,SAAS,CAAA;AAEb;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,cAAc,MAAM,EAAE,UAAU,iBAAiB,KAAG,mBAyJxF,CAAA"}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
import { isHttpMethod } from '@scalar/helpers/http/is-http-method';
|
|
1
2
|
import { slugify } from '@scalar/helpers/string/slugify';
|
|
2
3
|
import { DEFAULT_MODELS_SECTION_LABEL } from '@scalar/types/api-reference';
|
|
4
|
+
/**
|
|
5
|
+
* Fixed fields retain their existing links; authored variants need a distinct namespace.
|
|
6
|
+
* Extension methods retain exact case because HTTP method tokens are case-sensitive.
|
|
7
|
+
* Normalizing COPY and copy would collapse distinct operations onto the same anchor.
|
|
8
|
+
*/
|
|
9
|
+
const getMethodId = (method) => isHttpMethod(method)
|
|
10
|
+
? method === method.toLowerCase()
|
|
11
|
+
? method.toUpperCase()
|
|
12
|
+
: `additionalOperations/${method}`
|
|
13
|
+
: method;
|
|
3
14
|
/**
|
|
4
15
|
* Returns options for traversing an OpenAPI document, allowing customization of
|
|
5
16
|
* how IDs and slugs are generated for tags, headings, models, operations, and webhooks.
|
|
@@ -65,11 +76,13 @@ export const getNavigationOptions = (documentName, options) => {
|
|
|
65
76
|
return `${prefixTag}${options.generateOperationSlug({
|
|
66
77
|
path: props.path,
|
|
67
78
|
operationId: props.operation.operationId,
|
|
68
|
-
method: props.method.
|
|
79
|
+
method: isHttpMethod(props.method) && props.method === props.method.toLowerCase()
|
|
80
|
+
? props.method.toUpperCase()
|
|
81
|
+
: props.method,
|
|
69
82
|
summary: props.operation.summary,
|
|
70
83
|
})}`;
|
|
71
84
|
}
|
|
72
|
-
return `${prefixTag}${props.method
|
|
85
|
+
return `${prefixTag}${getMethodId(props.method)}${props.path}`;
|
|
73
86
|
}
|
|
74
87
|
// -------- Default webhook id generation logic --------
|
|
75
88
|
if (props.type === 'webhook') {
|
|
@@ -83,13 +96,15 @@ export const getNavigationOptions = (documentName, options) => {
|
|
|
83
96
|
if (options?.generateWebhookSlug) {
|
|
84
97
|
return `${prefixTag}webhook/${options.generateWebhookSlug({
|
|
85
98
|
name: props.name,
|
|
86
|
-
method: props.method
|
|
99
|
+
method: isHttpMethod(props.method) && props.method === props.method.toLowerCase()
|
|
100
|
+
? props.method.toUpperCase()
|
|
101
|
+
: props.method,
|
|
87
102
|
})}`;
|
|
88
103
|
}
|
|
89
104
|
// Webhook events are commonly named with dots (e.g. "account_holder.created").
|
|
90
105
|
// Keep the dot so the deep link stays close to the event name, instead of
|
|
91
106
|
// dropping it and joining adjacent words ("account-holdercreated").
|
|
92
|
-
return `${prefixTag}webhook/${props.method
|
|
107
|
+
return `${prefixTag}webhook/${getMethodId(props.method)}/${slugify(props.name, { allowedSpecialChars: '.' })}`;
|
|
93
108
|
}
|
|
94
109
|
// -------- Default model id generation logic --------
|
|
95
110
|
if (props.type === 'model') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traverse-paths.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/traverse-paths.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"traverse-paths.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/traverse-paths.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAE5F,OAAO,KAAK,EAA+B,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AAI9F,eAAO,MAAM,qBAAqB,GAAI,WAAW,eAAe,YAE/D,CAAA;AAsED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,aAAa,GAAI,sEAM3B;IACD,QAAQ,EAAE,eAAe,CAAA;IACzB,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAA;IAChB,0DAA0D;IAC1D,UAAU,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAA;IAC7C,kBAAkB;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,oFAAoF;IACpF,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;CAC5C,KAAG;IAAE,kBAAkB,EAAE,kBAAkB,EAAE,CAAA;CA0D7C,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { escapeJsonPointer } from '@scalar/json-magic/helpers/escape-json-pointer';
|
|
2
|
-
import { forEachPathItemOperation } from '../../helpers/for-each-path-item-operation.js';
|
|
2
|
+
import { forEachPathItemOperation, getPathItemOperationKey } from '../../helpers/for-each-path-item-operation.js';
|
|
3
3
|
import { getResolvedRef, mergeSiblingReferences } from '../../helpers/get-resolved-ref.js';
|
|
4
4
|
import { isHidden } from '../../helpers/is-hidden.js';
|
|
5
5
|
import { traverseOperationExamples } from '../../navigation/helpers/traverse-examples.js';
|
|
@@ -83,7 +83,7 @@ export const traversePaths = ({ document, tagsMap, generateId, documentId, opera
|
|
|
83
83
|
if (isHidden(operation)) {
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
|
-
const ref = `#/paths/${escapeJsonPointer(path)}/${method}`;
|
|
86
|
+
const ref = `#/paths/${escapeJsonPointer(path)}/${getPathItemOperationKey(method)}`;
|
|
87
87
|
// Traverse tags
|
|
88
88
|
if (operation.tags?.length) {
|
|
89
89
|
operation.tags.forEach((tagName) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traverse-webhooks.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/traverse-webhooks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"traverse-webhooks.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/traverse-webhooks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACtE,OAAO,KAAK,EAAa,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvE,OAAO,KAAK,EAAE,eAAe,EAA8B,MAAM,wCAAwC,CAAA;AA2DzG;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,GAAI,0EAM9B;IACD,uBAAuB;IACvB,QAAQ,EAAE,eAAe,CAAA;IACzB,6CAA6C;IAC7C,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAA;IAC7C,wBAAwB,EAAE,MAAM,CAAA;IAChC,UAAU,EAAE,MAAM,CAAA;CACnB,KAAG,gBAAgB,EAuDnB,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { forEachPathItemOperation } from '../../helpers/for-each-path-item-operation.js';
|
|
1
|
+
import { forEachPathItemOperation, getPathItemOperationKey } from '../../helpers/for-each-path-item-operation.js';
|
|
2
2
|
import { getResolvedRef, mergeSiblingReferences } from '../../helpers/get-resolved-ref.js';
|
|
3
3
|
import { isHidden } from '../../helpers/is-hidden.js';
|
|
4
4
|
import { isDeprecatedOperation } from '../../navigation/helpers/traverse-paths.js';
|
|
@@ -62,7 +62,7 @@ export const traverseWebhooks = ({ document, tagsMap, generateId, untaggedWebhoo
|
|
|
62
62
|
if (isHidden(operation)) {
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
|
-
const ref = `#/webhooks/${name}/${method}`;
|
|
65
|
+
const ref = `#/webhooks/${name}/${getPathItemOperationKey(method)}`;
|
|
66
66
|
if (operation.tags?.length) {
|
|
67
67
|
operation.tags.forEach((tagName) => {
|
|
68
68
|
const { tag, id: tagId } = getTag({ tagsMap, name: tagName, documentId, generateId });
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { HttpMethod } from '@scalar/helpers/http/http-methods';
|
|
2
1
|
import type { WorkspaceStore } from '../../client.js';
|
|
3
2
|
import type { IdGenerator, TraversedOperation, TraversedTag, TraversedWebhook, WithParent } from '../../schemas/navigation.js';
|
|
4
3
|
import type { TagObject } from '../../schemas/v3.2/strict/openapi-document.js';
|
|
@@ -10,7 +9,7 @@ type UpdateOrderIdParams = {
|
|
|
10
9
|
/** Operation or webhook entries to update the order ID for */
|
|
11
10
|
entries: (WithParent<TraversedOperation> | WithParent<TraversedWebhook>)[];
|
|
12
11
|
operation: OperationObject;
|
|
13
|
-
method:
|
|
12
|
+
method: string;
|
|
14
13
|
path: string;
|
|
15
14
|
} | {
|
|
16
15
|
/** Tag entries to update the order ID for */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-order-ids.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/update-order-ids.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"update-order-ids.d.ts","sourceRoot":"","sources":["../../../src/navigation/helpers/update-order-ids.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAG9C,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAEvH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAA;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAEtE,KAAK,mBAAmB,GAAG;IACzB,KAAK,EAAE,cAAc,CAAA;IACrB,UAAU,EAAE,WAAW,CAAA;CACxB,GAAG,CACA;IACE,8DAA8D;IAC9D,OAAO,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAA;IAC1E,SAAS,EAAE,eAAe,CAAA;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACb,GACD;IACE,6CAA6C;IAC7C,OAAO,EAAE,UAAU,CAAC,YAAY,CAAC,EAAE,CAAA;IACnC,GAAG,EAAE,SAAS,CAAA;CACf,CACJ,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,gCAAgC,mBAAmB,SAiEjF,CAAA"}
|
|
@@ -117,4 +117,5 @@ export declare const syncPathParameters: () => LifecyclePlugin;
|
|
|
117
117
|
* These keys are used for internal purposes and are not needed in the final bundled document.
|
|
118
118
|
*/
|
|
119
119
|
export declare const removeExtraScalarKeys: () => LifecyclePlugin;
|
|
120
|
+
export { openApiDocument, resolveOpenApiDocument } from './openapi-document.js';
|
|
120
121
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -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;;;;;;;;;;;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,
|
|
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,eA6BtC,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,eAmFrC,CAAA;AAKD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAO,eAaxC,CAAA;AAED,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA"}
|
|
@@ -149,9 +149,15 @@ export const refsEverywhere = () => {
|
|
|
149
149
|
export const restoreOriginalRefs = () => {
|
|
150
150
|
return {
|
|
151
151
|
type: 'lifecycle',
|
|
152
|
-
|
|
152
|
+
onAfterNodeProcess: (node, context) => {
|
|
153
153
|
const ref = node['$ref'];
|
|
154
154
|
const root = context.rootNode;
|
|
155
|
+
const authoredRefs = root['x-scalar-original-refs'];
|
|
156
|
+
const authored = isObject(authoredRefs) ? authoredRefs[JSON.stringify(context.path)] : undefined;
|
|
157
|
+
if (isObject(authored) && typeof authored.original === 'string' && authored.rewritten === ref) {
|
|
158
|
+
node['$ref'] = authored.original;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
155
161
|
const extUrls = root['x-ext-urls'];
|
|
156
162
|
// Only process if $ref is a string and x-ext-urls is a valid object
|
|
157
163
|
if (typeof ref !== 'string' || typeof extUrls !== 'object' || extUrls === null || !isLocalRef(ref)) {
|
|
@@ -267,8 +273,9 @@ export const syncPathParameters = () => {
|
|
|
267
273
|
}
|
|
268
274
|
const pathString = path[1];
|
|
269
275
|
// Sync parameters for each operation method
|
|
270
|
-
|
|
271
|
-
|
|
276
|
+
const additionalOperations = isObject(node.additionalOperations) ? Object.values(node.additionalOperations) : [];
|
|
277
|
+
for (const operationNode of [...HTTP_METHODS.map((method) => node[method]), ...additionalOperations]) {
|
|
278
|
+
const operation = getResolvedRef(operationNode, context);
|
|
272
279
|
if (!isObject(operation)) {
|
|
273
280
|
continue;
|
|
274
281
|
}
|
|
@@ -334,3 +341,4 @@ export const removeExtraScalarKeys = () => {
|
|
|
334
341
|
},
|
|
335
342
|
};
|
|
336
343
|
};
|
|
344
|
+
export { openApiDocument, resolveOpenApiDocument } from './openapi-document.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type DocumentResolver, type LifecyclePlugin } from '@scalar/json-magic/bundle';
|
|
2
|
+
/** Resolves an OpenAPI document's declared identity against its retrieval location. */
|
|
3
|
+
export declare const resolveOpenApiDocument: DocumentResolver;
|
|
4
|
+
/** Honors `$self` for complete OpenAPI documents, including external and cached documents. */
|
|
5
|
+
export declare const openApiDocument: () => LifecyclePlugin;
|
|
6
|
+
//# sourceMappingURL=openapi-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi-document.d.ts","sourceRoot":"","sources":["../../../src/plugins/bundler/openapi-document.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAwB,MAAM,2BAA2B,CAAA;AAE7G,uFAAuF;AACvF,eAAO,MAAM,sBAAsB,EAAE,gBAcpC,CAAA;AAED,8FAA8F;AAC9F,eAAO,MAAM,eAAe,QAAO,eAsClC,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isObject } from '@scalar/helpers/object/is-object';
|
|
2
|
+
import { resolveReferencePath } from '@scalar/json-magic/bundle';
|
|
3
|
+
/** Resolves an OpenAPI document's declared identity against its retrieval location. */
|
|
4
|
+
export const resolveOpenApiDocument = (document, retrievalUri) => {
|
|
5
|
+
if (!isObject(document) ||
|
|
6
|
+
typeof document.openapi !== 'string' ||
|
|
7
|
+
!/^3\.2\.\d+$/.test(document.openapi) ||
|
|
8
|
+
typeof document.$self !== 'string') {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
const self = resolveReferencePath(retrievalUri, document.$self);
|
|
12
|
+
// RFC 3986 requires a fragment-free base, while the declared identity can retain its fragment.
|
|
13
|
+
const fragmentIndex = self.indexOf('#');
|
|
14
|
+
const baseUri = fragmentIndex === -1 ? self : self.slice(0, fragmentIndex);
|
|
15
|
+
return { baseUri, metadata: { openapi: document.openapi, $self: self } };
|
|
16
|
+
};
|
|
17
|
+
/** Honors `$self` for complete OpenAPI documents, including external and cached documents. */
|
|
18
|
+
export const openApiDocument = () => {
|
|
19
|
+
const authoredRefs = new WeakMap();
|
|
20
|
+
const paths = new WeakMap();
|
|
21
|
+
const indexPaths = (value, path) => {
|
|
22
|
+
if (value === null || typeof value !== 'object' || paths.has(value))
|
|
23
|
+
return;
|
|
24
|
+
paths.set(value, path);
|
|
25
|
+
for (const [key, child] of Object.entries(value)) {
|
|
26
|
+
indexPaths(child, [...path, key]);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
type: 'lifecycle',
|
|
31
|
+
resolveDocument: resolveOpenApiDocument,
|
|
32
|
+
onBeforeNodeProcess: (node, context) => {
|
|
33
|
+
if (typeof node.$ref === 'string' && resolveOpenApiDocument(context.rootNode, context.origin)) {
|
|
34
|
+
// Partial bundles report paths relative to the selected subtree. Index the supplied root
|
|
35
|
+
// so the saved references can also be restored when exporting the entire document.
|
|
36
|
+
indexPaths(context.rootNode, []);
|
|
37
|
+
authoredRefs.set(node, node.$ref);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
onAfterNodeProcess: (node, context) => {
|
|
41
|
+
const authored = authoredRefs.get(node);
|
|
42
|
+
if (authored === undefined || authored === node.$ref) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// A path-based map survives serialization and partial bundles without changing Reference Objects.
|
|
46
|
+
// Keep the first spelling, including fragments and ./, when a later pass rewrites it again.
|
|
47
|
+
const root = context.rootNode;
|
|
48
|
+
const existing = root['x-scalar-original-refs'];
|
|
49
|
+
const mapping = isObject(existing) ? existing : {};
|
|
50
|
+
const key = JSON.stringify(paths.get(node) ?? context.path);
|
|
51
|
+
const previous = mapping[key];
|
|
52
|
+
const original = isObject(previous) && previous.rewritten === authored ? previous.original : authored;
|
|
53
|
+
mapping[key] = { original, rewritten: node.$ref };
|
|
54
|
+
root['x-scalar-original-refs'] = mapping;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { MediaTypeObject, SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document';
|
|
2
|
+
/** Multipart parts stay structured until sending so nested text can resolve environment variables. */
|
|
3
|
+
export type MultipartPart = {
|
|
4
|
+
key?: string;
|
|
5
|
+
contentType?: string;
|
|
6
|
+
headers?: Record<string, string>;
|
|
7
|
+
} & ({
|
|
8
|
+
type: 'text';
|
|
9
|
+
value: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'file';
|
|
12
|
+
value: File;
|
|
13
|
+
} | {
|
|
14
|
+
type: 'blob';
|
|
15
|
+
value: Blob;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'multipart';
|
|
18
|
+
value: MultipartPart[];
|
|
19
|
+
contentType: string;
|
|
20
|
+
});
|
|
21
|
+
/** Identify ordered multipart independently of the editor's row representation. */
|
|
22
|
+
export declare const isPositionalMultipart: (contentType: string, media: MediaTypeObject) => boolean;
|
|
23
|
+
/** Whether a media type needs ordered or nested multipart serialization. */
|
|
24
|
+
export declare const needsMultipartEncoding: (contentType: string, media: MediaTypeObject) => boolean;
|
|
25
|
+
/** Resolve a positional item's schema independently of the encoding prefix length. */
|
|
26
|
+
export declare const getMultipartItemSchema: (schema: SchemaObject | undefined, index: number, itemSchema?: MediaTypeObject["itemSchema"]) => SchemaObject | undefined;
|
|
27
|
+
/** Build ordered parts, applying prefix encodings independently of schema prefix lengths. */
|
|
28
|
+
export declare const buildMultipart: (value: unknown, contentType: string, encoding?: Pick<MediaTypeObject, "encoding" | "prefixEncoding" | "itemEncoding" | "itemSchema">, schema?: SchemaObject, nesting?: number) => MultipartPart[];
|
|
29
|
+
//# sourceMappingURL=build-multipart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-multipart.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/body/build-multipart.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAQrE,sGAAsG;AACtG,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC,GAAG,CACA;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CACrE,CAAA;AAED,mFAAmF;AACnF,eAAO,MAAM,qBAAqB,GAAI,aAAa,MAAM,EAAE,OAAO,eAAe,KAAG,OASnF,CAAA;AAED,4EAA4E;AAC5E,eAAO,MAAM,sBAAsB,GAAI,aAAa,MAAM,EAAE,OAAO,eAAe,KAAG,OASpF,CAAA;AA4CD,sFAAsF;AACtF,eAAO,MAAM,sBAAsB,GACjC,QAAQ,YAAY,GAAG,SAAS,EAChC,OAAO,MAAM,EACb,aAAa,eAAe,CAAC,YAAY,CAAC,KACzC,YAAY,GAAG,SAMa,CAAA;AAc/B,6FAA6F;AAC7F,eAAO,MAAM,cAAc,GACzB,OAAO,OAAO,EACd,aAAa,MAAM,EACnB,WAAU,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,gBAAgB,GAAG,cAAc,GAAG,YAAY,CAAM,EACnG,SAAS,YAAY,EACrB,gBAAW,KACV,aAAa,EAkIf,CAAA"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { parseMimeType } from '@scalar/helpers/http/mime-type';
|
|
2
|
+
import { isObject } from '@scalar/helpers/object/is-object';
|
|
3
|
+
import { getResolvedRef, mergeSiblingReferences } from '@scalar/workspace-store/helpers/get-resolved-ref';
|
|
4
|
+
import { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy';
|
|
5
|
+
import { isArraySchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards';
|
|
6
|
+
import { serializeXmlPart } from '../../xml/serialize-xml-part.js';
|
|
7
|
+
import { MAX_MULTIPART_NESTING } from './multipart-limits.js';
|
|
8
|
+
import { resolveLeafSchema } from './schema-value-coercion.js';
|
|
9
|
+
import { hasEncodingStyle, serializeFormPropertyWithEncoding } from './serialize-form-property.js';
|
|
10
|
+
/** Identify ordered multipart independently of the editor's row representation. */
|
|
11
|
+
export const isPositionalMultipart = (contentType, media) => {
|
|
12
|
+
const schema = getResolvedRef(media.schema);
|
|
13
|
+
return (parseMimeType(contentType).essence !== 'multipart/form-data' ||
|
|
14
|
+
media.prefixEncoding !== undefined ||
|
|
15
|
+
media.itemEncoding !== undefined ||
|
|
16
|
+
(schema !== undefined && isArraySchema(schema)) ||
|
|
17
|
+
media.itemSchema !== undefined);
|
|
18
|
+
};
|
|
19
|
+
/** Whether a media type needs ordered or nested multipart serialization. */
|
|
20
|
+
export const needsMultipartEncoding = (contentType, media) => {
|
|
21
|
+
const mime = parseMimeType(contentType);
|
|
22
|
+
return (mime.type === 'multipart' &&
|
|
23
|
+
(isPositionalMultipart(contentType, media) ||
|
|
24
|
+
Object.values(media.encoding ?? {}).some((encoding) => parseMimeType(encoding.contentType).type === 'multipart' || encoding.encoding !== undefined)));
|
|
25
|
+
};
|
|
26
|
+
const defaultContentType = (schema, value) => {
|
|
27
|
+
if (value instanceof Blob) {
|
|
28
|
+
return value.type || 'application/octet-stream';
|
|
29
|
+
}
|
|
30
|
+
// OpenAPI 3.2.1 Encoding Object defaults explicitly treat absent type as binary.
|
|
31
|
+
// With no schema at all, infer from the example so existing editor values remain usable.
|
|
32
|
+
if (schema && (!('type' in schema) || !schema.type || (schema.type === 'string' && schema.contentEncoding))) {
|
|
33
|
+
return 'application/octet-stream';
|
|
34
|
+
}
|
|
35
|
+
return typeof value === 'object' && value !== null ? 'application/json' : 'text/plain';
|
|
36
|
+
};
|
|
37
|
+
/** Encoding accepts ranges, but each wire header needs a single concrete media type. */
|
|
38
|
+
const selectContentType = (encoding, schema, value) => {
|
|
39
|
+
const fallback = defaultContentType(schema, value);
|
|
40
|
+
if (!encoding) {
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
if (/[\r\n\0]/.test(encoding)) {
|
|
44
|
+
throw new Error('Invalid multipart content type');
|
|
45
|
+
}
|
|
46
|
+
const choices = encoding.split(',').map((choice) => choice.trim());
|
|
47
|
+
const preferred = parseMimeType(fallback);
|
|
48
|
+
const match = choices.find((choice) => {
|
|
49
|
+
const mime = parseMimeType(choice);
|
|
50
|
+
return ((mime.type === '*' || mime.type === preferred.type) &&
|
|
51
|
+
(mime.subtype === '*' || mime.subtype === preferred.subtype));
|
|
52
|
+
});
|
|
53
|
+
if (match) {
|
|
54
|
+
const mime = parseMimeType(match);
|
|
55
|
+
if (!mime.essence.includes('*')) {
|
|
56
|
+
return match;
|
|
57
|
+
}
|
|
58
|
+
// Keep parameters from the range while replacing only its wildcard essence.
|
|
59
|
+
return match.replace(/^[^;]+/, preferred.essence);
|
|
60
|
+
}
|
|
61
|
+
// A nonmatching range cannot supply a concrete wire type; keep the inferred fallback.
|
|
62
|
+
return choices.find((choice) => !parseMimeType(choice).essence.includes('*')) ?? fallback;
|
|
63
|
+
};
|
|
64
|
+
/** Resolve a positional item's schema independently of the encoding prefix length. */
|
|
65
|
+
export const getMultipartItemSchema = (schema, index, itemSchema) => getResolvedRef((schema && 'prefixItems' in schema ? schema.prefixItems?.[index] : undefined) ??
|
|
66
|
+
(schema && 'items' in schema ? schema.items : undefined) ??
|
|
67
|
+
itemSchema, mergeSiblingReferences);
|
|
68
|
+
/** Serialize structured values to the selected part format; strings already containing XML stay intact. */
|
|
69
|
+
const serializePartValue = (value, contentType, schema) => {
|
|
70
|
+
const subtype = contentType ? parseMimeType(contentType).subtype : undefined;
|
|
71
|
+
if ((subtype === 'xml' || subtype?.endsWith('+xml')) && isObject(value)) {
|
|
72
|
+
return serializeXmlPart(value, schema);
|
|
73
|
+
}
|
|
74
|
+
const json = subtype === 'json' || subtype?.endsWith('+json');
|
|
75
|
+
return json || (value !== null && typeof value === 'object')
|
|
76
|
+
? JSON.stringify(unpackProxyObject(value))
|
|
77
|
+
: String(value ?? '');
|
|
78
|
+
};
|
|
79
|
+
/** Build ordered parts, applying prefix encodings independently of schema prefix lengths. */
|
|
80
|
+
export const buildMultipart = (value, contentType, encoding = {}, schema, nesting = 0) => {
|
|
81
|
+
if (nesting >= MAX_MULTIPART_NESTING) {
|
|
82
|
+
throw new Error('Maximum multipart nesting exceeded');
|
|
83
|
+
}
|
|
84
|
+
const named = parseMimeType(contentType).essence === 'multipart/form-data';
|
|
85
|
+
const positional = Array.isArray(value);
|
|
86
|
+
const entries = positional
|
|
87
|
+
? value.map((item, index) => {
|
|
88
|
+
const itemEncoding = index < (encoding.prefixEncoding?.length ?? 0) ? encoding.prefixEncoding?.[index] : encoding.itemEncoding;
|
|
89
|
+
const itemSchema = getMultipartItemSchema(schema, index, encoding.itemSchema);
|
|
90
|
+
if (named && item !== null && typeof item === 'object' && !Array.isArray(item)) {
|
|
91
|
+
// Each position describes one named part; accepting more keys would silently discard data.
|
|
92
|
+
const entries = Object.entries(item);
|
|
93
|
+
const entry = entries[0];
|
|
94
|
+
if (entries.length !== 1 || !entry) {
|
|
95
|
+
throw new Error('Named positional multipart items must contain exactly one property');
|
|
96
|
+
}
|
|
97
|
+
return [entry[0], entry[1], itemEncoding, resolveLeafSchema(itemSchema, [entry[0]])];
|
|
98
|
+
}
|
|
99
|
+
return [undefined, item, itemEncoding, itemSchema];
|
|
100
|
+
})
|
|
101
|
+
: value !== null && typeof value === 'object'
|
|
102
|
+
? Object.entries(value).flatMap(([key, item]) => {
|
|
103
|
+
const propertySchema = resolveLeafSchema(schema, [key]);
|
|
104
|
+
return (Array.isArray(item) ? item : [item]).map((part) => [
|
|
105
|
+
key,
|
|
106
|
+
part,
|
|
107
|
+
encoding.encoding?.[key],
|
|
108
|
+
Array.isArray(item)
|
|
109
|
+
? getResolvedRef(propertySchema && isArraySchema(propertySchema) ? propertySchema.items : undefined, mergeSiblingReferences)
|
|
110
|
+
: propertySchema,
|
|
111
|
+
]);
|
|
112
|
+
})
|
|
113
|
+
: [];
|
|
114
|
+
return entries.flatMap(([key, item, partEncoding, partSchema]) => {
|
|
115
|
+
const style = named && hasEncodingStyle(partEncoding);
|
|
116
|
+
const styleParts = style ? serializeFormPropertyWithEncoding(key ?? '', item, partEncoding) : null;
|
|
117
|
+
const partContentType = style ? undefined : selectContentType(partEncoding?.contentType, partSchema, item);
|
|
118
|
+
const headers = Object.fromEntries(Object.entries(partEncoding?.headers ?? {}).flatMap(([name, ref]) => {
|
|
119
|
+
if (name.toLowerCase() === 'content-type') {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
const header = getResolvedRef(ref);
|
|
123
|
+
if (!header || !('schema' in header)) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
const headerSchema = getResolvedRef(header.schema);
|
|
127
|
+
const example = header?.example ??
|
|
128
|
+
getResolvedRef(Object.values(header?.examples ?? {})[0])?.value ??
|
|
129
|
+
headerSchema?.const ??
|
|
130
|
+
headerSchema?.default;
|
|
131
|
+
return example === undefined ? [] : [[name, String(example)]];
|
|
132
|
+
}));
|
|
133
|
+
if (partSchema?.contentEncoding &&
|
|
134
|
+
!Object.keys(headers).some((name) => name.toLowerCase() === 'content-transfer-encoding')) {
|
|
135
|
+
headers['Content-Transfer-Encoding'] = partSchema.contentEncoding;
|
|
136
|
+
}
|
|
137
|
+
const metadata = {
|
|
138
|
+
...(key === undefined ? {} : { key }),
|
|
139
|
+
...(partContentType ? { contentType: partContentType } : {}),
|
|
140
|
+
...(Object.keys(headers).length ? { headers } : {}),
|
|
141
|
+
};
|
|
142
|
+
if (styleParts) {
|
|
143
|
+
return styleParts.map((part) => ({ ...metadata, type: 'text', ...part }));
|
|
144
|
+
}
|
|
145
|
+
if (partContentType &&
|
|
146
|
+
parseMimeType(partContentType).type === 'multipart' &&
|
|
147
|
+
typeof item !== 'string' &&
|
|
148
|
+
!(item instanceof Blob)) {
|
|
149
|
+
return [
|
|
150
|
+
{
|
|
151
|
+
...metadata,
|
|
152
|
+
type: 'multipart',
|
|
153
|
+
contentType: partContentType,
|
|
154
|
+
value: buildMultipart(item, partContentType, partEncoding, partSchema, nesting + 1),
|
|
155
|
+
},
|
|
156
|
+
];
|
|
157
|
+
}
|
|
158
|
+
if (partContentType &&
|
|
159
|
+
parseMimeType(partContentType).essence === 'application/x-www-form-urlencoded' &&
|
|
160
|
+
item !== null &&
|
|
161
|
+
typeof item === 'object') {
|
|
162
|
+
const params = Object.entries(item).flatMap(([name, fieldValue]) => (Array.isArray(fieldValue) ? fieldValue : [fieldValue]).flatMap((field) => {
|
|
163
|
+
const fieldEncoding = partEncoding?.encoding?.[name];
|
|
164
|
+
const styled = serializeFormPropertyWithEncoding(name, field, fieldEncoding);
|
|
165
|
+
if (styled) {
|
|
166
|
+
return styled;
|
|
167
|
+
}
|
|
168
|
+
return [
|
|
169
|
+
{
|
|
170
|
+
key: name,
|
|
171
|
+
value: serializePartValue(field, hasEncodingStyle(fieldEncoding) ? undefined : fieldEncoding?.contentType),
|
|
172
|
+
},
|
|
173
|
+
];
|
|
174
|
+
}));
|
|
175
|
+
return [
|
|
176
|
+
{
|
|
177
|
+
...metadata,
|
|
178
|
+
type: 'text',
|
|
179
|
+
value: new URLSearchParams(params.map((part) => [part.key, part.value])).toString(),
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
if (item instanceof File) {
|
|
184
|
+
return [{ ...metadata, type: 'file', value: unpackProxyObject(item) }];
|
|
185
|
+
}
|
|
186
|
+
if (item instanceof Blob) {
|
|
187
|
+
return [{ ...metadata, type: 'blob', value: unpackProxyObject(item) }];
|
|
188
|
+
}
|
|
189
|
+
return [{ ...metadata, type: 'text', value: serializePartValue(item, partContentType, partSchema) }];
|
|
190
|
+
});
|
|
191
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RequestBodyObject } from '@scalar/workspace-store/schemas/v3.2/strict/request-body';
|
|
2
|
+
import { type MultipartPart } from './build-multipart.js';
|
|
2
3
|
type FormData = {
|
|
3
4
|
mode: 'formdata';
|
|
4
5
|
value: ({
|
|
@@ -30,7 +31,11 @@ type Raw = {
|
|
|
30
31
|
value: string | File | Blob;
|
|
31
32
|
contentType?: string;
|
|
32
33
|
};
|
|
33
|
-
export type RequestBody = FormData | UrlEncoded | Raw
|
|
34
|
+
export type RequestBody = FormData | UrlEncoded | Raw | {
|
|
35
|
+
mode: 'multipart';
|
|
36
|
+
contentType: string;
|
|
37
|
+
value: MultipartPart[];
|
|
38
|
+
};
|
|
34
39
|
/**
|
|
35
40
|
* Create the fetch request body
|
|
36
41
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-request-body.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/body/build-request-body.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build-request-body.d.ts","sourceRoot":"","sources":["../../../../src/request-example/builder/body/build-request-body.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0DAA0D,CAAA;AAKjG,OAAO,EACL,KAAK,aAAa,EAKnB,MAAM,mBAAmB,CAAA;AAO1B,KAAK,QAAQ,GAAG;IACd,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,EAAE,CACH;QACE,IAAI,EAAE,MAAM,CAAA;QACZ,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;QACb,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,GACD;QACE,IAAI,EAAE,MAAM,CAAA;QACZ,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,IAAI,CAAA;QACX,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,GACD;QACE,IAAI,EAAE,MAAM,CAAA;QACZ,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,IAAI,CAAA;QACX,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,CACJ,EAAE,CAAA;CACJ,CAAA;AAwBD,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE;QACL,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;KACd,EAAE,CAAA;CACJ,CAAA;AAED,KAAK,GAAG,GAAG;IACT,IAAI,EAAE,KAAK,CAAA;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,UAAU,GACV,GAAG,GACH;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,CAAA;AA2CtE;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,aAAa,iBAAiB,GAAG,SAAS;AAC1C,qCAAqC;AACrC,oBAAuB;AACvB,sEAAsE;AACtE,kCAAkC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACvD,WAAW,GAAG,IA8WhB,CAAA"}
|