Skip to content

Separate Entry Points for client and host#4

Merged
hbmartin merged 1 commit intomainfrom
separate-entry-points
Sep 17, 2025
Merged

Separate Entry Points for client and host#4
hbmartin merged 1 commit intomainfrom
separate-entry-points

Conversation

@hbmartin
Copy link
Copy Markdown
Owner

@hbmartin hbmartin commented Sep 17, 2025

Summary by Sourcery

Split the library into separate client and host entry points, update build configuration and package exports accordingly, and refine related type definitions and module exports.

New Features:

  • Introduce separate library entry points for client and host in both build config and package exports
  • Add top-level client.ts and host.ts modules to simplify imports for each entry point

Enhancements:

  • Refactor vite.config to support multiple entries (index, host, client) and remove custom filename logic
  • Relocate and export disallowedLogKeys from the host logger module
  • Freeze context keys for safety and tighten return types in useWebviewApi and WebviewProvider
  • Refine ClientCalls type to use string keys only and adjust host logger type annotations

Summary by CodeRabbit

  • New Features
    • Added dedicated “host” and “client” entry points for direct imports.
    • Exposed disallowedLogKeys alongside Logger utilities.
  • Refactor
    • Consolidated public client/host APIs into separate entry modules for clearer consumption.
    • Improved logger typing and name fallback behavior.
    • Removed the withWebviewApi higher‑order component.
    • Tightened types: ClientCalls now supports string keys only.
  • Chores
    • Updated build to multi-entry outputs (index, host, client) for clearer distribution.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 17, 2025

Walkthrough

Adds dedicated client and host entry points and exports, updates build configuration to emit multiple entries, consolidates public re-exports, narrows a key public type, removes a client HOC, adjusts logger typing and naming, and relocates the disallowedLogKeys definition and re-exports.

Changes

Cohort / File(s) Summary
Package exports and build config
package.json, vite.config.ts
Adds ./host and ./client exports with types/import/require. Switches Vite lib.entry to multi-entry { index, host, client }; removes custom lib.fileName.
Client public API barrel and hooks/provider
src/lib/client.ts, src/lib/client/useWebviewApi.ts, src/lib/client/WebviewProvider.tsx
Introduces client barrel re-exports. createCtxKey now returns a frozen key. callApi signature annotated to return ReturnType<T[K]> (implementation still returns a promise).
Removal of HOC
src/lib/client/withWebviewApi.tsx
Deletes withWebviewApi higher-order component.
Host public API barrel and logger/provider
src/lib/host.ts, src/lib/host/logger.ts, src/lib/host/BaseWebviewViewProvider.ts
Adds host barrel re-exports. Defines and exports disallowedLogKeys locally. Types the logger as ILogger and updates logger name fallback (split('.')[1] ?? providerId).
Types and root index re-exports
src/lib/types.ts, src/lib/index.ts
Narrows ClientCalls keys to string. Moves disallowedLogKeys definition to host logger and re-exports it via index.ts.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor C as Client Component
  participant WP as WebviewProvider
  participant VH as VS Code Host
  participant HP as WebviewApiProvider

  C->>WP: useWebviewApi().callApi(method, args)
  note right of WP: New/Changed: callApi return type annotation<br/>(implementation resolves a promise)
  WP->>VH: postMessage({ request })
  VH->>HP: dispatch(request)
  HP-->>VH: response / error
  VH-->>WP: message({ response })
  WP-->>C: resolve/reject
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Support multiple API context providers #3 — Touches WebviewProvider, useWebviewApi/createCtxKey, and related client/host types and context, overlapping with these API and typing adjustments.
  • Release prep #2 — Modifies core modules and public entry points (client/host barrels, logger, types) similar to the re-exports and typing changes here.

Suggested labels

Review effort 3/5

Poem

I hop through exports, neat and bright,
New doors for host and client light.
A frozen key, a promise’s face,
The logger guards a secret place.
The HOC sleeps, its work now done—
Carrots compiled, three entries spun. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Separate Entry Points for client and host" is a concise, single-sentence summary that accurately captures the primary change in this PR—adding distinct client and host entry points (new lib barrels, vite multi-entry, and package.json exports). It is focused and clear enough for a teammate scanning the commit history to understand the main intent without extraneous detail.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch separate-entry-points

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 and usage tips.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Sep 17, 2025

Reviewer's Guide

This PR separates the library into distinct entry points for client and host by updating the build config and exports, reorganizes module entry files, refines type handling in the client API hooks, and cleans up logger initialization and related constants.

Class diagram for updated ClientCalls type and useWebviewApi

classDiagram
  class ClientCalls {
    <<type>>
    + [key: string]: (...args: any[]) => PromiseLike<any>
  }
  class useWebviewApi {
    + useWebviewApi<T extends ClientCalls>(): WebviewContextValue<T>
    + createCtxKey<T extends ClientCalls>(contextKey: string): CtxKey<T>
  }
  useWebviewApi --> ClientCalls
Loading

File-Level Changes

Change Details Files
Split library entry points into host, client, and default
  • Add "./host" and "./client" export entries in package.json
  • Change Vite build.lib.entry to an object with index, host, and client
  • Remove custom fileName logic to use default output filenames
package.json
vite.config.ts
Reorganize module exports into dedicated client.ts and host.ts
  • Create src/lib/client.ts and src/lib/host.ts with specific exports
  • Update root index.ts to delegate exports to the new entry files
  • Re-export disallowedLogKeys from host/logger instead of index
src/lib/index.ts
src/lib/client.ts
src/lib/host.ts
Tighten context key handling and API call types
  • Freeze returned CtxKey objects in createCtxKey
  • Adjust import paths for WebviewContextValue
  • Narrow callApi return type to exact ReturnType<T[K]>
src/lib/client/useWebviewApi.ts
src/lib/client/WebviewProvider.tsx
Refactor host logger initialization and relocate constants
  • Move disallowedLogKeys into host/logger
  • Annotate logger field with ILogger
  • Update getLogger argument to handle undefined split
src/lib/host/logger.ts
src/lib/host/BaseWebviewViewProvider.ts
Simplify ClientCalls type definition
  • Restrict ClientCalls key type to string only
  • Adjust related import statements
src/lib/types.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @hbmartin, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the library's architecture by separating client and host-side code into distinct modules with their own entry points. This change aims to improve modularity, reduce bundle sizes for consumers by allowing them to import only the necessary components, and enhance the clarity of the codebase by clearly delineating responsibilities between client and host environments. The build configuration has been updated to support this new structure, and several type definitions have been refined for improved accuracy.

Highlights

  • Separate Entry Points: Introduced distinct entry points for client-side (./client) and host-side (./host) code in package.json and vite.config.ts, allowing for more granular imports and potentially smaller bundles.
  • New Client and Host Modules: Created src/lib/client.ts and src/lib/host.ts to consolidate and export client-specific and host-specific functionalities, respectively.
  • Type Refinements: Modified the callApi return type in WebviewProvider.tsx for better type inference and refined the ClientCalls type in src/lib/types.ts to only accept string keys.
  • Code Cleanup and Relocation: Removed the withWebviewApi.tsx higher-order component and relocated disallowedLogKeys from src/lib/index.ts to src/lib/host/logger.ts.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@qodo-code-review
Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Typing Regression

Narrowing ClientCalls from Record<string | symbol, ...> to Record<string, ...> may break existing usages that rely on symbol keys for client APIs. Verify no symbol-keyed APIs are used and update docs accordingly.

export type ClientCalls = Record<string, (...args: any[]) => PromiseLike<any>>;
Fallback Handling

getLogger(providerId.split('.')[1] ?? providerId) introduces a fallback when no second segment exists. Confirm this behavior is intended and won’t change logger names unexpectedly for single-segment IDs.

  this.logger = getLogger(providerId.split('.')[1] ?? providerId);
}
Return Type Casting

callApi now returns ReturnType<T[K]> via casting the deferred promise. Ensure the generic typing matches actual promise-like return behavior and that no non-promise paths exist.

  key: K,
  ...params: Parameters<T[K]>
): ReturnType<T[K]> => {
  const id = generateId('req');
  const deferred = new DeferredPromise<Awaited<ReturnType<T[K]>>>(key as string);

  const request: ViewApiRequest<T, K> = {
    type: 'request',
    id,
    key,
    params,
    context: contextRef.current,
  };

  pendingRequests.current.set(id, deferred);

  // Send the request
  // eslint-disable-next-line sonarjs/no-try-promise
  try {
    vscodeApi.postMessage(request);
  } catch (error) {
    console.error(`Failed to send API request ${key as string}:`, error);
    deferred.clearTimeout();
    pendingRequests.current.delete(id);
    deferred.reject(error instanceof Error ? error : new Error(String(error)));
  }

  return deferred.promise as ReturnType<T[K]>;
};

@qodo-code-review
Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Lint, Type Check, and Test

Failed stage: Run ESLint [❌]

Failure summary:

The action failed during the linting step (npm run lint) due to ESLint/Prettier errors:
- In
src/lib/client.ts at line 9:46: Prettier error Insert ⏎ (prettier/prettier).
- In src/lib/host.ts at
line 8:46: Prettier error Insert ⏎ (prettier/prettier).
- In src/lib/index.ts at line 6:32: ESLint
import error Unable to resolve path to module './client/withWebviewApi' (import/no-unresolved),
indicating a missing/incorrect file path or module.
As a result, the lint step exited with code 1
and the workflow failed.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

137:  run `npm fund` for details
138:  found 0 vulnerabilities
139:  ##[group]Run npm run typecheck
140:  �[36;1mnpm run typecheck�[0m
141:  shell: /usr/bin/bash -e {0}
142:  ##[endgroup]
143:  > react-vscode-webview-ipc@0.1.0 typecheck
144:  > tsc --noEmit
145:  ##[group]Run npm run lint
146:  �[36;1mnpm run lint�[0m
147:  shell: /usr/bin/bash -e {0}
148:  ##[endgroup]
149:  > react-vscode-webview-ipc@0.1.0 lint
150:  > eslint .
151:  /home/runner/work/react-vscode-webview-ipc/react-vscode-webview-ipc/src/lib/client.ts
152:  ##[error]  9:46  error  Insert `⏎`  prettier/prettier
153:  /home/runner/work/react-vscode-webview-ipc/react-vscode-webview-ipc/src/lib/host.ts
154:  ##[error]  8:46  error  Insert `⏎`  prettier/prettier
155:  /home/runner/work/react-vscode-webview-ipc/react-vscode-webview-ipc/src/lib/index.ts
156:  ##[error]  6:32  error  Unable to resolve path to module './client/withWebviewApi'  import/no-unresolved
157:  ✖ 3 problems (3 errors, 0 warnings)
158:  2 errors and 0 warnings potentially fixable with the `--fix` option.
159:  ##[error]Process completed with exit code 1.
160:  Post job cleanup.

@openhands-ai
Copy link
Copy Markdown

openhands-ai Bot commented Sep 17, 2025

Looks like there are a few issues preventing this PR from being merged!

  • GitHub Actions are failing:
    • CI

If you'd like me to help, just leave a comment, like

@OpenHands please fix the failing actions on PR #4 at branch `separate-entry-points`

Feel free to include any additional details that might help me get this PR into a better state.

You can manage your notification settings

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • Double-check the Vite config’s removal of the custom fileName logic—ensure the bundled host and client files are named and placed as expected across both ES and CJS outputs.
  • The ClientCalls type was tightened from allowing string|symbol keys to only string keys—verify there are no existing code paths or contexts relying on symbol‐keyed call definitions.
  • The disallowedLogKeys array has been moved and re-exported in host/logger.ts—consider centralizing this constant in one module to avoid duplication or drift as its usage grows.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Double-check the Vite config’s removal of the custom fileName logic—ensure the bundled host and client files are named and placed as expected across both ES and CJS outputs.
- The ClientCalls type was tightened from allowing string|symbol keys to only string keys—verify there are no existing code paths or contexts relying on symbol‐keyed call definitions.
- The disallowedLogKeys array has been moved and re-exported in host/logger.ts—consider centralizing this constant in one module to avoid duplication or drift as its usage grows.

## Individual Comments

### Comment 1
<location> `src/lib/client/WebviewProvider.tsx:54` </location>
<code_context>
   const callApi = <K extends keyof T = keyof T>(
     key: K,
     ...params: Parameters<T[K]>
-  ): Promise<ReturnType<T[K]>> => {
+  ): ReturnType<T[K]> => {
     const id = generateId('req');
     const deferred = new DeferredPromise<Awaited<ReturnType<T[K]>>>(key as string);
</code_context>

<issue_to_address>
**issue:** Changing return type from Promise<ReturnType<T[K]>> to ReturnType<T[K]> may cause type mismatches.

Ensure that all callApi usages expect a promise, as the implementation still returns one despite the updated return type.
</issue_to_address>

### Comment 2
<location> `src/lib/host/BaseWebviewViewProvider.ts:28` </location>
<code_context>
     private readonly extensionUri: vscode.Uri,
     private readonly apiProvider?: WebviewApiProvider<HostCalls>
   ) {
-    this.logger = getLogger(providerId.split('.')[1]);
+    this.logger = getLogger(providerId.split('.')[1] ?? providerId);
   }

</code_context>

<issue_to_address>
**suggestion (bug_risk):** Fallback to providerId if split fails may mask errors.

Validating providerId or logging a warning when the format is unexpected would help catch formatting errors instead of silently falling back.

```suggestion
    const providerIdParts = providerId.split('.');
    if (providerIdParts.length < 2) {
      console.warn(`[BaseWebviewViewProvider] Unexpected providerId format: "${providerId}". Expected at least one '.'`);
      this.logger = getLogger(providerId);
    } else {
      this.logger = getLogger(providerIdParts[1]);
    }
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

const callApi = <K extends keyof T = keyof T>(
key: K,
...params: Parameters<T[K]>
): Promise<ReturnType<T[K]>> => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue: Changing return type from Promise<ReturnType<T[K]>> to ReturnType<T[K]> may cause type mismatches.

Ensure that all callApi usages expect a promise, as the implementation still returns one despite the updated return type.

private readonly extensionUri: vscode.Uri,
private readonly apiProvider?: WebviewApiProvider<HostCalls>
) {
this.logger = getLogger(providerId.split('.')[1]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): Fallback to providerId if split fails may mask errors.

Validating providerId or logging a warning when the format is unexpected would help catch formatting errors instead of silently falling back.

Suggested change
this.logger = getLogger(providerId.split('.')[1]);
const providerIdParts = providerId.split('.');
if (providerIdParts.length < 2) {
console.warn(`[BaseWebviewViewProvider] Unexpected providerId format: "${providerId}". Expected at least one '.'`);
this.logger = getLogger(providerId);
} else {
this.logger = getLogger(providerIdParts[1]);
}

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively refactors the library to have separate entry points for the client and host environments, which is a great enhancement for modularity. The changes to package.json and vite.config.ts correctly set up the new build structure. I also appreciate the improvements in type safety, such as refining the ClientCalls type and making the return type of callApi more accurate. However, I've found one critical issue: the withWebviewApi Higher-Order Component was removed, but its export statement remains in src/lib/index.ts, which will cause the build to fail. Please address this to ensure the project remains buildable.

@qodo-code-review
Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Re-evaluate the main entry point

The main index.ts entry point should be modified to export only shared types.
Currently, it exports both client and host implementations, which counteracts
the benefits of the new separate entry points.

Examples:

src/lib/index.ts [1-15]
export { type WebviewContextValue } from './client/WebviewContext';
export { WebviewProvider } from './client/WebviewProvider';
export { createCtxKey, useWebviewApi } from './client/useWebviewApi';
export { useVscodeState } from './client/useVscodeState';
export { useLogger } from './client/useLogger';
export { withWebviewApi } from './client/withWebviewApi';
export type { StateReducer, WebviewKey } from './types/ipcReducer';
export type { WebviewLayout } from './types';
export type { ILogger } from './host/ILogger';
export { Logger, getLogger, disallowedLogKeys } from './host/logger';

 ... (clipped 5 lines)

Solution Walkthrough:

Before:

// src/lib/index.ts
// Client-side exports
export { WebviewProvider } from './client/WebviewProvider';
export { useWebviewApi } from './client/useWebviewApi';
// ...

// Host-side exports
export { WebviewApiProvider } from './host/WebviewApiProvider';
export { BaseWebviewViewProvider } from './host/BaseWebviewViewProvider';
// ...

// Shared type exports
export type { ClientCalls, HostCalls } from './types';
// ...

After:

// src/lib/index.ts
// Only shared types are exported from the main entry point.
// Implementation details are in 'host.ts' and 'client.ts'.
export { isViewApiRequest, isViewApiResponse, isViewApiEvent, type CtxKey } from './types';
export type { ClientCalls, HostCalls, ViewApiResponse, ViewApiError } from './types';
export type { ActionDelegate, StateReducer, WebviewKey } from './types/ipcReducer';
export type { WebviewLayout } from './types';
export type { ILogger } from './host/ILogger';

// Consumers will now explicitly import from '/client' or '/host'
// e.g., import { WebviewProvider } from 'my-package/client';
// e.g., import { WebviewApiProvider } from 'my-package/host';
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a core architectural flaw where the main index.ts entry point undermines the PR's goal of creating separate client/host bundles by continuing to export code from both.

High
General
Improve logger tag extraction logic

Improve the logger tag extraction from providerId by using the substring after
the first dot, making the logic more robust and the resulting tag more
descriptive.

src/lib/host/BaseWebviewViewProvider.ts [28]

-this.logger = getLogger(providerId.split('.')[1] ?? providerId);
+const dotIndex = providerId.indexOf('.');
+const loggerTag = dotIndex !== -1 ? providerId.substring(dotIndex + 1) : providerId;
+this.logger = getLogger(loggerTag);
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies that using split('.')[1] can be brittle and proposes a more robust way to extract the logger tag, which would improve the descriptiveness of log messages.

Low
  • More

Copy link
Copy Markdown

@ellipsis-dev ellipsis-dev Bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed everything up to 5a1ae38 in 2 minutes and 13 seconds. Click for details.
  • Reviewed 219 lines of code in 11 files
  • Skipped 0 files when reviewing.
  • Skipped posting 7 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. package.json:25
  • Draft comment:
    New entry points for './host' and './client' have been added. Ensure these exports are compatible with your bundler and consumers.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is asking the PR author to ensure compatibility with bundlers and consumers, which falls under the rule of not asking the author to ensure behavior is intended or tested. It doesn't provide a specific suggestion or point out a specific issue.
2. src/lib/client.ts:9
  • Draft comment:
    Missing newline at end-of-file; consider adding one to comply with POSIX standards.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% While technically correct about POSIX standards, this is a very minor issue that would likely be handled by editor settings or linting rules if it was important to the project. It doesn't affect functionality and is more of a style preference. According to our rules, we should not make purely informative comments or point out obvious/unimportant issues. The missing newline could potentially cause issues with some tools or in certain environments. It is a widely accepted standard. While true, if this was important to the project, it would be enforced by their tooling. This kind of minor style issue doesn't warrant a manual review comment. Delete this comment as it points out a minor style issue that doesn't require manual intervention and would be better handled by automated tooling if important to the project.
3. src/lib/client/WebviewProvider.tsx:79
  • Draft comment:
    The cast 'as ReturnType<T[K]>' may hide potential type mismatches. Verify that the deferred.promise type aligns with the expected promise type.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the PR author to verify the alignment of types, which is against the rules. It doesn't provide a specific suggestion or point out a clear issue with the code. It is more of a cautionary note rather than a constructive comment.
4. src/lib/client/useWebviewApi.ts:24
  • Draft comment:
    Good use of Object.freeze to enforce immutability for the context key.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
5. src/lib/host/BaseWebviewViewProvider.ts:28
  • Draft comment:
    Ensure that 'providerId' always contains a '.' as expected; otherwise, splitting it might yield undefined. Consider adding validation for providerId format.
  • Reason this comment was not posted:
    Comment was on unchanged code.
6. src/lib/types.ts:6
  • Draft comment:
    Changing 'ClientCalls' to accept only string keys (was string | symbol) may be breaking if symbol keys were used elsewhere. Confirm that symbol keys aren’t needed.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% The type guard isViewApiRequest already enforces string keys with typeof message.key === 'string'. This means the code was already assuming string-only keys. The type change appears to be aligning the type definition with existing runtime behavior. The comment is speculative and asks for confirmation without strong evidence that symbol keys were ever used. I could be wrong if there are other files in the codebase that use symbol keys with ClientCalls that I can't see. The type guard might not be the only usage pattern. However, the presence of the type guard strongly suggests this was the intended usage pattern. If symbol keys were meant to be supported, the type guard would have been written differently. Delete the comment. The type change appears to be fixing a mismatch between types and runtime behavior, and the comment is speculative without evidence.
7. vite.config.ts:18
  • Draft comment:
    Multiple entry points (index, host, client) are now defined. Ensure output filenames and module boundaries are as intended; if module separation is required, consider setting preserveModules to true.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 50% <= threshold 50% The comment suggests ensuring that output filenames and module boundaries are as intended, which violates the rule against asking the PR author to ensure behavior is intended. However, it also provides a specific suggestion about setting preserveModules to true if module separation is required, which is a valid code suggestion.

Workflow ID: wflow_zeW9A6VdYdzvvat0

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/host/logger.ts (1)

18-21: structuredClone can throw before try/catch — make logging never throw.

If structuredClone fails (e.g., non-cloneables), the logger will throw. Logging must be fail-safe.

Apply:

-  const clone = structuredClone(dictionary) as Record<string, unknown>;
-
-  try {
+  try {
+    const clone = structuredClone(dictionary) as Record<string, unknown>;
     for (const key in clone) {
       const value = clone[key];
       if (disallowedLogKeys.includes(key)) {
         delete clone[key];
         continue;
       }
       if (Array.isArray(value)) {
         clone[key] = value.map((item) => removePromptsFromData(item)) as unknown;
       } else if (typeof value === 'object' && value !== null) {
         clone[key] = removePromptsFromData(value as Record<string, unknown>) as unknown;
       }
     }
   } catch (error) {
     console.error('Error processing log data:', error);
     return {} as T;
   }

Optional micro: use a local Set for lookups without changing the exported API.

+  const redactSet = new Set(disallowedLogKeys);
-      if (disallowedLogKeys.includes(key)) {
+      if (redactSet.has(key)) {
🧹 Nitpick comments (7)
src/lib/client/WebviewProvider.tsx (1)

69-77: Handle postMessage Thenable rejections (and false).

vscode.postMessage returns a Thenable. Sync try/catch won’t catch async failures; also false should be treated as delivery failure.

Apply:

-    try {
-      vscodeApi.postMessage(request);
-    } catch (error) {
+    try {
+      const maybeThenable = vscodeApi.postMessage(request);
+      if (maybeThenable && typeof (maybeThenable as any).then === 'function') {
+        (maybeThenable as PromiseLike<boolean>).then(
+          (ok) => {
+            if (ok === false) {
+              const err = new Error(`Host did not accept message ${String(key)}`);
+              const d = pendingRequests.current.get(id);
+              if (d) {
+                d.clearTimeout();
+                pendingRequests.current.delete(id);
+                d.reject(err);
+              }
+            }
+          },
+          (error) => {
+            const d = pendingRequests.current.get(id);
+            if (d) {
+              d.clearTimeout();
+              pendingRequests.current.delete(id);
+              d.reject(error instanceof Error ? error : new Error(String(error)));
+            }
+          }
+        );
+      }
+    } catch (error) {
       console.error(`Failed to send API request ${key as string}:`, error);
       deferred.clearTimeout();
       pendingRequests.current.delete(id);
       deferred.reject(error instanceof Error ? error : new Error(String(error)));
     }
src/lib/host/logger.ts (1)

4-5: Expose redaction keys here — consider freezing and documenting.

Export looks good. Optionally make it immutable to avoid accidental mutation and clarify intent.

-export const disallowedLogKeys = ['password', 'secret', 'token', 'apiKey', 'apiSecret', 'content'];
+export const disallowedLogKeys = Object.freeze(
+  ['password', 'secret', 'token', 'apiKey', 'apiSecret', 'content'] as const
+);
package.json (1)

1-95: CI depcheck false-positive for 'vscode'.

vscode is provided by the VS Code runtime; it should be extern’d (it is) and ignored by depcheck. Don’t add it as a dependency (the npm ‘vscode’ package is not meant for runtime here).

Update the CI depcheck step to ignore it:

- npx depcheck --ignores="@types/*"
+ npx depcheck --ignores="vscode,@types/*"

Alternatively, add a depcheck config:

   "devDependencies": {
     ...
   },
+  "depcheck": {
+    "ignoreMatches": ["vscode", "@types/*"]
+  }
src/lib/host/BaseWebviewViewProvider.ts (1)

28-29: Tag derivation: prefer last segment to handle multi-dot IDs.

Using only index 1 can mislabel tags if there are more than two segments.

-    this.logger = getLogger(providerId.split('.')[1] ?? providerId);
+    this.logger = getLogger(providerId.split('.').pop() ?? providerId);
src/lib/client.ts (1)

9-9: Fix Prettier violation: add a trailing newline.

CI is failing with "prettier/prettier: Insert ⏎".

Apply this diff:

-export type { WebviewLayout } from './types';
+export type { WebviewLayout } from './types';
+
src/lib/host.ts (2)

8-8: Fix Prettier violation: add a trailing newline.

Matches the CI error on this file.

Apply this diff:

-export type { WebviewLayout } from './types';
+export type { WebviewLayout } from './types';
+

2-2: Make disallowedLogKeys immutable to consumers.

Since it’s part of the public host API, expose it as a ReadonlyArray<string> or a frozen Set<string> to prevent mutation.

In src/lib/host/logger.ts, consider:

export const disallowedLogKeys = Object.freeze<string[]>([/* ... */]) as readonly string[];
// or
export const disallowedLogKeys = new Set<string>([/* ... */]) as ReadonlySet<string>;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96874c8 and 5a1ae38.

📒 Files selected for processing (11)
  • package.json (1 hunks)
  • src/lib/client.ts (1 hunks)
  • src/lib/client/WebviewProvider.tsx (2 hunks)
  • src/lib/client/useWebviewApi.ts (2 hunks)
  • src/lib/client/withWebviewApi.tsx (0 hunks)
  • src/lib/host.ts (1 hunks)
  • src/lib/host/BaseWebviewViewProvider.ts (2 hunks)
  • src/lib/host/logger.ts (1 hunks)
  • src/lib/index.ts (1 hunks)
  • src/lib/types.ts (1 hunks)
  • vite.config.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/lib/client/withWebviewApi.tsx
🧰 Additional context used
🧬 Code graph analysis (4)
src/lib/types.ts (2)
src/lib/client.ts (1)
  • ClientCalls (7-7)
src/lib/index.ts (1)
  • ClientCalls (13-13)
src/lib/client/useWebviewApi.ts (1)
src/lib/types.ts (1)
  • CtxKey (10-14)
src/lib/host/BaseWebviewViewProvider.ts (3)
src/lib/host/ILogger.ts (1)
  • ILogger (6-12)
src/lib/types/ipcReducer.ts (2)
  • ActionDelegate (72-76)
  • WebviewKey (3-3)
src/lib/host/logger.ts (1)
  • getLogger (96-106)
src/lib/host/logger.ts (2)
src/lib/host.ts (1)
  • disallowedLogKeys (2-2)
src/lib/index.ts (1)
  • disallowedLogKeys (10-10)
🪛 GitHub Actions: CI
src/lib/host/BaseWebviewViewProvider.ts

[error] 1-1: depcheck reported missing dependency 'vscode' for this file (not listed in package.json). Command: 'npx depcheck --ignores="@types/*"'. Exit code: 255.

src/lib/client.ts

[error] 9-9: prettier/prettier: Insert .

🪛 GitHub Check: Lint, Type Check, and Test
src/lib/host.ts

[failure] 8-8:
Insert

src/lib/client.ts

[failure] 9-9:
Insert

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (12)
src/lib/client/WebviewProvider.tsx (1)

54-54: Return type fix aligns with ClientCalls PromiseLike.

Good change: returning ReturnType<T[K]> (PromiseLike) avoids double-wrapping. The cast to ReturnType<T[K]> is safe since Promise satisfies PromiseLike.

Please confirm no callers relied on the previous double-promise (e.g., await (await api.foo())). A quick repo grep for nested await on API calls would suffice.

Also applies to: 79-79

src/lib/types.ts (1)

6-6: String-only keys for ClientCalls match runtime guarantees.

This lines up with the guards (typeof message.key === 'string') and structured clone constraints. Mark as a (minor) breaking type change and note in release notes.

Confirm no internal/public APIs used symbol keys for client calls.

src/lib/client/useWebviewApi.ts (2)

2-3: Import source refactor is clean.

Switching to local types keeps entry points clean and avoids circular barrels.


24-24: Freezing context keys is a good defensive move.

Prevents accidental mutation and preserves WeakMap identity guarantees.

vite.config.ts (1)

18-22: Multi-entry lib config LGTM.

Matches new package exports. No need for custom fileName; Vite will emit per-entry names.

Double-check d.ts emission creates host.d.ts and client.d.ts at dist root with vite-plugin-dts rollupTypes: true.

src/lib/host/BaseWebviewViewProvider.ts (3)

12-12: ILogger typing import is correct.

Strongly typing the logger property tightens contracts without runtime impact.


21-21: Explicit logger type is an improvement.

Keeps the class interface clear and helps callers.


1-1: CI: depcheck missing 'vscode'.

Root cause and fixes summarized in package.json comment; nothing to change in this file.

src/lib/index.ts (1)

10-10: Re-exporting disallowedLogKeys from host/logger is consistent.

Keeps the single source of truth in host/logger.

package.json (1)

25-33: Build artifacts missing — run build and re-verify exports

Local verification failed: dist/ not found and require('./dist/host.cjs') raised MODULE_NOT_FOUND.

Snippet to verify remains (package.json exports):

    "./host": {
      "types": "./dist/host.d.ts",
      "import": "./dist/host.js",
      "require": "./dist/host.cjs"
    },
    "./client": {
      "types": "./dist/client.d.ts",
      "import": "./dist/client.js",
      "require": "./dist/client.cjs"

Run these and paste the output:

npm run build
ls -1 dist | rg -n '^(host|client)\.(js|cjs|d\.ts)$'
node -e "require('./dist/host.cjs'); import('./dist/client.js').then(()=>console.log('ok'))"
src/lib/client.ts (1)

1-5: Approved — client public surface verified

All symbols re-exported by src/lib/client.ts exist in their source files and are exported; no missing exports detected.

src/lib/host.ts (1)

1-4: Host entry point shape LGTM; package.json exports present — verify bundler emits host/client artifacts.

  • package.json includes "./host" and "./client" with types/import/require pointing at dist/host.{d.ts,js,cjs} and dist/client.{d.ts,js} (package.json ~lines 25–32).
  • No matching Vite/Rollup lib entry found in the quick check; confirm your build (vite/rollup/tsup/etc.) actually produces dist/host.{js,d.ts} and dist/client.{js,d.ts} or add the bundler entries.

@hbmartin hbmartin merged commit b06c44c into main Sep 17, 2025
3 of 4 checks passed
@hbmartin hbmartin deleted the separate-entry-points branch September 17, 2025 17:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant