Skip to content

Conversation

@hanspagel
Copy link
Member

@hanspagel hanspagel commented Oct 7, 2025

Tasks

  • lots of conflicts, I’ll split up this PR into just the schemas/types and ff with the remaining stuff

Problem

Currently, we support OpenAPI documents, that's great. But what if someone wants to load an AsyncAPI document? 🤔 It seems so similar … so what if we add support for it?

Solution

This PR:

  • adds AsyncAPI 3.0 schemas
  • the workspace store returns OpenApiDocument | AsyncApiDocument types instead of just OpenApiDocument
  • adds helpers to narrow down the type
  • adds a little bit of type-narrowing with those helpers where necessary

Out of scope

  • the navigation is wrong, that’s for another PR
  • there’s basically no rendering for AsyncAPI documents, that’s for another PR

Checklist

I've gone through the following:

  • I've added an explanation why this change is needed.
  • I've added a changeset (pnpm changeset).
  • I've added tests for the regression or new feature.
  • I've updated the documentation.

Note

Add AsyncAPI 3.0 support to the workspace store (schemas, navigation, server/client), gate OpenAPI-only UI/search paths, and update tests/docs.

  • Workspace Store:
    • Schemas: Introduce comprehensive AsyncApiDocument 3.0 schema set and navigation types; add isOpenApiDocument/isAsyncApiDocument type guards; support mixed ApiDefinition.
    • Navigation: Add createAsyncApiNavigation with channel/operation/message traversal.
    • Server (SSR/Static): Externalize AsyncAPI operations; generate chunks for AsyncAPI; support mixed OpenAPI/AsyncAPI; update loaders and exports.
    • Client: Accept AsyncAPI or OpenAPI, preserve original version (x-original-asyncapi-version), conditional navigation generation, config/override handling, and export/load logic.
    • Mutators: Make request/server/security mutators tolerant; scope to OpenAPI where applicable.
  • API Reference:
    • Content/Models: Guard OpenAPI-only features (servers, clients, models) via type checks.
    • Search: Accept OpenApiDocument | AsyncApiDocument; build search index only for OpenAPI.
  • Tests/Docs:
    • Add extensive AsyncAPI tests (client/server/navigation), update existing tests for new types, and expand README with AsyncAPI usage.
  • Misc:
    • Update re-exports, add sample AsyncAPI source, and changeset for minor release.

Written by Cursor Bugbot for commit 239f1c5. This will update automatically on new commits. Configure here.

@hanspagel hanspagel requested a review from DemonHa October 7, 2025 14:08
@hanspagel hanspagel self-assigned this Oct 7, 2025
@changeset-bot
Copy link

changeset-bot bot commented Oct 7, 2025

🦋 Changeset detected

Latest commit: 239f1c5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
Name Type
@scalar/workspace-store Minor
@scalar/nuxt Patch
@scalar/api-client Patch
@scalar/api-reference Patch
@scalar/oas-utils Patch
@scalar/sidebar Patch
@scalar/api-client-react Patch
scalar-app Patch
@scalarapi/docker-api-reference Patch
@scalar/aspire Patch
@scalar/aspnetcore Patch
@scalar/fastify-api-reference Patch
@scalar/webjar Patch
@scalar/api-reference-react Patch
@scalar/components Patch
@scalar/mock-server Patch
@scalar/openapi-to-markdown Patch
@scalar/postman-to-openapi Patch
@scalar/pre-post-request-scripts Patch
@scalar/use-codemirror Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Oct 7, 2025

Scalar Components Snapshot Test Results

passed  152 passed

Details

report  Open report ↗︎
stats  152 tests across 19 suites
duration  47.7 seconds
commit  239f1c5

@github-actions
Copy link
Contributor

github-actions bot commented Oct 7, 2025

@github-actions
Copy link
Contributor

github-actions bot commented Oct 7, 2025

@github-actions
Copy link
Contributor

github-actions bot commented Oct 7, 2025

Scalar CDN Snapshot Diff Results

failed  4 failed
passed  15 passed

Details

report  Open report ↗︎
stats  19 tests across 1 suite
duration  39.4 seconds
commit  239f1c5
info  These tests are non-blocking and will not prevent merging of your PR.

Failed tests

test-snapshots/snapshot.e2e.ts › Diff with CDN - Relative URL Example
test-snapshots/snapshot.e2e.ts › Diff with CDN - Hello World (string)
test-snapshots/snapshot.e2e.ts › Diff with CDN - Scalar Galaxy Events (AsyncAPI)
test-snapshots/snapshot.e2e.ts › Diff with CDN - Circular

Important

These tests detect visual differences between the current PR and the latest CDN build which means they may be affected by other changes in main that haven't been released yet.

They can help determine if the changes in the PR are causing any unexpected visual regressions but may be less helpful in isolating the exact cause. For more details see the readme.

@hanspagel hanspagel force-pushed the feat/asyncapi-workspace-store branch from 92a9468 to feecd65 Compare October 9, 2025 10:52
@hanspagel hanspagel marked this pull request as ready for review October 9, 2025 11:02
@hanspagel hanspagel marked this pull request as draft October 9, 2025 11:03
cursor[bot]

This comment was marked as outdated.

@hanspagel hanspagel marked this pull request as ready for review October 9, 2025 12:31
cursor[bot]

This comment was marked as outdated.

@hanspagel hanspagel force-pushed the feat/asyncapi-workspace-store branch from 085a006 to 2af1b96 Compare October 13, 2025 14:11
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@hanspagel
Copy link
Member Author

The v-if condition added to the operations section prevents AsyncAPI documents from rendering

This is okay. We just want to add support to the store. We don’t want to add the rendering yet.

@hanspagel hanspagel mentioned this pull request Oct 14, 2025
@hanspagel hanspagel force-pushed the feat/asyncapi-workspace-store branch from bd4af0c to 15a905d Compare October 15, 2025 10:19
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@hanspagel hanspagel force-pushed the feat/asyncapi-workspace-store branch from 31bc06c to f593df7 Compare October 16, 2025 19:26
…r documents

- Updated the type guard function to combine checks for OpenAPI and Swagger documents, improving clarity and maintainability.
- Refactored the `createWorkspaceStore` logic to utilize the new type guard, ensuring consistent document type detection.
- Added documentation comments for better understanding of the type guard functions.
…onent

- Enhanced the logic in the Content component to check if the document is an OpenAPI document before accessing its version property, preventing potential runtime errors.
- Updated the rendering condition for traversed operations to ensure it only displays when a valid OpenAPI document is present, improving robustness and user experience.
- Corrected import paths for AsyncAPI document types in SearchButton, SearchModal, and useSearchIndex components to align with the new v3.0 schema organization.
- This change enhances clarity and maintainability by ensuring consistent references to AsyncAPI documents across the codebase.
- Introduced a check for AsyncAPI documents in the useWorkspaceStoreEvents hook to prepare for future support.
- Added TODO comments to indicate the need for implementing AsyncAPI functionality, enhancing clarity for upcoming development efforts.
- Changed 'publish' to 'send' for user signup events.
- Updated 'subscribe' to 'receive' for user deletion events.
- Adjusted related test assertions to reflect these changes.
…uments

- Updated the condition for rendering the Models component to check if the document is a valid OpenAPI document, preventing potential rendering issues.
- Introduced support for multi-format schemas in the Models component.
- Updated the rendering logic to include messages under channels in the AsyncAPI document.
- Added new type guards and utility functions for better message ID generation and schema resolution.
- Enhanced tests to cover new message handling scenarios, ensuring robust navigation structure for AsyncAPI documents.
…rom ClassicLayout component

- Simplified the schema prop type in ClassicLayout.vue by removing MultiFormatSchemaObject, ensuring it only uses SchemaObject.
- This change helps streamline the component's type definitions and improves clarity.
…n check

- Fixed a typo in the title prop of the IntroductionCardItem component from "Authentication" to "Authpentication".
- Updated the condition for rendering the Models component to ensure it only displays for valid OpenAPI documents, improving the component's reliability.
- Fixed a typo in the title prop from "Authpentication" to "Authentication" in the Content.vue file, ensuring accurate display of the authentication title.
@hanspagel hanspagel force-pushed the feat/asyncapi-workspace-store branch from 13b3ed4 to 239f1c5 Compare October 23, 2025 17:32
Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: AsyncAPI Security Scheme Mutators Undefined

The securitySchemeMutators field is undefined for AsyncAPI documents, but its type doesn't reflect this. This can cause runtime errors when callers attempt to use mutator methods, like addSecurityScheme, on an AsyncAPI document.

packages/workspace-store/src/mutators/index.ts#L43-L48

requestMutators: requestMutators(document),
securitySchemeMutators:
document && isOpenApiDocument(document)
? securitySchemeMutators(document?.components?.securitySchemes)
: // TODO: AsyncAPI Security Schemes
undefined,

Fix in Cursor Fix in Web


Bug: Binding Schema Accepts Invalid Protocol Combinations

The BindingBaseSchemaDefinition uses Type.Record with a union of all possible binding types, which means it accepts ANY string key with ANY of the binding values. This is incorrect for binding objects where specific protocol names should map to their corresponding binding types (e.g., "http" should only accept HttpOperationBinding, not KafkaServerBinding). The current implementation allows invalid combinations like { "http": AmqpChannelBinding } which violates the AsyncAPI specification where binding keys must match their protocol-specific values.

packages/workspace-store/src/schemas/asyncapi/v3.0/binding.ts#L42-L94

*/
const BindingBaseSchemaDefinition = Type.Record(
Type.String(),
Type.Union([
// AMQP
AmqpChannelBindingRef,
AmqpOperationBindingRef,
AmqpMessageBindingRef,
// HTTP
HttpOperationBindingRef,
HttpMessageBindingRef,
// WebSocket
WebSocketChannelBindingRef,
// Kafka
KafkaServerBindingRef,
KafkaChannelBindingRef,
KafkaOperationBindingRef,
KafkaMessageBindingRef,
// MQTT
MqttServerBindingRef,
MqttOperationBindingRef,
MqttMessageBindingRef,
// MQTT5
Mqtt5ServerBindingRef,
// NATS
NatsOperationBindingRef,
// SNS
SnsChannelBindingRef,
SnsOperationBindingRef,
// SQS
SqsChannelBindingRef,
SqsOperationBindingRef,
// Google Pub/Sub
GooglePubSubChannelBindingRef,
GooglePubSubMessageBindingRef,
// Anypoint MQ
AnypointMqChannelBindingRef,
AnypointMqMessageBindingRef,
// IBM MQ
IbmMqServerBindingRef,
IbmMqChannelBindingRef,
IbmMqMessageBindingRef,
// JMS
JmsServerBindingRef,
JmsChannelBindingRef,
JmsMessageBindingRef,
// Pulsar
PulsarServerBindingRef,
PulsarChannelBindingRef,
// Solace
SolaceServerBindingRef,
SolaceOperationBindingRef,
]),

Fix in Cursor Fix in Web


Bug: Schema Reference Redundancy

The schemas field in ComponentsObject allows a union of SchemaObjectRef and MultiFormatSchemaObjectRef with their references. However, the Type.Union includes both the direct refs and reference() wrappers for each type, creating redundancy. The reference() function already wraps refs, so reference(SchemaObjectRef) and reference(MultiFormatSchemaObjectRef) may create duplicate or conflicting schema definitions. This should likely just be Type.Union([SchemaObjectRef, MultiFormatSchemaObjectRef]) with a single reference() wrapper if needed.

packages/workspace-store/src/schemas/asyncapi/v3.0/components.ts#L53-L62

schemas: Type.Optional(
Type.Record(
Type.String(),
Type.Union([
SchemaObjectRef,
MultiFormatSchemaObjectRef,
reference(SchemaObjectRef),
reference(MultiFormatSchemaObjectRef),
]),
),

Fix in Cursor Fix in Web


Bug: Duplicate AsyncAPI Operations Writing

The code writes AsyncAPI operations chunks twice in the same block. Lines 471-479 check if (operations) and write AsyncAPI operations chunks, but this is redundant since lines 460-469 already handle writing operations chunks. This means for AsyncAPI documents, operations will be written twice to the same location, potentially causing race conditions or wasted I/O operations. The second block (471-479) should likely have a different condition or be removed entirely since AsyncAPI operations are already handled by the first operations block.

packages/workspace-store/src/server.ts#L470-L479

// Write the AsyncAPI operations chunks
if (operations) {
const operationPath = `${basePath}/chunks/${name}/operations`
await fs.mkdir(operationPath, { recursive: true })
for (const [operationId, operation] of Object.entries(operations)) {
await fs.writeFile(`${operationPath}/${operationId}.json`, JSON.stringify(operation))
}
}

Fix in Cursor Fix in Web


// | ((a: { action: string; channel: string }, b: { action: string; channel: string }) => number)

/** Function to generate unique IDs for markdown headings */
getHeadingId: (heading: { depth: number; value: string; slug?: string }) => string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We’re transitioning to a new interface for ID generation.
The new design uses a single function that accepts an object containing a type discriminator and its associated context.

if (document.operations) {
Object.entries(document.operations).forEach(([operationId, operation]) => {
// Handle ReferenceType - operation could be a $ref or the actual operation
const actualOperation = '$ref' in operation ? operation['$ref-value'] : operation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use the helper here called getResolvedRef

export const MessagesObjectRef = Type.Ref(ASYNCAPI_REF_DEFINITIONS.MessagesObject)
export const TagsObjectRef = Type.Ref(ASYNCAPI_REF_DEFINITIONS.TagsObject)

// Legacy aliases for backward compatibility (will be removed in future versions)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need this

requestMutators: requestMutators(document),
securitySchemeMutators: securitySchemeMutators(document?.components?.securitySchemes),
securitySchemeMutators:
document && isOpenApiDocument(document)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of doing this we can create different mutators for async api and conditionally return mutators

Object.entries(result.documents).map(([name, doc]) => [
name,
createOverridesProxy(createMagicProxy(doc), result.overrides[name]),
createOverridesProxy(createMagicProxy(doc) as ApiDefinition, result.overrides[name]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of casting we need to update the Inmem worksapce schema

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants