@scalar/api-client 3.21.3 → 3.21.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/plugins/posthog/sanitize-event-payload.d.ts.map +1 -1
- package/dist/plugins/posthog/sanitize-event-payload.js +1 -0
- package/dist/plugins/posthog/sanitize-event-payload.js.map +1 -1
- package/dist/style.css +59 -49
- package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.js +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js +3 -0
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.js +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.script.js +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js +53 -22
- package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.d.ts +4 -0
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.script.js +23 -12
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.script.js +30 -6
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth-device-authorization.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth-device-authorization.js +3 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth-device-authorization.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js +9 -3
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.d.ts.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.js +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.js.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.script.js.map +1 -1
- package/dist/v2/components/data-table/DataTableInput.vue.d.ts.map +1 -1
- package/dist/v2/components/data-table/DataTableInput.vue.js +1 -1
- package/dist/v2/components/data-table/DataTableInput.vue.js.map +1 -1
- package/dist/v2/components/data-table/DataTableInput.vue.script.js +15 -11
- package/dist/v2/components/data-table/DataTableInput.vue.script.js.map +1 -1
- package/dist/v2/components/server/ServerDropdown.vue.d.ts.map +1 -1
- package/dist/v2/components/server/ServerDropdown.vue.js.map +1 -1
- package/dist/v2/components/server/ServerDropdown.vue.script.js +1 -1
- package/dist/v2/components/server/ServerDropdown.vue.script.js.map +1 -1
- package/dist/v2/constants.js +1 -1
- package/dist/v2/features/localization/locales/ar.d.ts +3 -0
- package/dist/v2/features/localization/locales/ar.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/ar.js +4 -1
- package/dist/v2/features/localization/locales/ar.js.map +1 -1
- package/dist/v2/features/localization/locales/de.d.ts +3 -0
- package/dist/v2/features/localization/locales/de.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/de.js +4 -1
- package/dist/v2/features/localization/locales/de.js.map +1 -1
- package/dist/v2/features/localization/locales/es.d.ts +3 -0
- package/dist/v2/features/localization/locales/es.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/es.js +4 -1
- package/dist/v2/features/localization/locales/es.js.map +1 -1
- package/dist/v2/features/localization/locales/fr.d.ts +3 -0
- package/dist/v2/features/localization/locales/fr.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/fr.js +4 -1
- package/dist/v2/features/localization/locales/fr.js.map +1 -1
- package/dist/v2/features/localization/locales/pt.d.ts +3 -0
- package/dist/v2/features/localization/locales/pt.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/pt.js +4 -1
- package/dist/v2/features/localization/locales/pt.js.map +1 -1
- package/dist/v2/features/localization/locales/ru.d.ts +3 -0
- package/dist/v2/features/localization/locales/ru.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/ru.js +4 -1
- package/dist/v2/features/localization/locales/ru.js.map +1 -1
- package/dist/v2/features/localization/locales/zh-cn.d.ts +3 -0
- package/dist/v2/features/localization/locales/zh-cn.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/zh-cn.js +4 -1
- package/dist/v2/features/localization/locales/zh-cn.js.map +1 -1
- package/dist/v2/features/localization/translations.d.ts +3 -0
- package/dist/v2/features/localization/translations.d.ts.map +1 -1
- package/dist/v2/features/localization/translations.js +4 -1
- package/dist/v2/features/localization/translations.js.map +1 -1
- package/dist/v2/workspace-events.d.ts.map +1 -1
- package/dist/v2/workspace-events.js +1 -0
- package/dist/v2/workspace-events.js.map +1 -1
- package/dist/vue-styles.css +29 -31
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @scalar/api-client
|
|
2
2
|
|
|
3
|
+
## 3.21.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#10463](https://github.com/scalar/scalar/pull/10463): Fix large request bodies rendering blank gaps in the code editor.
|
|
8
|
+
- [#10431](https://github.com/scalar/scalar/pull/10431): Keep explicit authentication field clears separate from configured defaults, add field-local reset actions, and prevent clearing fixed-choice OAuth settings.
|
|
9
|
+
- [#10470](https://github.com/scalar/scalar/pull/10470): Polish the bearer token "Get a token" row: the label matches the font size and color of the rows around it, the settings icon lines up with the password toggle above it, and the authorize button uses the gradient style.
|
|
10
|
+
- [#10472](https://github.com/scalar/scalar/pull/10472): Stop pointing auth field labels at the non-labelable editor wrapper, and keep focusing the masked password input when its label is clicked.
|
|
11
|
+
- [#10466](https://github.com/scalar/scalar/pull/10466): Fix long unbroken lines in the raw request body (for example Base64 strings or tokens) stretching the client beyond the viewport. The line now scrolls inside the editor.
|
|
12
|
+
- [#10467](https://github.com/scalar/scalar/pull/10467): Use the design system border, shadow, and extra-large radius for all floating surfaces. Backdrops now inherit their radius from the floating element, and the lifted brightness no longer brightens the border.
|
|
13
|
+
|
|
14
|
+
## 3.21.4
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- [#10372](https://github.com/scalar/scalar/pull/10372): fix: improve keyboard and screen reader access to code blocks and multiselect comboboxes
|
|
19
|
+
- The code block scroller is exposed as a named group ("Code sample: Shell cURL" in the API Reference, localizable via `operation.codeSample`) so screen readers announce it when it receives focus
|
|
20
|
+
- The code block copy button now has a stable accessible name ("Copy Shell code") in every state, including while its visible label is hidden
|
|
21
|
+
- In multiselect comboboxes such as the auth scheme picker, Space toggles the active option while the search query is empty instead of hiding the whole list
|
|
22
|
+
|
|
3
23
|
## 3.21.3
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize-event-payload.d.ts","sourceRoot":"","sources":["../../../src/plugins/posthog/sanitize-event-payload.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAuBxE;;;;;;GAMG;AACH,KAAK,gBAAgB,CAAC,CAAC,SAAS,MAAM,kBAAkB,GAAG,MAAM,kBAAkB,IAAI,CACrF,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAA;AAEpD,4EAA4E;AAC5E,KAAK,gBAAgB,GAAG;KACrB,CAAC,IAAI,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,SAAS;CACjE,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"sanitize-event-payload.d.ts","sourceRoot":"","sources":["../../../src/plugins/posthog/sanitize-event-payload.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAuBxE;;;;;;GAMG;AACH,KAAK,gBAAgB,CAAC,CAAC,SAAS,MAAM,kBAAkB,GAAG,MAAM,kBAAkB,IAAI,CACrF,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAA;AAEpD,4EAA4E;AAC5E,KAAK,gBAAgB,GAAG;KACrB,CAAC,IAAI,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,SAAS;CACjE,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,gBAsI5B,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,MAAM,kBAAkB,EACrE,OAAO,CAAC,EACR,SAAS,kBAAkB,CAAC,CAAC,CAAC,KAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG,IAMpD,CAAA"}
|
|
@@ -26,6 +26,7 @@ var TRACKED_EVENTS = {
|
|
|
26
26
|
"auth:clear:selected-security-schemes": stringAtPath(["meta", "type"]),
|
|
27
27
|
"auth:update:selected-scopes": stringAtPath(["meta", "type"]),
|
|
28
28
|
"auth:delete:security-scheme": empty,
|
|
29
|
+
"auth:reset:security-scheme-secret": empty,
|
|
29
30
|
"auth:clear:security-scheme-secrets": empty,
|
|
30
31
|
"auth:upsert:scopes": empty,
|
|
31
32
|
"auth:delete:scopes": empty,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize-event-payload.js","names":[],"sources":["../../../src/plugins/posthog/sanitize-event-payload.ts"],"sourcesContent":["import { getValueAtPath } from '@scalar/helpers/object/get-value-at-path'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\n\n/**\n * Builds an extractor that pulls a string from `payload` at `path` and emits\n * it under `{ [key]: value }`. Returns `{}` when the leaf is missing or is\n * not a string.\n *\n * `key` defaults to the dotted form of `path` (e.g. `['meta', 'type']` becomes\n * `'meta.type'`), matching the existing PostHog property names.\n *\n * Built on `getValueAtPath`, so null/undefined traversal and missing segments\n * are handled centrally.\n */\nconst stringAtPath = (path: string[], key: string = path.join('.')) => {\n return (payload: unknown): Record<string, unknown> => {\n const value = getValueAtPath(payload, path)\n return typeof value === 'string' ? { [key]: value } : {}\n }\n}\n\n/** Extractor for events whose only useful property is the fact they fired. */\nconst empty = (): Record<string, unknown> => ({})\n\n/**\n * Allowlist of events that should be forwarded to PostHog.\n *\n * Each key is an event name; its value is an extractor that pulls only the\n * safe, non-PII properties we want to track. Events not in this map are\n * silently dropped — this keeps the analytics surface explicit and auditable.\n */\ntype PayloadExtractor<K extends keyof ApiReferenceEvents = keyof ApiReferenceEvents> = (\n payload: ApiReferenceEvents[K],\n) => Record<string, unknown> | ApiReferenceEvents[K]\n\n/** Maps every event to either a typed extractor or `undefined` (opt-out) */\ntype TrackedEventsMap = {\n [K in keyof ApiReferenceEvents]: PayloadExtractor<K> | undefined\n}\n\nexport const TRACKED_EVENTS: TrackedEventsMap = {\n // Auth events — track the scheme type so we know which auth methods are popular\n 'auth:update:selected-security-schemes': stringAtPath(['meta', 'type']),\n 'auth:update:active-index': stringAtPath(['meta', 'type']),\n 'auth:update:security-scheme': stringAtPath(['payload', 'type']),\n 'auth:clear:selected-security-schemes': stringAtPath(['meta', 'type']),\n 'auth:update:selected-scopes': stringAtPath(['meta', 'type']),\n 'auth:delete:security-scheme': empty,\n 'auth:clear:security-scheme-secrets': empty,\n 'auth:upsert:scopes': empty,\n 'auth:delete:scopes': empty,\n\n // Cookie events — track whether it belongs to a document or workspace\n 'cookie:upsert:cookie': stringAtPath(['collectionType']),\n 'cookie:delete:cookie': stringAtPath(['collectionType']),\n\n // Environment events — same document-vs-workspace distinction\n 'environment:upsert:environment': stringAtPath(['collectionType']),\n 'environment:delete:environment': stringAtPath(['collectionType']),\n 'environment:upsert:environment-variable': stringAtPath(['collectionType']),\n 'environment:delete:environment-variable': stringAtPath(['collectionType']),\n\n // Document lifecycle\n 'document:create:empty-document': empty,\n 'document:delete:document': empty,\n 'document:update:info': empty,\n 'document:update:icon': empty,\n 'document:update:watch-mode': empty,\n\n // Operation events — contentType helps us understand payload format usage\n 'operation:send:request:hotkey': empty,\n 'operation:cancel:request': empty,\n 'operation:create:operation': empty,\n 'operation:delete:operation': empty,\n 'operation:create:draft-example': empty,\n 'operation:delete:example': empty,\n 'operation:update:requestBody:contentType': stringAtPath(['payload', 'contentType']),\n 'operation:update:pathMethod': empty,\n 'operation:rename:example': empty,\n 'operation:reload:history': empty,\n\n // UI events — track which surfaces users interact with\n 'ui:open:client-modal': empty,\n 'ui:open:command-palette': empty,\n 'ui:open:settings': empty,\n 'ui:download:document': stringAtPath(['format']),\n 'ui:toggle:sidebar': empty,\n 'ui:save:local-document': empty,\n 'copy-url:address-bar': empty,\n 'tabs:add:tab': empty,\n 'tabs:copy:url': empty,\n\n // Server events\n 'server:add:server': empty,\n 'server:delete:server': empty,\n\n // Tag events\n 'tag:create:tag': empty,\n 'tag:delete:tag': empty,\n\n // Request lifecycle hooks — lets us measure request volume without capturing bodies\n 'hooks:on:request:sent': empty,\n 'hooks:on:request:complete': empty,\n 'hooks:on:rebase:document:complete': empty,\n\n // Workspace preference events\n 'workspace:update:color-mode': empty,\n 'workspace:update:theme': empty,\n 'workspace:update:selected-client': empty,\n 'workspace:update:selected-example': empty,\n 'workspace:update:active-proxy': (payload) => ({ enabled: !!payload }),\n 'workspace:update:active-environment': empty,\n\n // Meta events\n 'update:dark-mode': empty,\n 'update:active-document': empty,\n 'update:selected-client': empty,\n\n // Account funnel events\n 'log:login-click': empty,\n 'log:register-click': empty,\n 'log:user-login': empty,\n 'log:user-logout': empty,\n\n // Document sync and save events\n 'log:save-document': empty,\n 'log:sync-pull-document': empty,\n 'log:sync-push-document': empty,\n\n // ---------------------------------------------------------------------------\n // Do not track — explicitly opted out so new events cause a type error\n // until they are consciously placed above with a payload\n // ---------------------------------------------------------------------------\n 'auth:update:security-scheme-secrets': undefined,\n 'analytics:on:show-more': undefined,\n 'analytics:on:loaded': undefined,\n 'document:update:extension': undefined,\n 'operation:update:meta': undefined,\n 'operation:update:extension': undefined,\n 'operation:upsert:parameter': undefined,\n 'operation:update:extra-parameters': undefined,\n 'operation:delete:parameter': undefined,\n 'operation:delete-all:parameters': undefined,\n 'operation:update:requestBody:value': undefined,\n 'operation:update:requestBody:formValue': undefined,\n 'server:initialize:servers': undefined,\n 'server:update:server': undefined,\n 'server:update:variables': undefined,\n 'server:update:selected': undefined,\n 'server:clear:servers': undefined,\n 'asyncapi-server:update:selected': undefined,\n 'asyncapi-server:update:variables': undefined,\n 'tabs:update:tabs': undefined,\n 'tabs:close:tab': undefined,\n 'tabs:close:other-tabs': undefined,\n 'tabs:navigate:previous': undefined,\n 'tabs:navigate:next': undefined,\n 'tabs:focus:tab': undefined,\n 'tabs:focus:tab-last': undefined,\n 'ui:focus:address-bar': undefined,\n 'ui:focus:send-button': undefined,\n 'ui:focus:search': undefined,\n 'ui:open:create-workspace': undefined,\n 'ui:close:client-modal': undefined,\n 'ui:navigate': undefined,\n 'toggle:nav-item': undefined,\n 'select:nav-item': undefined,\n 'intersecting:nav-item': undefined,\n 'scroll-to:nav-item': undefined,\n 'scroll-to:model-by-name': undefined,\n 'copy-url:nav-item': undefined,\n 'tag:edit:tag': undefined,\n 'workspace:update:name': undefined,\n}\n\n/**\n * Returns sanitized properties for a tracked event, or `null` if the event\n * should not be captured at all.\n *\n * This is the only function that the PostHog plugin needs to call — it\n * encapsulates both the \"should we track this?\" decision and the \"what\n * properties are safe to send?\" extraction in one step.\n */\nexport const sanitizeEventPayload = <K extends keyof ApiReferenceEvents>(\n event: K,\n payload: ApiReferenceEvents[K],\n): Record<string, unknown> | ApiReferenceEvents[K] | null => {\n const extractor = TRACKED_EVENTS[event]\n if (!extractor) {\n return null\n }\n return extractor(payload)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sanitize-event-payload.js","names":[],"sources":["../../../src/plugins/posthog/sanitize-event-payload.ts"],"sourcesContent":["import { getValueAtPath } from '@scalar/helpers/object/get-value-at-path'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\n\n/**\n * Builds an extractor that pulls a string from `payload` at `path` and emits\n * it under `{ [key]: value }`. Returns `{}` when the leaf is missing or is\n * not a string.\n *\n * `key` defaults to the dotted form of `path` (e.g. `['meta', 'type']` becomes\n * `'meta.type'`), matching the existing PostHog property names.\n *\n * Built on `getValueAtPath`, so null/undefined traversal and missing segments\n * are handled centrally.\n */\nconst stringAtPath = (path: string[], key: string = path.join('.')) => {\n return (payload: unknown): Record<string, unknown> => {\n const value = getValueAtPath(payload, path)\n return typeof value === 'string' ? { [key]: value } : {}\n }\n}\n\n/** Extractor for events whose only useful property is the fact they fired. */\nconst empty = (): Record<string, unknown> => ({})\n\n/**\n * Allowlist of events that should be forwarded to PostHog.\n *\n * Each key is an event name; its value is an extractor that pulls only the\n * safe, non-PII properties we want to track. Events not in this map are\n * silently dropped — this keeps the analytics surface explicit and auditable.\n */\ntype PayloadExtractor<K extends keyof ApiReferenceEvents = keyof ApiReferenceEvents> = (\n payload: ApiReferenceEvents[K],\n) => Record<string, unknown> | ApiReferenceEvents[K]\n\n/** Maps every event to either a typed extractor or `undefined` (opt-out) */\ntype TrackedEventsMap = {\n [K in keyof ApiReferenceEvents]: PayloadExtractor<K> | undefined\n}\n\nexport const TRACKED_EVENTS: TrackedEventsMap = {\n // Auth events — track the scheme type so we know which auth methods are popular\n 'auth:update:selected-security-schemes': stringAtPath(['meta', 'type']),\n 'auth:update:active-index': stringAtPath(['meta', 'type']),\n 'auth:update:security-scheme': stringAtPath(['payload', 'type']),\n 'auth:clear:selected-security-schemes': stringAtPath(['meta', 'type']),\n 'auth:update:selected-scopes': stringAtPath(['meta', 'type']),\n 'auth:delete:security-scheme': empty,\n 'auth:reset:security-scheme-secret': empty,\n 'auth:clear:security-scheme-secrets': empty,\n 'auth:upsert:scopes': empty,\n 'auth:delete:scopes': empty,\n\n // Cookie events — track whether it belongs to a document or workspace\n 'cookie:upsert:cookie': stringAtPath(['collectionType']),\n 'cookie:delete:cookie': stringAtPath(['collectionType']),\n\n // Environment events — same document-vs-workspace distinction\n 'environment:upsert:environment': stringAtPath(['collectionType']),\n 'environment:delete:environment': stringAtPath(['collectionType']),\n 'environment:upsert:environment-variable': stringAtPath(['collectionType']),\n 'environment:delete:environment-variable': stringAtPath(['collectionType']),\n\n // Document lifecycle\n 'document:create:empty-document': empty,\n 'document:delete:document': empty,\n 'document:update:info': empty,\n 'document:update:icon': empty,\n 'document:update:watch-mode': empty,\n\n // Operation events — contentType helps us understand payload format usage\n 'operation:send:request:hotkey': empty,\n 'operation:cancel:request': empty,\n 'operation:create:operation': empty,\n 'operation:delete:operation': empty,\n 'operation:create:draft-example': empty,\n 'operation:delete:example': empty,\n 'operation:update:requestBody:contentType': stringAtPath(['payload', 'contentType']),\n 'operation:update:pathMethod': empty,\n 'operation:rename:example': empty,\n 'operation:reload:history': empty,\n\n // UI events — track which surfaces users interact with\n 'ui:open:client-modal': empty,\n 'ui:open:command-palette': empty,\n 'ui:open:settings': empty,\n 'ui:download:document': stringAtPath(['format']),\n 'ui:toggle:sidebar': empty,\n 'ui:save:local-document': empty,\n 'copy-url:address-bar': empty,\n 'tabs:add:tab': empty,\n 'tabs:copy:url': empty,\n\n // Server events\n 'server:add:server': empty,\n 'server:delete:server': empty,\n\n // Tag events\n 'tag:create:tag': empty,\n 'tag:delete:tag': empty,\n\n // Request lifecycle hooks — lets us measure request volume without capturing bodies\n 'hooks:on:request:sent': empty,\n 'hooks:on:request:complete': empty,\n 'hooks:on:rebase:document:complete': empty,\n\n // Workspace preference events\n 'workspace:update:color-mode': empty,\n 'workspace:update:theme': empty,\n 'workspace:update:selected-client': empty,\n 'workspace:update:selected-example': empty,\n 'workspace:update:active-proxy': (payload) => ({ enabled: !!payload }),\n 'workspace:update:active-environment': empty,\n\n // Meta events\n 'update:dark-mode': empty,\n 'update:active-document': empty,\n 'update:selected-client': empty,\n\n // Account funnel events\n 'log:login-click': empty,\n 'log:register-click': empty,\n 'log:user-login': empty,\n 'log:user-logout': empty,\n\n // Document sync and save events\n 'log:save-document': empty,\n 'log:sync-pull-document': empty,\n 'log:sync-push-document': empty,\n\n // ---------------------------------------------------------------------------\n // Do not track — explicitly opted out so new events cause a type error\n // until they are consciously placed above with a payload\n // ---------------------------------------------------------------------------\n 'auth:update:security-scheme-secrets': undefined,\n 'analytics:on:show-more': undefined,\n 'analytics:on:loaded': undefined,\n 'document:update:extension': undefined,\n 'operation:update:meta': undefined,\n 'operation:update:extension': undefined,\n 'operation:upsert:parameter': undefined,\n 'operation:update:extra-parameters': undefined,\n 'operation:delete:parameter': undefined,\n 'operation:delete-all:parameters': undefined,\n 'operation:update:requestBody:value': undefined,\n 'operation:update:requestBody:formValue': undefined,\n 'server:initialize:servers': undefined,\n 'server:update:server': undefined,\n 'server:update:variables': undefined,\n 'server:update:selected': undefined,\n 'server:clear:servers': undefined,\n 'asyncapi-server:update:selected': undefined,\n 'asyncapi-server:update:variables': undefined,\n 'tabs:update:tabs': undefined,\n 'tabs:close:tab': undefined,\n 'tabs:close:other-tabs': undefined,\n 'tabs:navigate:previous': undefined,\n 'tabs:navigate:next': undefined,\n 'tabs:focus:tab': undefined,\n 'tabs:focus:tab-last': undefined,\n 'ui:focus:address-bar': undefined,\n 'ui:focus:send-button': undefined,\n 'ui:focus:search': undefined,\n 'ui:open:create-workspace': undefined,\n 'ui:close:client-modal': undefined,\n 'ui:navigate': undefined,\n 'toggle:nav-item': undefined,\n 'select:nav-item': undefined,\n 'intersecting:nav-item': undefined,\n 'scroll-to:nav-item': undefined,\n 'scroll-to:model-by-name': undefined,\n 'copy-url:nav-item': undefined,\n 'tag:edit:tag': undefined,\n 'workspace:update:name': undefined,\n}\n\n/**\n * Returns sanitized properties for a tracked event, or `null` if the event\n * should not be captured at all.\n *\n * This is the only function that the PostHog plugin needs to call — it\n * encapsulates both the \"should we track this?\" decision and the \"what\n * properties are safe to send?\" extraction in one step.\n */\nexport const sanitizeEventPayload = <K extends keyof ApiReferenceEvents>(\n event: K,\n payload: ApiReferenceEvents[K],\n): Record<string, unknown> | ApiReferenceEvents[K] | null => {\n const extractor = TRACKED_EVENTS[event]\n if (!extractor) {\n return null\n }\n return extractor(payload)\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,IAAM,gBAAgB,MAAgB,MAAc,KAAK,KAAK,GAAG,MAAM;CACrE,QAAQ,YAA8C;EACpD,MAAM,QAAQ,eAAe,SAAS,IAAI;EAC1C,OAAO,OAAO,UAAU,WAAW,GAAG,MAAM,MAAM,IAAI,CAAC;CACzD;AACF;;AAGA,IAAM,eAAwC,CAAC;AAkB/C,IAAa,iBAAmC;CAE9C,yCAAyC,aAAa,CAAC,QAAQ,MAAM,CAAC;CACtE,4BAA4B,aAAa,CAAC,QAAQ,MAAM,CAAC;CACzD,+BAA+B,aAAa,CAAC,WAAW,MAAM,CAAC;CAC/D,wCAAwC,aAAa,CAAC,QAAQ,MAAM,CAAC;CACrE,+BAA+B,aAAa,CAAC,QAAQ,MAAM,CAAC;CAC5D,+BAA+B;CAC/B,qCAAqC;CACrC,sCAAsC;CACtC,sBAAsB;CACtB,sBAAsB;CAGtB,wBAAwB,aAAa,CAAC,gBAAgB,CAAC;CACvD,wBAAwB,aAAa,CAAC,gBAAgB,CAAC;CAGvD,kCAAkC,aAAa,CAAC,gBAAgB,CAAC;CACjE,kCAAkC,aAAa,CAAC,gBAAgB,CAAC;CACjE,2CAA2C,aAAa,CAAC,gBAAgB,CAAC;CAC1E,2CAA2C,aAAa,CAAC,gBAAgB,CAAC;CAG1E,kCAAkC;CAClC,4BAA4B;CAC5B,wBAAwB;CACxB,wBAAwB;CACxB,8BAA8B;CAG9B,iCAAiC;CACjC,4BAA4B;CAC5B,8BAA8B;CAC9B,8BAA8B;CAC9B,kCAAkC;CAClC,4BAA4B;CAC5B,4CAA4C,aAAa,CAAC,WAAW,aAAa,CAAC;CACnF,+BAA+B;CAC/B,4BAA4B;CAC5B,4BAA4B;CAG5B,wBAAwB;CACxB,2BAA2B;CAC3B,oBAAoB;CACpB,wBAAwB,aAAa,CAAC,QAAQ,CAAC;CAC/C,qBAAqB;CACrB,0BAA0B;CAC1B,wBAAwB;CACxB,gBAAgB;CAChB,iBAAiB;CAGjB,qBAAqB;CACrB,wBAAwB;CAGxB,kBAAkB;CAClB,kBAAkB;CAGlB,yBAAyB;CACzB,6BAA6B;CAC7B,qCAAqC;CAGrC,+BAA+B;CAC/B,0BAA0B;CAC1B,oCAAoC;CACpC,qCAAqC;CACrC,kCAAkC,aAAa,EAAE,SAAS,CAAC,CAAC,QAAQ;CACpE,uCAAuC;CAGvC,oBAAoB;CACpB,0BAA0B;CAC1B,0BAA0B;CAG1B,mBAAmB;CACnB,sBAAsB;CACtB,kBAAkB;CAClB,mBAAmB;CAGnB,qBAAqB;CACrB,0BAA0B;CAC1B,0BAA0B;CAM1B,uCAAuC,KAAA;CACvC,0BAA0B,KAAA;CAC1B,uBAAuB,KAAA;CACvB,6BAA6B,KAAA;CAC7B,yBAAyB,KAAA;CACzB,8BAA8B,KAAA;CAC9B,8BAA8B,KAAA;CAC9B,qCAAqC,KAAA;CACrC,8BAA8B,KAAA;CAC9B,mCAAmC,KAAA;CACnC,sCAAsC,KAAA;CACtC,0CAA0C,KAAA;CAC1C,6BAA6B,KAAA;CAC7B,wBAAwB,KAAA;CACxB,2BAA2B,KAAA;CAC3B,0BAA0B,KAAA;CAC1B,wBAAwB,KAAA;CACxB,mCAAmC,KAAA;CACnC,oCAAoC,KAAA;CACpC,oBAAoB,KAAA;CACpB,kBAAkB,KAAA;CAClB,yBAAyB,KAAA;CACzB,0BAA0B,KAAA;CAC1B,sBAAsB,KAAA;CACtB,kBAAkB,KAAA;CAClB,uBAAuB,KAAA;CACvB,wBAAwB,KAAA;CACxB,wBAAwB,KAAA;CACxB,mBAAmB,KAAA;CACnB,4BAA4B,KAAA;CAC5B,yBAAyB,KAAA;CACzB,eAAe,KAAA;CACf,mBAAmB,KAAA;CACnB,mBAAmB,KAAA;CACnB,yBAAyB,KAAA;CACzB,sBAAsB,KAAA;CACtB,2BAA2B,KAAA;CAC3B,qBAAqB,KAAA;CACrB,gBAAgB,KAAA;CAChB,yBAAyB,KAAA;AAC3B;;;;;;;;;AAUA,IAAa,wBACX,OACA,YAC2D;CAC3D,MAAM,YAAY,eAAe;CACjC,IAAI,CAAC,WACH,OAAO;CAET,OAAO,UAAU,OAAO;AAC1B"}
|
package/dist/style.css
CHANGED
|
@@ -2036,10 +2036,6 @@
|
|
|
2036
2036
|
inset-inline: 4px;
|
|
2037
2037
|
}
|
|
2038
2038
|
|
|
2039
|
-
.scalar-app .inset-x-px {
|
|
2040
|
-
inset-inline: 1px;
|
|
2041
|
-
}
|
|
2042
|
-
|
|
2043
2039
|
.scalar-app .-inset-y-0\.5 {
|
|
2044
2040
|
inset-block: -2px;
|
|
2045
2041
|
}
|
|
@@ -2172,6 +2168,10 @@
|
|
|
2172
2168
|
left: 0;
|
|
2173
2169
|
}
|
|
2174
2170
|
|
|
2171
|
+
.scalar-app .left-1\.75 {
|
|
2172
|
+
left: 7px;
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
2175
|
.scalar-app .left-1\/2 {
|
|
2176
2176
|
left: 50%;
|
|
2177
2177
|
}
|
|
@@ -2180,10 +2180,6 @@
|
|
|
2180
2180
|
left: 8px;
|
|
2181
2181
|
}
|
|
2182
2182
|
|
|
2183
|
-
.scalar-app .left-2\.5 {
|
|
2184
|
-
left: 10px;
|
|
2185
|
-
}
|
|
2186
|
-
|
|
2187
2183
|
.scalar-app .left-3 {
|
|
2188
2184
|
left: 12px;
|
|
2189
2185
|
}
|
|
@@ -2496,6 +2492,10 @@
|
|
|
2496
2492
|
margin-bottom: 0;
|
|
2497
2493
|
}
|
|
2498
2494
|
|
|
2495
|
+
.scalar-app .mb-0\.75 {
|
|
2496
|
+
margin-bottom: 3px;
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
2499
|
.scalar-app .mb-1 {
|
|
2500
2500
|
margin-bottom: 4px;
|
|
2501
2501
|
}
|
|
@@ -3973,10 +3973,6 @@
|
|
|
3973
3973
|
padding-block: 8px;
|
|
3974
3974
|
}
|
|
3975
3975
|
|
|
3976
|
-
.scalar-app .py-2\.5 {
|
|
3977
|
-
padding-block: 10px;
|
|
3978
|
-
}
|
|
3979
|
-
|
|
3980
3976
|
.scalar-app .py-3 {
|
|
3981
3977
|
padding-block: 12px;
|
|
3982
3978
|
}
|
|
@@ -4029,6 +4025,10 @@
|
|
|
4029
4025
|
padding-right: 6px;
|
|
4030
4026
|
}
|
|
4031
4027
|
|
|
4028
|
+
.scalar-app .pr-1\.75 {
|
|
4029
|
+
padding-right: 7px;
|
|
4030
|
+
}
|
|
4031
|
+
|
|
4032
4032
|
.scalar-app .pr-2 {
|
|
4033
4033
|
padding-right: 8px;
|
|
4034
4034
|
}
|
|
@@ -4041,10 +4041,6 @@
|
|
|
4041
4041
|
padding-right: 9px;
|
|
4042
4042
|
}
|
|
4043
4043
|
|
|
4044
|
-
.scalar-app .pr-3 {
|
|
4045
|
-
padding-right: 12px;
|
|
4046
|
-
}
|
|
4047
|
-
|
|
4048
4044
|
.scalar-app .pr-6 {
|
|
4049
4045
|
padding-right: 24px;
|
|
4050
4046
|
}
|
|
@@ -4105,8 +4101,8 @@
|
|
|
4105
4101
|
padding-left: 16px;
|
|
4106
4102
|
}
|
|
4107
4103
|
|
|
4108
|
-
.scalar-app .pl-
|
|
4109
|
-
padding-left:
|
|
4104
|
+
.scalar-app .pl-7\.25 {
|
|
4105
|
+
padding-left: 29px;
|
|
4110
4106
|
}
|
|
4111
4107
|
|
|
4112
4108
|
.scalar-app .pl-8\.5 {
|
|
@@ -5088,6 +5084,11 @@
|
|
|
5088
5084
|
display: block;
|
|
5089
5085
|
}
|
|
5090
5086
|
|
|
5087
|
+
.scalar-app .after\:hidden:after {
|
|
5088
|
+
content: var(--tw-content);
|
|
5089
|
+
display: none;
|
|
5090
|
+
}
|
|
5091
|
+
|
|
5091
5092
|
.scalar-app .after\:h-0\.75:after {
|
|
5092
5093
|
content: var(--tw-content);
|
|
5093
5094
|
height: 3px;
|
|
@@ -5098,6 +5099,11 @@
|
|
|
5098
5099
|
border-radius: var(--scalar-radius-md);
|
|
5099
5100
|
}
|
|
5100
5101
|
|
|
5102
|
+
.scalar-app .after\:rounded-\[inherit\]:after {
|
|
5103
|
+
content: var(--tw-content);
|
|
5104
|
+
border-radius: inherit;
|
|
5105
|
+
}
|
|
5106
|
+
|
|
5101
5107
|
.scalar-app .after\:bg-blue:after {
|
|
5102
5108
|
content: var(--tw-content);
|
|
5103
5109
|
background-color: var(--scalar-color-blue);
|
|
@@ -5108,6 +5114,12 @@
|
|
|
5108
5114
|
opacity: .15;
|
|
5109
5115
|
}
|
|
5110
5116
|
|
|
5117
|
+
.scalar-app .after\:shadow-border:after {
|
|
5118
|
+
content: var(--tw-content);
|
|
5119
|
+
--tw-shadow: inset 0 0 0 var(--scalar-border-width) var(--scalar-border-color);
|
|
5120
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
5121
|
+
}
|
|
5122
|
+
|
|
5111
5123
|
.scalar-app .after\:content-\[\'\:\'\]:after {
|
|
5112
5124
|
--tw-content: ":";
|
|
5113
5125
|
content: var(--tw-content);
|
|
@@ -6244,23 +6256,22 @@ to {
|
|
|
6244
6256
|
/*
|
|
6245
6257
|
Deep styling for customizing Codemirror
|
|
6246
6258
|
*/
|
|
6247
|
-
[data-v-
|
|
6259
|
+
[data-v-5ce9d77a] .cm-editor {
|
|
6248
6260
|
height: 100%;
|
|
6249
6261
|
outline: none;
|
|
6250
6262
|
padding: 0;
|
|
6251
6263
|
background: transparent;
|
|
6252
6264
|
}
|
|
6253
|
-
[data-v-
|
|
6265
|
+
[data-v-5ce9d77a] .cm-placeholder {
|
|
6254
6266
|
color: var(--scalar-color-3);
|
|
6255
6267
|
}
|
|
6256
|
-
[data-v-
|
|
6268
|
+
[data-v-5ce9d77a] .cm-content {
|
|
6257
6269
|
font-family: var(--scalar-font-code);
|
|
6258
6270
|
font-size: var(--scalar-small);
|
|
6259
|
-
max-height: 20px;
|
|
6260
6271
|
padding: 8px 0;
|
|
6261
6272
|
}
|
|
6262
6273
|
/* Tooltip helper */
|
|
6263
|
-
[data-v-
|
|
6274
|
+
[data-v-5ce9d77a] .cm-tooltip {
|
|
6264
6275
|
background: transparent !important;
|
|
6265
6276
|
filter: brightness(var(--scalar-lifted-brightness));
|
|
6266
6277
|
border-radius: var(--scalar-radius);
|
|
@@ -6269,43 +6280,43 @@ to {
|
|
|
6269
6280
|
outline: none !important;
|
|
6270
6281
|
overflow: hidden !important;
|
|
6271
6282
|
}
|
|
6272
|
-
[data-v-
|
|
6283
|
+
[data-v-5ce9d77a] .cm-tooltip-autocomplete ul li {
|
|
6273
6284
|
padding: 3px 6px !important;
|
|
6274
6285
|
}
|
|
6275
|
-
[data-v-
|
|
6286
|
+
[data-v-5ce9d77a] .cm-completionIcon-type:after {
|
|
6276
6287
|
color: var(--scalar-color-3) !important;
|
|
6277
6288
|
}
|
|
6278
|
-
[data-v-
|
|
6289
|
+
[data-v-5ce9d77a] .cm-tooltip-autocomplete ul li[aria-selected] {
|
|
6279
6290
|
background: var(--scalar-background-2) !important;
|
|
6280
6291
|
color: var(--scalar-color-1) !important;
|
|
6281
6292
|
}
|
|
6282
|
-
[data-v-
|
|
6293
|
+
[data-v-5ce9d77a] .cm-tooltip-autocomplete ul {
|
|
6283
6294
|
padding: 6px !important;
|
|
6284
6295
|
position: relative;
|
|
6285
6296
|
}
|
|
6286
|
-
[data-v-
|
|
6297
|
+
[data-v-5ce9d77a] .cm-tooltip-autocomplete ul li:hover {
|
|
6287
6298
|
border-radius: 3px;
|
|
6288
6299
|
color: var(--scalar-color-1) !important;
|
|
6289
6300
|
background: var(--scalar-background-3) !important;
|
|
6290
6301
|
}
|
|
6291
6302
|
/* Disable active line highlighting */
|
|
6292
|
-
[data-v-
|
|
6303
|
+
[data-v-5ce9d77a] .cm-activeLine,[data-v-5ce9d77a] .cm-activeLineGutter {
|
|
6293
6304
|
background-color: transparent;
|
|
6294
6305
|
}
|
|
6295
6306
|
/* Color selection matching */
|
|
6296
|
-
[data-v-
|
|
6307
|
+
[data-v-5ce9d77a] .cm-selectionMatch,[data-v-5ce9d77a] .cm-matchingBracket {
|
|
6297
6308
|
border-radius: var(--scalar-radius);
|
|
6298
6309
|
background: var(--scalar-background-4) !important;
|
|
6299
6310
|
}
|
|
6300
6311
|
/* Color Picker Swatches */
|
|
6301
|
-
[data-v-
|
|
6312
|
+
[data-v-5ce9d77a] .cm-css-color-picker-wrapper {
|
|
6302
6313
|
display: inline-flex;
|
|
6303
6314
|
outline: 1px solid var(--scalar-background-3);
|
|
6304
6315
|
border-radius: 3px;
|
|
6305
6316
|
overflow: hidden;
|
|
6306
6317
|
}
|
|
6307
6318
|
/* Number gutter */
|
|
6308
|
-
[data-v-
|
|
6319
|
+
[data-v-5ce9d77a] .cm-gutters {
|
|
6309
6320
|
background-color: transparent;
|
|
6310
6321
|
border-right: none;
|
|
6311
6322
|
color: var(--scalar-color-3);
|
|
@@ -6313,7 +6324,7 @@ to {
|
|
|
6313
6324
|
line-height: 22px;
|
|
6314
6325
|
border-radius: 0 0 0 3px;
|
|
6315
6326
|
}
|
|
6316
|
-
[data-v-
|
|
6327
|
+
[data-v-5ce9d77a] .cm-gutters:before {
|
|
6317
6328
|
content: '';
|
|
6318
6329
|
position: absolute;
|
|
6319
6330
|
top: 2px;
|
|
@@ -6323,7 +6334,7 @@ to {
|
|
|
6323
6334
|
border-radius: var(--scalar-radius) 0 0 var(--scalar-radius);
|
|
6324
6335
|
background-color: var(--scalar-background-1);
|
|
6325
6336
|
}
|
|
6326
|
-
[data-v-
|
|
6337
|
+
[data-v-5ce9d77a] .cm-gutterElement {
|
|
6327
6338
|
font-family: var(--scalar-font-code) !important;
|
|
6328
6339
|
padding-left: 0px !important;
|
|
6329
6340
|
padding-right: 6px !important;
|
|
@@ -6332,23 +6343,22 @@ to {
|
|
|
6332
6343
|
justify-content: flex-end;
|
|
6333
6344
|
position: relative;
|
|
6334
6345
|
}
|
|
6335
|
-
[data-v-
|
|
6346
|
+
[data-v-5ce9d77a] .cm-lineNumbers .cm-gutterElement {
|
|
6336
6347
|
min-width: fit-content;
|
|
6337
6348
|
}
|
|
6338
|
-
[data-v-
|
|
6349
|
+
[data-v-5ce9d77a] .cm-gutter + .cm-gutter :not(.cm-foldGutter) .cm-gutterElement {
|
|
6339
6350
|
padding-left: 0 !important;
|
|
6340
6351
|
}
|
|
6341
|
-
[data-v-
|
|
6352
|
+
[data-v-5ce9d77a] .cm-scroller {
|
|
6342
6353
|
overflow: auto;
|
|
6343
6354
|
}
|
|
6344
|
-
[data-v-
|
|
6355
|
+
[data-v-5ce9d77a] .cm-lineWrapping .cm-line {
|
|
6345
6356
|
word-break: break-all;
|
|
6346
6357
|
}
|
|
6347
|
-
[data-v-
|
|
6358
|
+
[data-v-5ce9d77a] .cm-content.cm-lineWrapping {
|
|
6348
6359
|
white-space: pre-wrap;
|
|
6349
|
-
max-height: none;
|
|
6350
6360
|
}
|
|
6351
|
-
.line-wrapping[data-v-
|
|
6361
|
+
.line-wrapping[data-v-5ce9d77a]:focus-within .cm-content {
|
|
6352
6362
|
display: inline-table;
|
|
6353
6363
|
min-height: fit-content;
|
|
6354
6364
|
padding: 3px 6px;
|
|
@@ -6517,28 +6527,28 @@ to {
|
|
|
6517
6527
|
margin-left: 0.5px;
|
|
6518
6528
|
}
|
|
6519
6529
|
|
|
6520
|
-
[data-v-
|
|
6530
|
+
[data-v-bf90c7e1] .cm-content {
|
|
6521
6531
|
font-size: var(--scalar-small);
|
|
6522
6532
|
}
|
|
6523
6533
|
|
|
6524
|
-
[data-v-
|
|
6534
|
+
[data-v-ce270af2] .code-input-lite__editor {
|
|
6525
6535
|
background-color: transparent;
|
|
6526
6536
|
font-family: var(--scalar-font);
|
|
6527
6537
|
font-size: var(--scalar-small);
|
|
6528
6538
|
padding: 5px 8px;
|
|
6529
6539
|
}
|
|
6530
|
-
[data-v-
|
|
6540
|
+
[data-v-ce270af2] .scalar-pill:not(:last-of-type) {
|
|
6531
6541
|
margin-right: 0.15em;
|
|
6532
6542
|
}
|
|
6533
|
-
[data-v-
|
|
6543
|
+
[data-v-ce270af2] .scalar-pill:not(:first-of-type) {
|
|
6534
6544
|
margin-left: 0.5px;
|
|
6535
6545
|
}
|
|
6536
6546
|
/* Tailwind placeholder is busted */
|
|
6537
|
-
input[data-v-
|
|
6547
|
+
input[data-v-ce270af2]::placeholder {
|
|
6538
6548
|
color: var(--scalar-color-3);
|
|
6539
6549
|
}
|
|
6540
6550
|
/* we want our inputs to look like a password input but not be one */
|
|
6541
|
-
.scalar-password-input[data-v-
|
|
6551
|
+
.scalar-password-input[data-v-ce270af2] {
|
|
6542
6552
|
text-security: disc;
|
|
6543
6553
|
-webkit-text-security: disc;
|
|
6544
6554
|
-moz-text-security: disc;
|
|
@@ -6706,10 +6716,10 @@ to {
|
|
|
6706
6716
|
margin-top: 0;
|
|
6707
6717
|
}
|
|
6708
6718
|
|
|
6709
|
-
.address-bar-history-button[data-v-
|
|
6719
|
+
.address-bar-history-button[data-v-8704eaef]:hover {
|
|
6710
6720
|
background: var(--scalar-background-3);
|
|
6711
6721
|
}
|
|
6712
|
-
.address-bar-history-button[data-v-
|
|
6722
|
+
.address-bar-history-button[data-v-8704eaef]:focus-within {
|
|
6713
6723
|
background: var(--scalar-background-2);
|
|
6714
6724
|
}
|
|
6715
6725
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"names":[],"mappings":"AAw0BA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAA;AAG/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAA;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iDAAiD,CAAA;AACnF,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAML,KAAK,qBAAqB,EAE1B,KAAK,0BAA0B,EAChC,MAAM,yCAAyC,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAA;AACxG,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uDAAuD,CAAA;AAmC5F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD;;;;;;;;;;;;GAYG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAMzC,MAAM,MAAM,mBAAmB,GAAG;IAChC,kFAAkF;IAClF,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,gBAAgB;IAChB,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,uBAAuB;IACvB,QAAQ,EAAE,eAAe,CAAA;IACzB,4BAA4B;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,wBAAwB;IACxB,gBAAgB,EAAE,aAAa,EAAE,CAAA;IACjC,uBAAuB;IACvB,eAAe,EAAE,aAAa,EAAE,CAAA;IAChC,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,oDAAoD;IACpD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,mBAAmB;IACnB,WAAW,EAAE,gBAAgB,CAAA;IAC7B,oCAAoC;IACpC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB,oBAAoB;IACpB,MAAM,EAAE,YAAY,CAAA;IACpB,gCAAgC;IAChC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAA;IAC3B,gCAAgC;IAChC,cAAc,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC,yBAAyB,CAAC,CAAA;IACtE,mDAAmD;IACnD,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,sCAAsC;IACtC,UAAU,EAAE,UAAU,CAAA;IACtB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oBAAoB;IACpB,MAAM,CAAC,EAAE,SAAS,GAAG,eAAe,CAAA;IACpC,uBAAuB;IACvB,SAAS,EAAE,eAAe,CAAA;IAC1B,qFAAqF;IACrF,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAA;IAClB,2CAA2C;IAC3C,QAAQ,EAAE,QAAQ,CAAA;IAClB,wCAAwC;IACxC,eAAe,EAAE,qBAAqB,CAAA;IACtC,qBAAqB;IACrB,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,uBAAuB;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,qCAAqC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,8CAA8C;IAC9C,WAAW,EAAE,kBAAkB,CAAA;IAC/B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAA;IAChB,kCAAkC;IAClC,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,0CAA0C;IAC1C,uBAAuB,EAAE,0BAA0B,EAAE,CAAA;IACrD,4BAA4B;IAC5B,oBAAoB,EAAE,eAAe,CAAC,UAAU,CAAC,CAAA;IACjD,sBAAsB;IACtB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,sEAAsE;IACtE,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxD,6CAA6C;IAC7C,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAA;CAChC,CAAA;AACD,QAAA,MAAM,YAAY;;;;
|
|
1
|
+
{"version":3,"file":"OperationBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * OperationBlock\n *\n * Orchestrates the operation view by wiring together the Header, OperationBlock,\n * and ResponseBlock. Forwards user interactions to the workspace event bus and\n * passes through configuration such as auth, servers, plugins, and environment.\n * This component keeps the Operation page lean by centralizing event emission\n * and prop wiring between the blocks.\n *\n * Notable behavior:\n * - Uses operation['x-scalar-method'] and operation['x-scalar-path'] to provide\n * draft overrides for the UI when present.\n */\nexport default {\n name: 'OperationBlock',\n}\n\nexport type OperationBlockProps = {\n /** Keep execution and editing unavailable until the selected payload is ready. */\n externalExamplesPending?: boolean\n externalExamplesFailed?: boolean\n /** Event bus */\n eventBus: WorkspaceEventBus\n /** Application version */\n appVersion: string\n /** Openapi document */\n document: OpenApiDocument\n /** Openapi document slug */\n documentSlug: string\n /** Workspace cookies */\n workspaceCookies: XScalarCookie[]\n /** Document cookies */\n documentCookies: XScalarCookie[]\n /** Current request path */\n path: string\n /** Current request method */\n method: string\n /** Whether `path` identifies an OpenAPI webhook. */\n isWebhook?: boolean\n /** HTTP clients */\n httpClients: AvailableClients\n /** The history for the operation */\n history?: HistoryEntry[]\n /** Client layout */\n layout: ClientLayout\n /** Currently selected server */\n server: ServerObject | null\n /** Currently selected client */\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n /** Server list available for operation/document */\n servers: ServerObject[]\n /** Meta information for the server */\n serverMeta: ServerMeta\n /** Hides the client button on the header */\n hideClientButton?: boolean\n /** Client integration */\n integration?: string | null\n /** Openapi document url for `modal` mode to open the client app */\n documentUrl?: string\n /** Client source */\n source?: 'gitbook' | 'api-reference'\n /** Operation object */\n operation: OperationObject\n /** Operation before downloaded examples are overlaid, for parameter edit targets. */\n sourceOperation?: OperationObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Meta information for the auth update */\n authMeta: AuthMeta\n /** Document defined security schemes */\n securitySchemes: MergedSecuritySchemes\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Environment list */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n /** For environment variables in the inputs */\n environment: XScalarEnvironment\n /** The proxy URL for sending requests */\n proxyUrl: string\n /** Currently selected security */\n selectedSecurity: SelectedSecurity\n /** Currently selected security schemes */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Security requirements */\n securityRequirements: OpenApiDocument['security']\n /** Default headers */\n defaultHeaders: Record<string, string>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /** Subset of config options for the modal */\n options?: ModalProps['options']\n}\n</script>\n<script setup lang=\"ts\">\nimport { generateClientOptions } from '@scalar/blocks/code-example'\nimport { ScalarButton } from '@scalar/components/button'\nimport { ERRORS } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport { isForbiddenHttpMethod } from '@scalar/helpers/http/is-forbidden-http-method'\nimport {\n executeHook,\n executeResponseHook,\n type ClientPlugin,\n} from '@scalar/oas-utils/helpers'\nimport {\n AVAILABLE_CLIENTS,\n type AvailableClients,\n} from '@scalar/types/snippetz'\nimport { useClipboard } from '@scalar/use-hooks/useClipboard'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type { HistoryEntry } from '@scalar/workspace-store/entities/history/schema'\nimport type {\n AuthMeta,\n ServerMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n requestFactory,\n resolveExecutableRequestUrl,\n type MergedSecuritySchemes,\n type RequestPayload,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.2/strict/operation'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n toValue,\n watch,\n} from 'vue'\n\nimport ViewLayout from '@/components/ViewLayout/ViewLayout.vue'\nimport ViewLayoutContent from '@/components/ViewLayout/ViewLayoutContent.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport { harToFetchRequest } from '@/v2/blocks/operation-block/helpers/har-to-fetch-request'\nimport { harToFetchResponse } from '@/v2/blocks/operation-block/helpers/har-to-fetch-response'\nimport {\n getCookieRequestUrl,\n getResponseCookieActions,\n} from '@/v2/blocks/operation-block/helpers/persist-response-cookies'\nimport { getEnvironmentPersistenceActions } from '@/v2/blocks/operation-block/helpers/persist-script-environment'\nimport {\n getOperationExampleKey,\n isStreamingResponse,\n responseCache,\n} from '@/v2/blocks/operation-block/helpers/response-cache'\nimport {\n sendRequest,\n type ResponseInstance,\n} from '@/v2/blocks/operation-block/helpers/send-request'\nimport { validatePathParameters } from '@/v2/blocks/operation-block/helpers/validate-path-parameters'\nimport { RequestBlock } from '@/v2/blocks/request-block'\nimport { ResponseBlock } from '@/v2/blocks/response-block'\nimport { type History } from '@/v2/blocks/scalar-address-bar-block'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport Header from './components/Header.vue'\n\nconst {\n externalExamplesPending = false,\n externalExamplesFailed = false,\n authMeta,\n environment,\n eventBus,\n exampleKey,\n document,\n documentSlug,\n workspaceCookies = [],\n documentCookies = [],\n hideClientButton,\n httpClients = AVAILABLE_CLIENTS,\n history = [],\n layout,\n method,\n isWebhook = false,\n operation,\n sourceOperation,\n path,\n plugins = [],\n proxyUrl,\n requestBodyCompositionSelection,\n securitySchemes,\n selectedClient,\n server,\n servers,\n environments,\n options,\n activeEnvironment,\n serverMeta,\n selectedSecurity,\n selectedSecuritySchemes,\n securityRequirements,\n defaultHeaders,\n} = defineProps<OperationBlockProps>()\n\ndefineEmits<{ (e: 'retry:externalExamples'): void }>()\n\nconst { translate } = useLocalization()\n\n/** Hoist up client generation so it doesn't get re-generated on every operation */\nconst clientOptions = computed(() => generateClientOptions(httpClients))\n\nconst { toast } = useToasts()\nconst { copyToClipboard } = useClipboard()\n\n// Refs\nconst abortController = ref<AbortController | null>(null)\nconst response = ref<ResponseInstance | null>(null)\nconst requestError = ref<Error | null>(null)\nconst requestPayload = ref<RequestPayload | null>(null)\n\n/**\n * A webhook has no OpenAPI server, so its destination is the full URL the user\n * enters at runtime. The field holds that whole URL (not a server-relative path),\n * and the request is sent to it directly with no separate server base.\n */\nconst webhookUrl = ref('')\n\nwatch(\n [() => path, () => method, () => isWebhook],\n () => {\n webhookUrl.value = ''\n },\n { immediate: true },\n)\n\nconst requestPath = computed(() => (isWebhook ? webhookUrl.value : path))\nconst requestServer = computed<ServerObject | null>(() =>\n isWebhook ? null : server,\n)\n\n/** Cancel the request */\nconst cancelRequest = () => abortController.value?.abort(ERRORS.REQUEST_ABORTED)\n\n/**\n * Persist server-set cookies from a response into the document cookie jar.\n *\n * Scalar keeps its own cookie jar because browsers hide `Set-Cookie` from `fetch`.\n * Mirroring browser behavior, cookies are stored scoped to the request host and\n * path and removed when the server expires them, so a value like a Django CSRF\n * token stays available for later PUT/PATCH requests after a page reload.\n */\nconst persistResponseCookies = (sendResult: {\n response: ResponseInstance\n requestPayload: RequestPayload\n}) => {\n const actions = getResponseCookieActions({\n cookieHeaderKeys: sendResult.response.cookieHeaderKeys ?? [],\n documentCookies,\n requestUrl: getCookieRequestUrl(String(sendResult.requestPayload[0])),\n })\n\n for (const action of actions) {\n if (action.type === 'delete') {\n eventBus.emit('cookie:delete:cookie', {\n collectionType: 'document',\n cookieName: action.cookieName,\n index: action.index,\n })\n continue\n }\n\n eventBus.emit('cookie:upsert:cookie', {\n collectionType: 'document',\n payload: action.cookie,\n ...(action.index === undefined ? {} : { index: action.index }),\n })\n }\n}\n\n/**\n * Copy the executable URL — same pipeline as Send (`requestFactory` +\n * `resolveExecutableRequestUrl`), including security query params.\n */\nconst copyAddressBarUrl = async (): Promise<void> => {\n const { request } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies: [...workspaceCookies, ...documentCookies],\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n openapiVersion: document.openapi,\n requestBodyCompositionSelection,\n })\n\n await copyToClipboard(\n resolveExecutableRequestUrl(request, getEnvironmentVariables(environment)),\n )\n}\n\n/** Execute the current operation example */\nconst handleExecute = async () => {\n if (externalExamplesPending) return\n requestError.value = null\n eventBus.flushDebouncedEmits?.()\n // Source edits must reach the overlaid operation prop before building the request.\n await nextTick()\n\n if (isWebhook && !requestPath.value.trim()) {\n toast(translate('apiClient.operationBlock.webhookUrlRequired'), 'error')\n return\n }\n\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast(translate('apiClient.operationBlock.pathParametersRequired'), 'error')\n return\n }\n\n const globalCookies = [...workspaceCookies, ...documentCookies]\n\n const { request: requestBuilder } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies,\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n openapiVersion: document.openapi,\n requestBodyCompositionSelection,\n })\n\n // Stop any previous streaming response\n if (response.value && 'reader' in response.value) {\n response.value.reader.cancel()\n }\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Seed the script variable store with the active environment so pm.environment.get()\n // and pm.variables.get() resolve to the same values as {{…}} placeholders. Without\n // seeding, the store starts empty and every scripted read returns undefined.\n const seededEnvironment = getEnvironmentVariables(environment)\n variablesStore.setEnvironment?.(\n Object.entries(seededEnvironment).map(([key, value]) => ({ key, value })),\n )\n\n // Snapshot the persistence target at request start, alongside the seed. Persistence runs after\n // the request completes (awaits below), and the environment props are reactive — if the active\n // environment is switched mid-flight, or a concurrent request splices these arrays, reading\n // them at persist time would apply the script's writes to the wrong environment or resolve\n // workspace/document indexes against a shifted list. Copy the arrays (not just the reference)\n // so the seeded values and these targets stay fixed to the same point in time.\n const persistenceTarget = activeEnvironment\n ? {\n environmentName: activeEnvironment,\n mergedVariables: [...environment.variables],\n documentVariables: [\n ...(document['x-scalar-environments']?.[activeEnvironment]\n ?.variables ?? []),\n ],\n environmentExistsOnDocument: Boolean(\n document['x-scalar-environments']?.[activeEnvironment],\n ),\n }\n : null\n\n // Execute the beforeRequest hook (plugins receive RequestFactory, not fetch Request)\n await executeHook(\n {\n requestBuilder,\n document,\n operation,\n variablesStore,\n server: requestServer.value,\n customFetch: toValue(options)?.customFetch,\n },\n 'beforeRequest',\n plugins,\n )\n\n // Persist environment variables set by scripts (pm.environment.set / unset) back to the active\n // environment so they survive to the next request, mirroring the Environment tab. Scope and\n // index are resolved from the seed-time environment so updates mutate in place. Defined here so\n // it can run on every exit path after the pre-request scripts — including a build failure or a\n // failed send — so a pre-request set, like a token stored before a flaky call, is not lost.\n const persistScriptEnvironment = () => {\n if (!persistenceTarget) {\n return\n }\n\n const environmentActions = getEnvironmentPersistenceActions({\n ...persistenceTarget,\n seededVariables: seededEnvironment,\n scriptVariables: variablesStore.getEnvironment(),\n })\n\n for (const action of environmentActions) {\n if (action.type === 'delete') {\n eventBus.emit('environment:delete:environment-variable', {\n environmentName: action.environmentName,\n index: action.index,\n collectionType: action.collectionType,\n })\n } else {\n eventBus.emit('environment:upsert:environment-variable', {\n environmentName: action.environmentName,\n variable: action.variable,\n index: action.index,\n collectionType: action.collectionType,\n })\n }\n }\n }\n\n // Resolve {{…}} placeholders from the script store so pre-request pm.environment.set() and\n // unset() take effect on this request. The store was seeded from the active environment, so\n // it already holds every value spreading seededEnvironment would add — minus the keys a script\n // unset, which must stay dropped (an object spread cannot remove them again).\n const envVariables = variablesStore.getVariables()\n\n // Build the fetch Request after hooks may have mutated the factory\n const built = buildRequest(requestBuilder, {\n envVariables,\n allowMissingRequestServerBase: layout === 'modal',\n })\n if (!built.ok) {\n // Save any pre-request script writes before bailing out on a build failure.\n persistScriptEnvironment()\n toast(built.message ?? built.error, 'error')\n return\n }\n\n // Check the final method because pre-request scripts can change it.\n const requestMethod = built.data.requestPayload[1].method ?? 'GET'\n if (isForbiddenHttpMethod(requestMethod)) {\n persistScriptEnvironment()\n toast(\n translate('apiClient.operationBlock.forbiddenMethod', {\n method: requestMethod.toUpperCase(),\n }),\n 'error',\n )\n return\n }\n\n // Store the abort controller for cancellation\n abortController.value = built.data.controller\n\n // Build the fetch Request once so the requestBuilt hook observes the exact bytes that are\n // sent. Rebuilding it later would generate a different multipart boundary, which breaks\n // plugins that hash the body (for example, request signing).\n const request = buildSafeBodyRequest(...built.data.requestPayload)\n\n // Execute the requestBuilt hook (plugins receive the exact fetch Request that will be sent)\n await executeHook(\n {\n request,\n requestBuilder,\n document,\n operation,\n variablesStore,\n },\n 'requestBuilt',\n plugins,\n )\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:sent', {\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n /** Execute the request */\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: built.data.isUsingProxy,\n requestPayload: built.data.requestPayload,\n request,\n plugins,\n customFetch: toValue(options)?.customFetch,\n onResponseReceived: async (response, responseDuration) => {\n const result = await executeResponseHook(\n {\n response,\n responseDuration,\n requestBuilder,\n request: buildSafeBodyRequest(...built.data.requestPayload),\n document,\n operation,\n variablesStore,\n },\n plugins,\n )\n return result.response\n },\n })\n\n // Save script environment writes (pre-request and, on success, post-response) back to the\n // active environment. Runs even when the send fails so a pre-request set is not lost.\n persistScriptEnvironment()\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:complete', {\n payload: sendResult\n ? {\n response: sendResult.originalResponse.clone(),\n requestPayload: sendResult.requestPayload,\n duration: sendResult.response.duration,\n timestamp: sendResult.timestamp,\n }\n : undefined,\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n if (sendError) {\n // Cancellation also happens when navigating away; keep the new operation intact.\n if (built.data.controller.signal.aborted) {\n if (abortController.value === built.data.controller) {\n abortController.value = null\n }\n return\n }\n requestError.value = sendError\n // clean up the response and request\n response.value = null\n requestPayload.value = null\n abortController.value = null\n\n toast(sendError.message, 'error')\n return\n }\n\n // Store the response\n response.value = sendResult.response\n requestPayload.value = sendResult.requestPayload\n\n // Persist server-set cookies into the document jar so values like a CSRF token\n // survive a page reload and get replayed on the next request, like a browser would.\n persistResponseCookies(sendResult)\n\n // Cache non-streaming responses so they can be restored when navigating back\n if (!isStreamingResponse(sendResult.response)) {\n responseCache.set(getOperationExampleKey(method, path, exampleKey), {\n response: sendResult.response,\n requestPayload: sendResult.requestPayload,\n })\n }\n}\n\nonMounted(() => {\n eventBus.on('operation:send:request:hotkey', handleExecute)\n eventBus.on('operation:cancel:request', cancelRequest)\n eventBus.on('copy-url:address-bar', copyAddressBarUrl)\n\n // Let plugins warm up per-operation resources (e.g. the scripts sandbox) so the first request\n // does not pay their cold-start cost.\n void executeHook({ document, operation }, 'onRequestMount', plugins)\n})\nonBeforeUnmount(() => {\n eventBus.off('operation:send:request:hotkey', handleExecute)\n eventBus.off('operation:cancel:request', cancelRequest)\n eventBus.off('copy-url:address-bar', copyAddressBarUrl)\n})\n\nconst operationHistory = computed<History[]>(() =>\n history\n .map((entry) => ({\n method: entry.request.method as string,\n path: entry.request.url,\n duration: entry.time,\n status: entry.response.status,\n }))\n .reverse(),\n)\n\nconst handleSelectHistoryItem = ({ index }: { index: number }) => {\n const transformedIndex = (history.length ?? 0) - index - 1\n const historyItem = history[transformedIndex]\n if (!historyItem) {\n return\n }\n\n const navigate = () =>\n eventBus.emit('ui:navigate', {\n page: 'example',\n method,\n path,\n exampleName: 'draft',\n callback: (status) => {\n // Do not replace the response if the navigation was not successful\n if (status !== 'success') {\n return\n }\n // Reconstruct the response\n const fetchResponse = harToFetchResponse({\n harResponse: historyItem.response,\n url: historyItem.request.url,\n method,\n path,\n duration: historyItem.time,\n })\n\n // Reconstruct the request\n const fetchRequest = harToFetchRequest({\n harRequest: historyItem.request,\n })\n\n // Update the response and request\n requestError.value = null\n response.value = fetchResponse\n requestPayload.value = fetchRequest\n },\n })\n\n eventBus.emit('operation:reload:history', {\n meta: {\n path,\n method,\n },\n index: transformedIndex,\n callback: navigate,\n })\n}\n\nconst handleNavigateSettings = () => {\n eventBus.emit('ui:navigate', {\n page: 'operation',\n path: 'overview',\n operationPath: path,\n method,\n })\n}\n\n/**\n * When the path, method, or example key changes, restore the response panel\n * for the new operation from the best available source:\n *\n * 1. `responseCache` — in-memory, populated on every successful send.\n * Has the live response object (including streams) so it wins.\n * 2. `history` — persisted in the workspace store. Used as a fallback when\n * the in-memory cache is empty (page reload, fresh app session, etc.)\n * so navigating to an operation that has been called before shows the\n * last response instead of an empty panel.\n * 3. Otherwise clear.\n *\n * Only the response is restored from history — the user's request inputs are\n * left alone, so we never silently overwrite an in-progress draft.\n */\nwatch(\n [() => path, () => method, () => exampleKey],\n ([newPath, newMethod, newExampleKey]) => {\n requestError.value = null\n const cached = responseCache.get(\n getOperationExampleKey(newMethod, newPath, newExampleKey),\n )\n\n if (cached) {\n response.value = cached.response\n requestPayload.value = cached.requestPayload\n } else {\n // History is keyed only by document/path/method but each entry carries\n // the example it came from, so we walk from the end and pick the most\n // recent entry that matches the active example. Otherwise a cache miss\n // on example B would restore example A's response. Only runs on a\n // cache miss — the common case (in-session navigation) skips it.\n const latest = (() => {\n for (let i = history.length - 1; i >= 0; i--) {\n const entry = history[i]\n if (entry?.meta.example === newExampleKey) {\n return entry\n }\n }\n return undefined\n })()\n\n if (latest) {\n response.value = harToFetchResponse({\n harResponse: latest.response,\n url: latest.request.url,\n method: newMethod,\n path: newPath,\n duration: latest.time,\n })\n requestPayload.value = null\n } else {\n response.value = null\n requestPayload.value = null\n }\n }\n\n // Cancel any in-flight request\n cancelRequest()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n // We cancel the request if the component is unmounted\n cancelRequest()\n})\n</script>\n<template>\n <div class=\"bg-b-1 flex h-full flex-col\">\n <div\n class=\"lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0\">\n <!-- Address Bar -->\n <Header\n :activeEnvironment\n :documentSlug\n :documentUrl\n :environment\n :environments\n :eventBus\n :exampleKey\n :executionDisabled=\"externalExamplesPending\"\n :hideClientButton\n :history=\"operationHistory\"\n :integration\n :isWebhook\n :layout\n :method\n :path=\"requestPath\"\n :server=\"requestServer\"\n :serverMeta\n :servers\n :source\n @execute=\"handleExecute\"\n @navigate:settings=\"handleNavigateSettings\"\n @select:history:item=\"handleSelectHistoryItem\"\n @update:webhook-url=\"(value) => (webhookUrl = value)\" />\n </div>\n\n <ViewLayout class=\"border-t\">\n <ViewLayoutContent class=\"flex-1\">\n <!-- Request Section -->\n <ViewLayoutSection\n v-if=\"externalExamplesPending\"\n aria-label=\"Request\">\n <template #title>Request</template>\n <div\n class=\"text-c-2 p-4\"\n role=\"status\">\n <template v-if=\"externalExamplesFailed\">\n Could not load this example.\n <ScalarButton\n size=\"sm\"\n variant=\"ghost\"\n @click=\"$emit('retry:externalExamples')\">\n Retry\n </ScalarButton>\n </template>\n <template v-else>Loading example…</template>\n </div>\n </ViewLayoutSection>\n <RequestBlock\n v-else\n :authMeta\n :clientOptions\n :defaultHeaders\n :defaultRequestBodyView=\"\n document['x-scalar-default-request-body-view']\n \"\n :documentCookies\n :documentSlug\n :environment\n :eventBus\n :exampleKey\n :layout\n :method\n :openapiVersion=\"document.openapi\"\n :operation\n :options=\"toValue(options)\"\n :path=\"requestPath\"\n :plugins\n :proxyUrl\n :requestBodyCompositionSelection\n :securityRequirements\n :securitySchemes\n :selectedClient\n :selectedSecurity\n :selectedSecuritySchemes\n :server=\"requestServer\"\n :sourceOperation\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :executionDisabled=\"externalExamplesPending\"\n :layout\n :plugins\n :requestError\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"OperationBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * OperationBlock\n *\n * Orchestrates the operation view by wiring together the Header, OperationBlock,\n * and ResponseBlock. Forwards user interactions to the workspace event bus and\n * passes through configuration such as auth, servers, plugins, and environment.\n * This component keeps the Operation page lean by centralizing event emission\n * and prop wiring between the blocks.\n *\n * Notable behavior:\n * - Uses operation['x-scalar-method'] and operation['x-scalar-path'] to provide\n * draft overrides for the UI when present.\n */\nexport default {\n name: 'OperationBlock',\n}\n\nexport type OperationBlockProps = {\n /** Keep execution and editing unavailable until the selected payload is ready. */\n externalExamplesPending?: boolean\n externalExamplesFailed?: boolean\n /** Event bus */\n eventBus: WorkspaceEventBus\n /** Application version */\n appVersion: string\n /** Openapi document */\n document: OpenApiDocument\n /** Openapi document slug */\n documentSlug: string\n /** Workspace cookies */\n workspaceCookies: XScalarCookie[]\n /** Document cookies */\n documentCookies: XScalarCookie[]\n /** Current request path */\n path: string\n /** Current request method */\n method: string\n /** Whether `path` identifies an OpenAPI webhook. */\n isWebhook?: boolean\n /** HTTP clients */\n httpClients: AvailableClients\n /** The history for the operation */\n history?: HistoryEntry[]\n /** Client layout */\n layout: ClientLayout\n /** Currently selected server */\n server: ServerObject | null\n /** Currently selected client */\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n /** Server list available for operation/document */\n servers: ServerObject[]\n /** Meta information for the server */\n serverMeta: ServerMeta\n /** Hides the client button on the header */\n hideClientButton?: boolean\n /** Client integration */\n integration?: string | null\n /** Openapi document url for `modal` mode to open the client app */\n documentUrl?: string\n /** Client source */\n source?: 'gitbook' | 'api-reference'\n /** Operation object */\n operation: OperationObject\n /** Operation before downloaded examples are overlaid, for parameter edit targets. */\n sourceOperation?: OperationObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Meta information for the auth update */\n authMeta: AuthMeta\n /** Document defined security schemes */\n securitySchemes: MergedSecuritySchemes\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Environment list */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n /** For environment variables in the inputs */\n environment: XScalarEnvironment\n /** The proxy URL for sending requests */\n proxyUrl: string\n /** Currently selected security */\n selectedSecurity: SelectedSecurity\n /** Currently selected security schemes */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Security requirements */\n securityRequirements: OpenApiDocument['security']\n /** Default headers */\n defaultHeaders: Record<string, string>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /** Subset of config options for the modal */\n options?: ModalProps['options']\n}\n</script>\n<script setup lang=\"ts\">\nimport { generateClientOptions } from '@scalar/blocks/code-example'\nimport { ScalarButton } from '@scalar/components/button'\nimport { ERRORS } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport { isForbiddenHttpMethod } from '@scalar/helpers/http/is-forbidden-http-method'\nimport {\n executeHook,\n executeResponseHook,\n type ClientPlugin,\n} from '@scalar/oas-utils/helpers'\nimport {\n AVAILABLE_CLIENTS,\n type AvailableClients,\n} from '@scalar/types/snippetz'\nimport { useClipboard } from '@scalar/use-hooks/useClipboard'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type { HistoryEntry } from '@scalar/workspace-store/entities/history/schema'\nimport type {\n AuthMeta,\n ServerMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n requestFactory,\n resolveExecutableRequestUrl,\n type MergedSecuritySchemes,\n type RequestPayload,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.2/strict/operation'\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n toValue,\n watch,\n} from 'vue'\n\nimport ViewLayout from '@/components/ViewLayout/ViewLayout.vue'\nimport ViewLayoutContent from '@/components/ViewLayout/ViewLayoutContent.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport { harToFetchRequest } from '@/v2/blocks/operation-block/helpers/har-to-fetch-request'\nimport { harToFetchResponse } from '@/v2/blocks/operation-block/helpers/har-to-fetch-response'\nimport {\n getCookieRequestUrl,\n getResponseCookieActions,\n} from '@/v2/blocks/operation-block/helpers/persist-response-cookies'\nimport { getEnvironmentPersistenceActions } from '@/v2/blocks/operation-block/helpers/persist-script-environment'\nimport {\n getOperationExampleKey,\n isStreamingResponse,\n responseCache,\n} from '@/v2/blocks/operation-block/helpers/response-cache'\nimport {\n sendRequest,\n type ResponseInstance,\n} from '@/v2/blocks/operation-block/helpers/send-request'\nimport { validatePathParameters } from '@/v2/blocks/operation-block/helpers/validate-path-parameters'\nimport { RequestBlock } from '@/v2/blocks/request-block'\nimport { ResponseBlock } from '@/v2/blocks/response-block'\nimport { type History } from '@/v2/blocks/scalar-address-bar-block'\nimport { useLocalization } from '@/v2/features/localization'\nimport type { ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport Header from './components/Header.vue'\n\nconst {\n externalExamplesPending = false,\n externalExamplesFailed = false,\n authMeta,\n environment,\n eventBus,\n exampleKey,\n document,\n documentSlug,\n workspaceCookies = [],\n documentCookies = [],\n hideClientButton,\n httpClients = AVAILABLE_CLIENTS,\n history = [],\n layout,\n method,\n isWebhook = false,\n operation,\n sourceOperation,\n path,\n plugins = [],\n proxyUrl,\n requestBodyCompositionSelection,\n securitySchemes,\n selectedClient,\n server,\n servers,\n environments,\n options,\n activeEnvironment,\n serverMeta,\n selectedSecurity,\n selectedSecuritySchemes,\n securityRequirements,\n defaultHeaders,\n} = defineProps<OperationBlockProps>()\n\ndefineEmits<{ (e: 'retry:externalExamples'): void }>()\n\nconst { translate } = useLocalization()\n\n/** Hoist up client generation so it doesn't get re-generated on every operation */\nconst clientOptions = computed(() => generateClientOptions(httpClients))\n\nconst { toast } = useToasts()\nconst { copyToClipboard } = useClipboard()\n\n// Refs\nconst abortController = ref<AbortController | null>(null)\nconst response = ref<ResponseInstance | null>(null)\nconst requestError = ref<Error | null>(null)\nconst requestPayload = ref<RequestPayload | null>(null)\n\n/**\n * A webhook has no OpenAPI server, so its destination is the full URL the user\n * enters at runtime. The field holds that whole URL (not a server-relative path),\n * and the request is sent to it directly with no separate server base.\n */\nconst webhookUrl = ref('')\n\nwatch(\n [() => path, () => method, () => isWebhook],\n () => {\n webhookUrl.value = ''\n },\n { immediate: true },\n)\n\nconst requestPath = computed(() => (isWebhook ? webhookUrl.value : path))\nconst requestServer = computed<ServerObject | null>(() =>\n isWebhook ? null : server,\n)\n\n/** Cancel the request */\nconst cancelRequest = () => abortController.value?.abort(ERRORS.REQUEST_ABORTED)\n\n/**\n * Persist server-set cookies from a response into the document cookie jar.\n *\n * Scalar keeps its own cookie jar because browsers hide `Set-Cookie` from `fetch`.\n * Mirroring browser behavior, cookies are stored scoped to the request host and\n * path and removed when the server expires them, so a value like a Django CSRF\n * token stays available for later PUT/PATCH requests after a page reload.\n */\nconst persistResponseCookies = (sendResult: {\n response: ResponseInstance\n requestPayload: RequestPayload\n}) => {\n const actions = getResponseCookieActions({\n cookieHeaderKeys: sendResult.response.cookieHeaderKeys ?? [],\n documentCookies,\n requestUrl: getCookieRequestUrl(String(sendResult.requestPayload[0])),\n })\n\n for (const action of actions) {\n if (action.type === 'delete') {\n eventBus.emit('cookie:delete:cookie', {\n collectionType: 'document',\n cookieName: action.cookieName,\n index: action.index,\n })\n continue\n }\n\n eventBus.emit('cookie:upsert:cookie', {\n collectionType: 'document',\n payload: action.cookie,\n ...(action.index === undefined ? {} : { index: action.index }),\n })\n }\n}\n\n/**\n * Copy the executable URL — same pipeline as Send (`requestFactory` +\n * `resolveExecutableRequestUrl`), including security query params.\n */\nconst copyAddressBarUrl = async (): Promise<void> => {\n const { request } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies: [...workspaceCookies, ...documentCookies],\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n openapiVersion: document.openapi,\n requestBodyCompositionSelection,\n })\n\n await copyToClipboard(\n resolveExecutableRequestUrl(request, getEnvironmentVariables(environment)),\n )\n}\n\n/** Execute the current operation example */\nconst handleExecute = async () => {\n if (externalExamplesPending) return\n requestError.value = null\n eventBus.flushDebouncedEmits?.()\n // Source edits must reach the overlaid operation prop before building the request.\n await nextTick()\n\n if (isWebhook && !requestPath.value.trim()) {\n toast(translate('apiClient.operationBlock.webhookUrlRequired'), 'error')\n return\n }\n\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast(translate('apiClient.operationBlock.pathParametersRequired'), 'error')\n return\n }\n\n const globalCookies = [...workspaceCookies, ...documentCookies]\n\n const { request: requestBuilder } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies,\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n openapiVersion: document.openapi,\n requestBodyCompositionSelection,\n })\n\n // Stop any previous streaming response\n if (response.value && 'reader' in response.value) {\n response.value.reader.cancel()\n }\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Seed the script variable store with the active environment so pm.environment.get()\n // and pm.variables.get() resolve to the same values as {{…}} placeholders. Without\n // seeding, the store starts empty and every scripted read returns undefined.\n const seededEnvironment = getEnvironmentVariables(environment)\n variablesStore.setEnvironment?.(\n Object.entries(seededEnvironment).map(([key, value]) => ({ key, value })),\n )\n\n // Snapshot the persistence target at request start, alongside the seed. Persistence runs after\n // the request completes (awaits below), and the environment props are reactive — if the active\n // environment is switched mid-flight, or a concurrent request splices these arrays, reading\n // them at persist time would apply the script's writes to the wrong environment or resolve\n // workspace/document indexes against a shifted list. Copy the arrays (not just the reference)\n // so the seeded values and these targets stay fixed to the same point in time.\n const persistenceTarget = activeEnvironment\n ? {\n environmentName: activeEnvironment,\n mergedVariables: [...environment.variables],\n documentVariables: [\n ...(document['x-scalar-environments']?.[activeEnvironment]\n ?.variables ?? []),\n ],\n environmentExistsOnDocument: Boolean(\n document['x-scalar-environments']?.[activeEnvironment],\n ),\n }\n : null\n\n // Execute the beforeRequest hook (plugins receive RequestFactory, not fetch Request)\n await executeHook(\n {\n requestBuilder,\n document,\n operation,\n variablesStore,\n server: requestServer.value,\n customFetch: toValue(options)?.customFetch,\n },\n 'beforeRequest',\n plugins,\n )\n\n // Persist environment variables set by scripts (pm.environment.set / unset) back to the active\n // environment so they survive to the next request, mirroring the Environment tab. Scope and\n // index are resolved from the seed-time environment so updates mutate in place. Defined here so\n // it can run on every exit path after the pre-request scripts — including a build failure or a\n // failed send — so a pre-request set, like a token stored before a flaky call, is not lost.\n const persistScriptEnvironment = () => {\n if (!persistenceTarget) {\n return\n }\n\n const environmentActions = getEnvironmentPersistenceActions({\n ...persistenceTarget,\n seededVariables: seededEnvironment,\n scriptVariables: variablesStore.getEnvironment(),\n })\n\n for (const action of environmentActions) {\n if (action.type === 'delete') {\n eventBus.emit('environment:delete:environment-variable', {\n environmentName: action.environmentName,\n index: action.index,\n collectionType: action.collectionType,\n })\n } else {\n eventBus.emit('environment:upsert:environment-variable', {\n environmentName: action.environmentName,\n variable: action.variable,\n index: action.index,\n collectionType: action.collectionType,\n })\n }\n }\n }\n\n // Resolve {{…}} placeholders from the script store so pre-request pm.environment.set() and\n // unset() take effect on this request. The store was seeded from the active environment, so\n // it already holds every value spreading seededEnvironment would add — minus the keys a script\n // unset, which must stay dropped (an object spread cannot remove them again).\n const envVariables = variablesStore.getVariables()\n\n // Build the fetch Request after hooks may have mutated the factory\n const built = buildRequest(requestBuilder, {\n envVariables,\n allowMissingRequestServerBase: layout === 'modal',\n })\n if (!built.ok) {\n // Save any pre-request script writes before bailing out on a build failure.\n persistScriptEnvironment()\n toast(built.message ?? built.error, 'error')\n return\n }\n\n // Check the final method because pre-request scripts can change it.\n const requestMethod = built.data.requestPayload[1].method ?? 'GET'\n if (isForbiddenHttpMethod(requestMethod)) {\n persistScriptEnvironment()\n toast(\n translate('apiClient.operationBlock.forbiddenMethod', {\n method: requestMethod.toUpperCase(),\n }),\n 'error',\n )\n return\n }\n\n // Store the abort controller for cancellation\n abortController.value = built.data.controller\n\n // Build the fetch Request once so the requestBuilt hook observes the exact bytes that are\n // sent. Rebuilding it later would generate a different multipart boundary, which breaks\n // plugins that hash the body (for example, request signing).\n const request = buildSafeBodyRequest(...built.data.requestPayload)\n\n // Execute the requestBuilt hook (plugins receive the exact fetch Request that will be sent)\n await executeHook(\n {\n request,\n requestBuilder,\n document,\n operation,\n variablesStore,\n },\n 'requestBuilt',\n plugins,\n )\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:sent', {\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n /** Execute the request */\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: built.data.isUsingProxy,\n requestPayload: built.data.requestPayload,\n request,\n plugins,\n customFetch: toValue(options)?.customFetch,\n onResponseReceived: async (response, responseDuration) => {\n const result = await executeResponseHook(\n {\n response,\n responseDuration,\n requestBuilder,\n request: buildSafeBodyRequest(...built.data.requestPayload),\n document,\n operation,\n variablesStore,\n },\n plugins,\n )\n return result.response\n },\n })\n\n // Save script environment writes (pre-request and, on success, post-response) back to the\n // active environment. Runs even when the send fails so a pre-request set is not lost.\n persistScriptEnvironment()\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:complete', {\n payload: sendResult\n ? {\n response: sendResult.originalResponse.clone(),\n requestPayload: sendResult.requestPayload,\n duration: sendResult.response.duration,\n timestamp: sendResult.timestamp,\n }\n : undefined,\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n if (sendError) {\n // Cancellation also happens when navigating away; keep the new operation intact.\n if (built.data.controller.signal.aborted) {\n if (abortController.value === built.data.controller) {\n abortController.value = null\n }\n return\n }\n requestError.value = sendError\n // clean up the response and request\n response.value = null\n requestPayload.value = null\n abortController.value = null\n\n toast(sendError.message, 'error')\n return\n }\n\n // Store the response\n response.value = sendResult.response\n requestPayload.value = sendResult.requestPayload\n\n // Persist server-set cookies into the document jar so values like a CSRF token\n // survive a page reload and get replayed on the next request, like a browser would.\n persistResponseCookies(sendResult)\n\n // Cache non-streaming responses so they can be restored when navigating back\n if (!isStreamingResponse(sendResult.response)) {\n responseCache.set(getOperationExampleKey(method, path, exampleKey), {\n response: sendResult.response,\n requestPayload: sendResult.requestPayload,\n })\n }\n}\n\nonMounted(() => {\n eventBus.on('operation:send:request:hotkey', handleExecute)\n eventBus.on('operation:cancel:request', cancelRequest)\n eventBus.on('copy-url:address-bar', copyAddressBarUrl)\n\n // Let plugins warm up per-operation resources (e.g. the scripts sandbox) so the first request\n // does not pay their cold-start cost.\n void executeHook({ document, operation }, 'onRequestMount', plugins)\n})\nonBeforeUnmount(() => {\n eventBus.off('operation:send:request:hotkey', handleExecute)\n eventBus.off('operation:cancel:request', cancelRequest)\n eventBus.off('copy-url:address-bar', copyAddressBarUrl)\n})\n\nconst operationHistory = computed<History[]>(() =>\n history\n .map((entry) => ({\n method: entry.request.method as string,\n path: entry.request.url,\n duration: entry.time,\n status: entry.response.status,\n }))\n .reverse(),\n)\n\nconst handleSelectHistoryItem = ({ index }: { index: number }) => {\n const transformedIndex = (history.length ?? 0) - index - 1\n const historyItem = history[transformedIndex]\n if (!historyItem) {\n return\n }\n\n const navigate = () =>\n eventBus.emit('ui:navigate', {\n page: 'example',\n method,\n path,\n exampleName: 'draft',\n callback: (status) => {\n // Do not replace the response if the navigation was not successful\n if (status !== 'success') {\n return\n }\n // Reconstruct the response\n const fetchResponse = harToFetchResponse({\n harResponse: historyItem.response,\n url: historyItem.request.url,\n method,\n path,\n duration: historyItem.time,\n })\n\n // Reconstruct the request\n const fetchRequest = harToFetchRequest({\n harRequest: historyItem.request,\n })\n\n // Update the response and request\n requestError.value = null\n response.value = fetchResponse\n requestPayload.value = fetchRequest\n },\n })\n\n eventBus.emit('operation:reload:history', {\n meta: {\n path,\n method,\n },\n index: transformedIndex,\n callback: navigate,\n })\n}\n\nconst handleNavigateSettings = () => {\n eventBus.emit('ui:navigate', {\n page: 'operation',\n path: 'overview',\n operationPath: path,\n method,\n })\n}\n\n/**\n * When the path, method, or example key changes, restore the response panel\n * for the new operation from the best available source:\n *\n * 1. `responseCache` — in-memory, populated on every successful send.\n * Has the live response object (including streams) so it wins.\n * 2. `history` — persisted in the workspace store. Used as a fallback when\n * the in-memory cache is empty (page reload, fresh app session, etc.)\n * so navigating to an operation that has been called before shows the\n * last response instead of an empty panel.\n * 3. Otherwise clear.\n *\n * Only the response is restored from history — the user's request inputs are\n * left alone, so we never silently overwrite an in-progress draft.\n */\nwatch(\n [() => path, () => method, () => exampleKey],\n ([newPath, newMethod, newExampleKey]) => {\n requestError.value = null\n const cached = responseCache.get(\n getOperationExampleKey(newMethod, newPath, newExampleKey),\n )\n\n if (cached) {\n response.value = cached.response\n requestPayload.value = cached.requestPayload\n } else {\n // History is keyed only by document/path/method but each entry carries\n // the example it came from, so we walk from the end and pick the most\n // recent entry that matches the active example. Otherwise a cache miss\n // on example B would restore example A's response. Only runs on a\n // cache miss — the common case (in-session navigation) skips it.\n const latest = (() => {\n for (let i = history.length - 1; i >= 0; i--) {\n const entry = history[i]\n if (entry?.meta.example === newExampleKey) {\n return entry\n }\n }\n return undefined\n })()\n\n if (latest) {\n response.value = harToFetchResponse({\n harResponse: latest.response,\n url: latest.request.url,\n method: newMethod,\n path: newPath,\n duration: latest.time,\n })\n requestPayload.value = null\n } else {\n response.value = null\n requestPayload.value = null\n }\n }\n\n // Cancel any in-flight request\n cancelRequest()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n // We cancel the request if the component is unmounted\n cancelRequest()\n})\n</script>\n<template>\n <div class=\"bg-b-1 flex h-full min-w-0 flex-col\">\n <div\n class=\"lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0\">\n <!-- Address Bar -->\n <Header\n :activeEnvironment\n :documentSlug\n :documentUrl\n :environment\n :environments\n :eventBus\n :exampleKey\n :executionDisabled=\"externalExamplesPending\"\n :hideClientButton\n :history=\"operationHistory\"\n :integration\n :isWebhook\n :layout\n :method\n :path=\"requestPath\"\n :server=\"requestServer\"\n :serverMeta\n :servers\n :source\n @execute=\"handleExecute\"\n @navigate:settings=\"handleNavigateSettings\"\n @select:history:item=\"handleSelectHistoryItem\"\n @update:webhook-url=\"(value) => (webhookUrl = value)\" />\n </div>\n\n <ViewLayout class=\"border-t\">\n <ViewLayoutContent class=\"flex-1\">\n <!-- Request Section -->\n <ViewLayoutSection\n v-if=\"externalExamplesPending\"\n aria-label=\"Request\">\n <template #title>Request</template>\n <div\n class=\"text-c-2 p-4\"\n role=\"status\">\n <template v-if=\"externalExamplesFailed\">\n Could not load this example.\n <ScalarButton\n size=\"sm\"\n variant=\"ghost\"\n @click=\"$emit('retry:externalExamples')\">\n Retry\n </ScalarButton>\n </template>\n <template v-else>Loading example…</template>\n </div>\n </ViewLayoutSection>\n <RequestBlock\n v-else\n :authMeta\n :clientOptions\n :defaultHeaders\n :defaultRequestBodyView=\"\n document['x-scalar-default-request-body-view']\n \"\n :documentCookies\n :documentSlug\n :environment\n :eventBus\n :exampleKey\n :layout\n :method\n :openapiVersion=\"document.openapi\"\n :operation\n :options=\"toValue(options)\"\n :path=\"requestPath\"\n :plugins\n :proxyUrl\n :requestBodyCompositionSelection\n :securityRequirements\n :securitySchemes\n :selectedClient\n :selectedSecurity\n :selectedSecuritySchemes\n :server=\"requestServer\"\n :sourceOperation\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :executionDisabled=\"externalExamplesPending\"\n :layout\n :plugins\n :requestError\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -25,7 +25,7 @@ import { AVAILABLE_CLIENTS } from "@scalar/types/snippetz";
|
|
|
25
25
|
import { useClipboard } from "@scalar/use-hooks/useClipboard";
|
|
26
26
|
import { useToasts } from "@scalar/use-toasts";
|
|
27
27
|
//#region src/v2/blocks/operation-block/OperationBlock.vue?vue&type=script&setup=true&lang.ts
|
|
28
|
-
var _hoisted_1 = { class: "bg-b-1 flex h-full flex-col" };
|
|
28
|
+
var _hoisted_1 = { class: "bg-b-1 flex h-full min-w-0 flex-col" };
|
|
29
29
|
var _hoisted_2 = { class: "lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0" };
|
|
30
30
|
var _hoisted_3 = {
|
|
31
31
|
class: "text-c-2 p-4",
|