Skip to content

feat: add query Parameters support to javascript websocket client - #2142

Open
batchu5 wants to merge 5 commits into
asyncapi:masterfrom
batchu5:feat/js-ws-query-params
Open

feat: add query Parameters support to javascript websocket client#2142
batchu5 wants to merge 5 commits into
asyncapi:masterfrom
batchu5:feat/js-ws-query-params

Conversation

@batchu5

@batchu5 batchu5 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Description

This PR adds support for query parameters to the generated JavaScript WebSocket client, bringing it closer to feature parity with the Python and Java clients.

Changes Made

  • JavaScript WebSocket Template (packages/templates/clients/websocket/javascript):
    • Updated ClientClass.js and Constructor.js to process and append query parameters to the WebSocket URL using the native Node.js querystring module.
    • Implemented QueryParamsArgumentsDocs.js to dynamically generate JSDoc @param descriptions for each query parameter.
    • Updated InitSignature.js to inject query parameters into the constructor signature, defaulting to the values specified in the AsyncAPI document.
    • Conditionally injected the querystring module dependency only when queryParams are present in the AsyncAPI document.

Generated-by: Claude Opus 4.6

Fixes #1957

Summary by CodeRabbit

  • New Features

    • WebSocket JavaScript clients now support optional URL query parameters.
    • Generated constructors include query-parameter arguments, documentation, defaults, and safe normalized names.
    • Added a Slack WebSocket client example.
  • Bug Fixes

    • Query strings are generated only when parameters are present, with improved URL assembly and formatting.
  • Tests

    • Added coverage for query-parameter signatures, documentation, name normalization, and Slack integration.

@changeset-bot

changeset-bot Bot commented Jul 1, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 67be77d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@asyncapi-bot

Copy link
Copy Markdown
Contributor

What reviewer looks at during PR review

The following are ideal points maintainers look for during review. Reviewing these points yourself beforehand can help streamline the review process and reduce time to merge.

  1. PR Title: Use a concise title that follows our Conventional Commits guidelines and clearly summarizes the change using imperative mood (it means spoken or written as if giving a command or instruction, like "add new helper for listing operations")

    Note - In Generator, prepend feat: or fix: in PR title only when PATCH/MINOR release must be triggered.

  2. PR Description: Clearly explain the issue being solved, summarize the changes made, and mention the related issue.

    Note - In Generator, we use Maintainers Work board to track progress. Ensure the PR Description includes Resolves #<issue-number> or Fixes #<issue-number> this will automatically close the linked issue when the PR is merged and helps automate the maintainers workflow.

  3. Documentation: Update the relevant Generator documentation to accurately reflect the changes introduced in the PR, ensuring users and contributors have up-to-date guidance.

  4. Comments and JSDoc: Write clear and consistent JSDoc comments for functions, including parameter types, return values, and error conditions, so others can easily understand and use the code.

  5. DRY Code: Ensure the code follows the Don't Repeat Yourself principle. Look out for duplicate logic that can be reused.

  6. Test Coverage: Ensure the new code is well-tested with meaningful test cases that pass consistently and cover all relevant edge cases.

  7. Commit History: Contributors should avoid force-pushing as much as possible. It makes it harder to track incremental changes and review the latest updates.

  8. Template Design Principles Alignment: While reviewing template-related changes in the packages/ directory, ensure they align with the Assumptions and Principles. If any principle feels outdated or no longer applicable, start a discussion these principles are meant to evolve with the project.

  9. Reduce Scope When Needed: If an issue or PR feels too large or complex, consider splitting it and creating follow-up issues. Smaller, focused PRs are easier to review and merge.

  10. Bot Comments: As reviewers, check that contributors have appropriately addressed comments or suggestions made by automated bots. If there are bot comments the reviewer disagrees with, react to them or mark them as resolved, so the review history remains clear and accurate.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • packages/templates/clients/websocket/test/integration-test/__snapshots__/integration.test.js.javascript.snap is excluded by !**/*.snap

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c8b88781-08ec-40d5-bb35-4defd0c31ca0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds query parameter support to the JavaScript WebSocket client template. The template extracts parameters from channel bindings, generates constructor signatures and documentation, appends query strings to WebSocket URLs, and wires the data through client generation and tests.

Changes

Query parameter support in JS WebSocket client

Layer / File(s) Summary
Shared query parameter variable generation
packages/components/src/components/QueryParamsVariables.js
The generator preserves raw parameter names, uses safe local names, and emits revised parameter assignment code.
Constructor signature and parameter documentation
packages/templates/clients/websocket/javascript/components/getSafeJsName.js, packages/templates/clients/websocket/javascript/components/InitSignature.js, packages/templates/clients/websocket/javascript/components/QueryParamsArgumentsDocs.js, packages/templates/clients/websocket/javascript/test/components/getSafeJsName.test.js
The generator creates safe constructor parameter names, renders parameter defaults and documentation, and tests identifier normalization.
Constructor URL generation
packages/templates/clients/websocket/javascript/components/Constructor.js
Constructor accepts query parameters, renders the updated signature and documentation, and appends a stringified query string to this.url.
Template and client wiring
packages/templates/clients/websocket/javascript/template/client.js.js, packages/templates/clients/websocket/javascript/components/ClientClass.js, packages/templates/clients/websocket/javascript/example-slack.js, packages/templates/clients/websocket/test/integration-test/integration.test.js
The template extracts channel query parameters, adds conditional dependencies, forwards the parameters to ClientClass, and adds Slack integration coverage.
Query parameter rendering validation
packages/templates/clients/websocket/javascript/test/components/InitSignature.test.js, packages/templates/clients/websocket/javascript/test/components/QueryParamsArgumentsDocs.test.js
Fixture-based snapshots cover empty, null, single, multiple, and typed default-value cases.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • asyncapi/generator#2106: Updates related query parameter extraction used by the WebSocket client generation flow.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The Slack client example and Slack integration test extend beyond issue #1957, which is limited to WebSocket query parameter support. Move the Slack example and Slack integration test to a separate pull request unless the linked scope explicitly includes basic Slack client support.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title uses the required feat: prefix, imperative mood, and clearly describes query parameter support for the JavaScript WebSocket client.
Linked Issues check ✅ Passed The changes satisfy issue #1957 by accepting channel query parameters, appending them to the WebSocket URL, and adding conditional querystring support.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
packages/templates/clients/websocket/javascript/test/components/InitSignature.test.js (2)

28-38: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add coverage for a query param without a default value.

Current tests only cover truthy default values ('false', 'true') and the multi-param fixture case. The component's defaultValue = paramDefaultValue ? ... : '' branch (param present but no default) isn't exercised by any test.

✅ Suggested additional test
   test('renders with single query parameter with default value true', () => {
     const queryParamsWithTrueDefault = [['bids', 'true']];
     const result = render(<InitSignature queryParams={queryParamsWithTrueDefault} />);
     expect(result.trim()).toMatchSnapshot();
   });
+
+  test('renders with single query parameter without default value', () => {
+    const queryParamsWithoutDefault = [['token', undefined]];
+    const result = render(<InitSignature queryParams={queryParamsWithoutDefault} />);
+    expect(result.trim()).toMatchSnapshot();
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/templates/clients/websocket/javascript/test/components/InitSignature.test.js`
around lines 28 - 38, Add a test case in InitSignature.test.js to cover a query
param entry without a default value, since InitSignature’s defaultValue handling
currently only has coverage through the truthy default branches and the
multi-param fixture. Extend the existing render snapshot tests for InitSignature
so one case passes a param tuple with no second element and asserts the rendered
output, exercising the paramDefaultValue ? ... : '' path.

1-16: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated parser/fixture setup across test files.

The parser instantiation, fixture path, and beforeAll block (lines 1-16) are identical to QueryParamsArgumentsDocs.test.js. Consider extracting a shared test helper to load the parsed document once for both test files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/templates/clients/websocket/javascript/test/components/InitSignature.test.js`
around lines 1 - 16, The parser setup in InitSignature.test.js is duplicated
from QueryParamsArgumentsDocs.test.js, so extract the shared AsyncAPI document
loading logic into a common test helper. Move the repeated Parser/fromFile
fixture path and beforeAll parsing flow into a reusable utility, then have
InitSignature and QueryParamsArgumentsDocs import and use it so the parsed
document is created in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/templates/clients/websocket/javascript/components/InitSignature.js`:
- Around line 12-17: The query param signature generation in InitSignature.js is
treating every default as a quoted string and dropping falsy defaults entirely.
Update the default rendering logic in queryParams.map so it checks whether
paramDefaultValue is actually provided (for example, not undefined/null) instead
of using a truthy test, and preserve boolean/number defaults without forcing
string quotes. Also align the guard behavior in QueryParamsVariables.js so
appending to the URL does not depend on JS truthiness of a stringified default.
- Around line 1-24: Add a clear JSDoc block for the exported InitSignature
function to match the repo guidelines. Document the queryParams argument with
its expected shape, describe the returned Text output, and note any relevant
edge cases or error conditions. Place the comment directly above InitSignature
so it stays with the function even if the component is moved or refactored.
- Around line 3-24: Sanitize the query-param names before they are interpolated
into the constructor signature in InitSignature; right now paramName is emitted
directly, which can produce invalid JS identifiers or collide with reserved
parameters like url and throwSendErrors. Update InitSignature (and the matching
QueryParamsVariables component) to map each original query key to a safe
parameter name first, while preserving the original key for lookups and
defaults, so generated constructor syntax stays valid and unique.

In
`@packages/templates/clients/websocket/javascript/components/QueryParamsArgumentsDocs.js`:
- Around line 1-18: Add JSDoc for the exported QueryParamsArgumentsDocs function
so it complies with the JS/TS/JSX coding guideline: document the queryParams
input with an `@param` tag and describe the return value with `@returns`. Keep the
docs attached directly above QueryParamsArgumentsDocs, and ensure they cover the
component’s behavior when queryParams is empty or missing.

---

Nitpick comments:
In
`@packages/templates/clients/websocket/javascript/test/components/InitSignature.test.js`:
- Around line 28-38: Add a test case in InitSignature.test.js to cover a query
param entry without a default value, since InitSignature’s defaultValue handling
currently only has coverage through the truthy default branches and the
multi-param fixture. Extend the existing render snapshot tests for InitSignature
so one case passes a param tuple with no second element and asserts the rendered
output, exercising the paramDefaultValue ? ... : '' path.
- Around line 1-16: The parser setup in InitSignature.test.js is duplicated from
QueryParamsArgumentsDocs.test.js, so extract the shared AsyncAPI document
loading logic into a common test helper. Move the repeated Parser/fromFile
fixture path and beforeAll parsing flow into a reusable utility, then have
InitSignature and QueryParamsArgumentsDocs import and use it so the parsed
document is created in one place.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 70315b57-c37f-48a9-ac43-41e9e7992f6c

📥 Commits

Reviewing files that changed from the base of the PR and between 97161a5 and d19c673.

⛔ Files ignored due to path filters (4)
  • packages/components/test/components/__snapshots__/QueryParamsVariables.test.js.snap is excluded by !**/*.snap
  • packages/templates/clients/websocket/javascript/test/components/__snapshots__/InitSignature.test.js.snap is excluded by !**/*.snap
  • packages/templates/clients/websocket/javascript/test/components/__snapshots__/QueryParamsArgumentsDocs.test.js.snap is excluded by !**/*.snap
  • packages/templates/clients/websocket/test/integration-test/__snapshots__/integration.test.js.javascript.snap is excluded by !**/*.snap
📒 Files selected for processing (8)
  • packages/components/src/components/QueryParamsVariables.js
  • packages/templates/clients/websocket/javascript/components/ClientClass.js
  • packages/templates/clients/websocket/javascript/components/Constructor.js
  • packages/templates/clients/websocket/javascript/components/InitSignature.js
  • packages/templates/clients/websocket/javascript/components/QueryParamsArgumentsDocs.js
  • packages/templates/clients/websocket/javascript/template/client.js.js
  • packages/templates/clients/websocket/javascript/test/components/InitSignature.test.js
  • packages/templates/clients/websocket/javascript/test/components/QueryParamsArgumentsDocs.test.js

@Adi-204 Adi-204 moved this to In Progress in Maintainers work Jul 1, 2026
@batchu5

batchu5 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated parser/fixture setup across test files.

The parser instantiation, fixture path, and beforeAll block (lines 1-16) are identical to QueryParamsArgumentsDocs.test.js. Consider extracting a shared test helper to load the parsed document once for both test files.

@Adi-204 I wonder if we can actually put the Common JS file for parsing the AsyncAPI document, because in all other tests we don't follow that way 🤔

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/templates/clients/websocket/javascript/components/getSafeJsName.js (1)

18-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stray formatting inside template literal.

`_${ safe}` has an unnecessary double space inside the expression. As per coding guidelines, formatting should be enforced entirely through ESLint rather than manual/Prettier-style edits; run lint to normalize this.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/templates/clients/websocket/javascript/components/getSafeJsName.js`
at line 18, The template literal in getSafeJsName contains stray manual spacing
inside the interpolation, so normalize this through the existing lint/formatting
rules rather than hand-editing the expression. Update the safe-name fallback in
getSafeJsName to follow the repository’s ESLint style, and verify the change by
running the relevant lint fix for the JavaScript template component.

Source: Coding guidelines

packages/templates/clients/websocket/javascript/test/components/InitSignature.test.js (1)

1-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Shared parser/fixture setup duplicated across test files.

This mirrors the duplication already raised in the PR discussion about extracting a shared helper for loading the parsed AsyncAPI document. Worth consolidating once the placement question (CommonJS parsing file vs. existing test patterns) is resolved.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/templates/clients/websocket/javascript/test/components/InitSignature.test.js`
around lines 1 - 16, The AsyncAPI document loading setup in
InitSignature.test.js is duplicated across multiple test files, so extract the
shared parser/fixture initialization into a reusable helper. Move the repeated
Parser, fromFile, asyncapiFilePath, and beforeAll parse logic into the agreed
shared location, then update InitSignature and the other affected component
tests to consume that helper instead of repeating the setup.
packages/templates/clients/websocket/javascript/test/components/getSafeJsName.test.js (1)

3-35: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Consider adding a collision test once dedup logic is added.

Given the identifier-collision risk flagged in getSafeJsName.js (distinct names like my-param/my_param both sanitizing to myParam), it would be worth adding a test case covering that scenario once the helper handles it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/templates/clients/websocket/javascript/test/components/getSafeJsName.test.js`
around lines 3 - 35, Add a new collision-focused test in getSafeJsName.test.js
for the getSafeJSName helper to cover distinct inputs that currently sanitize to
the same output, such as my-param and my_param both becoming myParam. Once the
dedup logic is implemented in getSafeJsName.js, assert that the helper returns
unique, non-conflicting names for colliding identifiers and keep the test
alongside the existing conversion and reserved-word cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/templates/clients/websocket/javascript/components/getSafeJsName.js`:
- Around line 11-19: The sanitization helper in getSafeJSName can return the
same identifier for different original names, which leads to duplicate JS
parameter names downstream. Update getSafeJSName (or the callers
InitSignature.js and QueryParamsArgumentsDocs.js) to track already-used names
and generate a unique fallback, such as appending a numeric suffix when a
collision is detected. Keep the existing reserved-word and leading-digit
handling, but ensure each returned name is distinct within the generated
parameter list.

---

Nitpick comments:
In `@packages/templates/clients/websocket/javascript/components/getSafeJsName.js`:
- Line 18: The template literal in getSafeJsName contains stray manual spacing
inside the interpolation, so normalize this through the existing lint/formatting
rules rather than hand-editing the expression. Update the safe-name fallback in
getSafeJsName to follow the repository’s ESLint style, and verify the change by
running the relevant lint fix for the JavaScript template component.

In
`@packages/templates/clients/websocket/javascript/test/components/getSafeJsName.test.js`:
- Around line 3-35: Add a new collision-focused test in getSafeJsName.test.js
for the getSafeJSName helper to cover distinct inputs that currently sanitize to
the same output, such as my-param and my_param both becoming myParam. Once the
dedup logic is implemented in getSafeJsName.js, assert that the helper returns
unique, non-conflicting names for colliding identifiers and keep the test
alongside the existing conversion and reserved-word cases.

In
`@packages/templates/clients/websocket/javascript/test/components/InitSignature.test.js`:
- Around line 1-16: The AsyncAPI document loading setup in InitSignature.test.js
is duplicated across multiple test files, so extract the shared parser/fixture
initialization into a reusable helper. Move the repeated Parser, fromFile,
asyncapiFilePath, and beforeAll parse logic into the agreed shared location,
then update InitSignature and the other affected component tests to consume that
helper instead of repeating the setup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 71c93031-8a1a-4115-b34e-282d30263bf3

📥 Commits

Reviewing files that changed from the base of the PR and between d19c673 and 50cdcef.

⛔ Files ignored due to path filters (1)
  • packages/templates/clients/websocket/javascript/test/components/__snapshots__/InitSignature.test.js.snap is excluded by !**/*.snap
📒 Files selected for processing (5)
  • packages/templates/clients/websocket/javascript/components/InitSignature.js
  • packages/templates/clients/websocket/javascript/components/QueryParamsArgumentsDocs.js
  • packages/templates/clients/websocket/javascript/components/getSafeJsName.js
  • packages/templates/clients/websocket/javascript/test/components/InitSignature.test.js
  • packages/templates/clients/websocket/javascript/test/components/getSafeJsName.test.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/templates/clients/websocket/javascript/components/QueryParamsArgumentsDocs.js
  • packages/templates/clients/websocket/javascript/components/InitSignature.js

Comment thread packages/templates/clients/websocket/javascript/components/getSafeJsName.js Outdated
@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

@Adi-204 Adi-204 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@batchu5 the main problem over here is in JS we don't have slack support for now and currently slack example is only having query params. So it is difficult to review also how did you test changes locally?

Comment thread packages/components/src/components/QueryParamsVariables.js
usedNames.add(candidate);

return candidate;
} No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Firstly I don't get point of this getSafeJsName becoz we can't just change param name given in the input asyncapi file. Secondly it is not a component it should be in file https://github.com/asyncapi/generator/blob/master/packages/helpers/src/utils.js

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The main use of getSafeJsName is, if the paramName that the user has sent is, for example, user-id, as it is not valid js variable name it would give a syntax error so to cut that off we are basically using this function

Sure thing, I should have put this in the utils.js.
Also, since we can't change the paramName in the AsyncAPI doc, what if paramName is invalid? What can we actually do here??

@batchu5

batchu5 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

I have tested the code using this file.

@Adi-204

Adi-204 commented Jul 10, 2026

Copy link
Copy Markdown
Member

I have tested the code using this file.

@batchu5 yeah I'm not sure we should develop in this way as difficult to test going forward. Let's keep this on hold we can discuss in next meeting!

@Adi-204

Adi-204 commented Jul 15, 2026

Copy link
Copy Markdown
Member

hey @batchu5 we discuss in the generator meeting https://fathom.video/share/P7tie39Wzz6zzHK3VuY-kkBh8nbR_jBX you can have a look at it basically right now it is a bit difficult to isolate this adding a new component to a template as we are not able to test it properly I think better would be changing the scope of issue and you can continue in this PR adding support for slack client in JS. NO need to complicate it too much for Phase 1 we don't want everything that python is doing right now rather main objective is to have slack support in JS client. Feel free to ask question if any.

@Adi-204

Adi-204 commented Aug 1, 2026

Copy link
Copy Markdown
Member

@batchu5 new scope of the issue - "basic version of working slack example"

If you notice in python template https://github.com/asyncapi/generator/tree/master/packages/templates/clients/websocket/python we have 3 examples

example.py, example-slack.py and example-slack-with-routing.py

Now to keep scope limited you only need to make sure for JS template something like example-slack.py is working which was introduce in #1509

What you DON"T need to DO - "automatic routing of message for slack" which was introduce in #1814 keep this OUT OF SCOPE.

Feel free to ask question!

@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/templates/clients/websocket/javascript/example-slack.js (1)

2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace descriptive comments with required JSDoc.

Remove the comment at Line 2. Replace the comment at Line 5 with JSDoc for myHandler. Add JSDoc for main with the parameter type, return type, and error behavior. Document that connection errors are caught and logged, and that the pending promise remains active while the client listens.

As per coding guidelines, comments should explain non-obvious why factors, and JavaScript functions require clear JSDoc with parameter types, return values, and error conditions.

Proposed documentation
-// Example usage
 const wsClient = new WSClient();
 
-// Example of how custom message handler that operates on incoming messages can look like
+/**
+ * Logs an incoming Slack event.
+ * `@param` {unknown} message Incoming Slack event.
+ * `@returns` {void}
+ */
 function myHandler(message) {
...
+/**
+ * Registers the handler, connects to Slack, and listens for events.
+ * `@returns` {Promise<void>} A promise that remains pending while the client listens.
+ * `@throws` {Error} If message-handler registration fails.
+ */
 async function main() {

Also applies to: 5-6, 12-12

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/templates/clients/websocket/javascript/example-slack.js` at line 2,
Remove the standalone descriptive comment, replace the existing comment above
myHandler with JSDoc documenting its parameters and return value, and add JSDoc
above main covering its parameter type, return type, connection-error handling
and logging, and the pending promise remaining active while the client listens.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/components/src/components/QueryParamsVariables.js`:
- Around line 68-80: Update QueryParamsVariables to reuse InitSignature’s
getSafeJSName mapping for generated local identifiers, applying safe names
consistently in declarations, conditions, and assignments. Generate environment
lookups with process.env[JSON.stringify(rawName)] and query keys with
JSON.stringify(rawName), then add regression coverage for non-identifier,
reserved, and colliding parameter names.

In `@packages/templates/clients/websocket/javascript/example-slack.js`:
- Line 3: Update the WSClient initialization in the example to pass the
connection URL returned by apps.connections.open, using new WSClient(url) so the
required ticket and app_id query parameters are preserved.

---

Nitpick comments:
In `@packages/templates/clients/websocket/javascript/example-slack.js`:
- Line 2: Remove the standalone descriptive comment, replace the existing
comment above myHandler with JSDoc documenting its parameters and return value,
and add JSDoc above main covering its parameter type, return type,
connection-error handling and logging, and the pending promise remaining active
while the client listens.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 73cdeb3c-b34b-429a-a54c-5694d1c7afcb

📥 Commits

Reviewing files that changed from the base of the PR and between aafe462 and f790e68.

⛔ Files ignored due to path filters (2)
  • packages/components/test/components/__snapshots__/QueryParamsVariables.test.js.snap is excluded by !**/*.snap
  • packages/templates/clients/websocket/test/integration-test/__snapshots__/integration.test.js.javascript.snap is excluded by !**/*.snap
📒 Files selected for processing (4)
  • packages/components/src/components/QueryParamsVariables.js
  • packages/templates/clients/websocket/javascript/components/getSafeJsName.js
  • packages/templates/clients/websocket/javascript/example-slack.js
  • packages/templates/clients/websocket/test/integration-test/integration.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/templates/clients/websocket/javascript/components/getSafeJsName.js

Comment on lines +68 to +80
const rawName = param[0];
const paramName = toCamelCase(rawName);
return {
variableDefinition: {
text: `const ${paramName} = ${paramName} || process.env.${paramName.toUpperCase()};`,
indent: 8,
text: `const _${rawName} = ${paramName} || process.env.${rawName.toUpperCase()};`,
indent: 0,
},
ifCondition: {
text: `if (${paramName}) {`,
indent: 8,
text: `if (_${rawName}) {`,
indent: 0,
},
assignment: {
text: `params["${paramName}"] = ${paramName};`,
indent: 10,
text: `params["${rawName}"] = _${rawName};`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 5 '\b(toCamelCase|getSafeJsName)\b' \
  packages/components/src/components/QueryParamsVariables.js \
  packages/templates/clients/websocket/javascript/components

rg -n -C 3 'auth-token|foo-bar|queryParams' \
  packages/components/test \
  packages/templates/clients/websocket/javascript/test

Repository: asyncapi/generator

Length of output: 28865


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- QueryParamsVariables.js ---'
cat -n packages/components/src/components/QueryParamsVariables.js

printf '%s\n' '--- getSafeJsName.js ---'
cat -n packages/templates/clients/websocket/javascript/components/getSafeJsName.js

printf '%s\n' '--- InitSignature.js ---'
cat -n packages/templates/clients/websocket/javascript/components/InitSignature.js

printf '%s\n' '--- component tests ---'
cat -n packages/components/test/components/QueryParamsVariables.test.js

printf '%s\n' '--- JavaScript snapshots ---'
rg -n -A18 -B3 'javascript' packages/components/test/components/__snapshots__/QueryParamsVariables.test.js.snap

printf '%s\n' '--- QueryParamsVariables usages ---'
rg -n -C3 '<QueryParamsVariables|QueryParamsVariables' packages --glob '*.{js,jsx,ts,tsx}'

Repository: asyncapi/generator

Length of output: 16195


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- helper usages and exports ---'
rg -n -C3 'getSafeJSName|QueryParamsVariables|QueryParamsArgumentsDocs|InitSignature' \
  packages/components packages/templates/clients/websocket/javascript

printf '%s\n' '--- JavaScript snapshot section ---'
sed -n '1,25p' packages/components/test/components/__snapshots__/QueryParamsVariables.test.js.snap

printf '%s\n' '--- helper source candidates ---'
rg -n -C5 'function toCamelCase|const toCamelCase|export .*toCamelCase' \
  packages

printf '%s\n' '--- package README principles ---'
sed -n '1,220p' packages/README.md

printf '%s\n' '--- deterministic safe-name probe ---'
python3 - <<'PY'
import re

def to_camel_case(name):
    # Probe the cases relevant to this review using the repository's helper
    # implementation if it is available as a readable source file.
    return name

def safe_js_name(name):
    safe = to_camel_case(name)
    safe = re.sub(r'[^a-zA-Z0-9_]', '_', safe)
    if re.match(r'^[0-9]', safe):
        safe = '_' + safe
    if safe in {
        'url', 'throwSendErrors', 'params', 'queryString',
        'class', 'const', 'let', 'var', 'if', 'else', 'return',
        'this', 'true', 'false', 'null', 'undefined',
    }:
        safe = '_' + safe
    return safe

for raw in ['auth-token', 'foo-bar', '1token', 'class', 'params', 'token']:
    print(raw, 'raw identifier:', f'const _{raw}', 'safe helper:', safe_js_name(raw))
PY

Repository: asyncapi/generator

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- toCamelCase implementation ---'
rg -l 'toCamelCase' packages | while read -r file; do
  rg -n -C8 'toCamelCase' "$file"
done | head -n 180

printf '%s\n' '--- focused constructor composition ---'
cat -n packages/templates/clients/websocket/javascript/components/Constructor.js

printf '%s\n' '--- focused safe-name tests ---'
cat -n packages/templates/clients/websocket/javascript/test/components/getSafeJsName.test.js

printf '%s\n' '--- JavaScript syntax probe ---'
node - <<'JS'
const cases = [
  {
    name: 'auth-token',
    argument: 'authToken',
    raw: 'const _auth-token = authToken || process.env.AUTH-TOKEN;',
    corrected: 'const _authToken = authToken || process.env["AUTH-TOKEN"];',
  },
  {
    name: 'url',
    argument: '_url',
    raw: 'const _url = url || process.env.URL;',
    corrected: 'const __url = _url || process.env["URL"];',
  },
  {
    name: 'throw-send-errors',
    argument: '_throwSendErrors',
    raw: 'const _throw-send-errors = throwSendErrors || process.env.THROW-SEND-ERRORS;',
    corrected: 'const __throwSendErrors = _throwSendErrors || process.env["THROW-SEND-ERRORS"];',
  },
];

for (const item of cases) {
  for (const [label, source] of [['raw', item.raw], ['corrected', item.corrected]]) {
    try {
      new Function(`function f(${item.argument}) { ${source} }`);
      console.log(item.name, label, 'PARSES');
    } catch (error) {
      console.log(item.name, label, 'REJECTED:', error.message);
    }
  }
}
JS

Repository: asyncapi/generator

Length of output: 11961


Use safe constructor names in generated query code.

QueryParamsVariables must use the same getSafeJSName mapping as InitSignature. Names such as auth-token, 1st, and url can otherwise produce invalid or duplicate declarations. Use the safe name for all local references, process.env[JSON.stringify(...)] for environment variables, and JSON.stringify(rawName) for query keys. Add regression tests for non-identifier, reserved, and colliding names.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/components/src/components/QueryParamsVariables.js` around lines 68 -
80, Update QueryParamsVariables to reuse InitSignature’s getSafeJSName mapping
for generated local identifiers, applying safe names consistently in
declarations, conditions, and assignments. Generate environment lookups with
process.env[JSON.stringify(rawName)] and query keys with
JSON.stringify(rawName), then add regression coverage for non-identifier,
reserved, and colliding parameter names.

@@ -0,0 +1,27 @@
const WSClient = require('./test/temp/snapshotTestResult/client_slack/client.js');
// Example usage
const wsClient = new WSClient();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 6 'new WSClient|constructor\(|query|ticket|app_id' \
  packages/templates/clients/websocket/javascript \
  packages/templates/clients/websocket/test

Repository: asyncapi/generator

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- tracked Slack-related files ---'
git ls-files packages/templates/clients/websocket | grep -Ei 'slack|fixture|snapshot' | head -80

echo '--- focused generated-client references ---'
rg -n -C 5 'class Slack|new WSClient|wss-primary\.slack\.com/link|ticket.*app_id|app_id.*ticket' \
  packages/templates/clients/websocket --glob '!**/*.python.snap' --glob '!**/node_modules/**' | head -240

echo '--- constructor generation ---'
sed -n '1,90p' packages/templates/clients/websocket/javascript/components/InitSignature.js
sed -n '1,90p' packages/templates/clients/websocket/javascript/components/Constructor.js

echo '--- example ---'
cat -n packages/templates/clients/websocket/javascript/example-slack.js

Repository: asyncapi/generator

Length of output: 27822


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- Slack fixture ---'
cat -n packages/templates/clients/websocket/test/__fixtures__/asyncapi-slack-client.yml | sed -n '1,90p'

echo '--- generated JavaScript constructor snapshot ---'
sed -n '1106,1165p' packages/templates/clients/websocket/test/integration-test/__snapshots__/integration.test.js.javascript.snap

echo '--- JavaScript Slack documentation and example references ---'
find packages/templates/clients/websocket/javascript -maxdepth 2 -type f -print | sort
rg -n -C 8 'apps\.connections\.open|ticket|app_id|example-slack|client_slack' \
  packages/templates/clients/websocket/javascript \
  packages/templates/clients/websocket/test/__fixtures__/asyncapi-slack-client.yml \
  packages/templates/clients/websocket/test/integration-test/__snapshots__/integration.test.js.javascript.snap

Repository: asyncapi/generator

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import re
from pathlib import Path

fixture = Path("packages/templates/clients/websocket/test/__fixtures__/asyncapi-slack-client.yml").read_text()
snapshot = Path(
    "packages/templates/clients/websocket/test/integration-test/"
    "__snapshots__/integration.test.js.javascript.snap"
).read_text()

fixture_section = fixture.split("properties:", 1)[1].split("operations:", 1)[0]
assert re.search(r"^\s+ticket:\s*$", fixture_section, re.MULTILINE)
assert re.search(r"^\s+app_id:\s*$", fixture_section, re.MULTILINE)

constructor = re.search(
    r"constructor\(([^)]*)\) \{(?P<body>.*?)\n  \}",
    snapshot,
    re.DOTALL,
)
assert constructor, "Slack constructor not found"
signature = constructor.group(1)
body = constructor.group("body")

assert signature == "url, ticket, appId, throwSendErrors = true"
assert "ticket = " not in signature
assert "appId = " not in signature
assert "this.url = url || 'wss://wss-primary.slack.com/link';" in body
assert "params[\\\\\"ticket\\\\\"] = _ticket;" in body
assert "params[\\\\\"app_id\\\\\"] = _app_id;" in body

# Model the constructor's zero-argument path without executing repository code.
url = "wss://wss-primary.slack.com/link"
ticket = None
app_id = None
if ticket or None:
    url += "?ticket=" + ticket
if app_id or None:
    url += ("&" if "?" in url else "?") + "app_id=" + app_id

print("constructor signature:", signature)
print("zero-argument URL:", url)
print("zero-argument URL has ticket:", "ticket=" in url)
print("zero-argument URL has app_id:", "app_id=" in url)
assert url == "wss://wss-primary.slack.com/link"
PY

Repository: asyncapi/generator

Length of output: 346


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import re
from pathlib import Path

fixture = Path("packages/templates/clients/websocket/test/__fixtures__/asyncapi-slack-client.yml").read_text()
snapshot = Path(
    "packages/templates/clients/websocket/test/integration-test/"
    "__snapshots__/integration.test.js.javascript.snap"
).read_text()

fixture_section = fixture.split("properties:", 1)[1].split("operations:", 1)[0]
assert re.search(r"^\s+ticket:\s*$", fixture_section, re.MULTILINE)
assert re.search(r"^\s+app_id:\s*$", fixture_section, re.MULTILINE)

constructor = re.search(
    r"constructor\(([^)]*)\) \{(?P<body>.*?)\n  \}",
    snapshot,
    re.DOTALL,
)
assert constructor, "Slack constructor not found"
signature = constructor.group(1)
body = constructor.group("body")

assert signature == "url, ticket, appId, throwSendErrors = true"
assert "ticket = " not in signature
assert "appId = " not in signature
assert "this.url = url || 'wss://wss-primary.slack.com/link';" in body
assert "params[\\\\\"ticket\\\\\"] = _ticket;" in body
assert "params[\\\\\"app_id\\\\\"] = _app_id;" in body

url = "wss://wss-primary.slack.com/link"
ticket = None
app_id = None
if ticket or None:
    url += "?ticket=" + ticket
if app_id or None:
    url += ("&" if "?" in url else "?") + "app_id=" + app_id

print("constructor signature:", signature)
print("zero-argument URL:", url)
print("zero-argument URL has ticket:", "ticket=" in url)
print("zero-argument URL has app_id:", "app_id=" in url)
assert url == "wss://wss-primary.slack.com/link"
PY

Repository: asyncapi/generator

Length of output: 346


Pass Slack’s generated connection URL to WSClient.

new WSClient() omits the required ticket and app_id query parameters. Pass the url returned by apps.connections.open to new WSClient(url).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/templates/clients/websocket/javascript/example-slack.js` at line 3,
Update the WSClient initialization in the example to pass the connection URL
returned by apps.connections.open, using new WSClient(url) so the required
ticket and app_id query parameters are preserved.

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

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

JavaScript WebSocket client template doesn't support query parameters from channel bindings

3 participants