Skip to content

Feat/introduce web client - #307

Open
tsmith023 wants to merge 49 commits into
mainfrom
feat/introduce-web-client
Open

Feat/introduce web client#307
tsmith023 wants to merge 49 commits into
mainfrom
feat/introduce-web-client

Conversation

@tsmith023

@tsmith023 tsmith023 commented Jun 20, 2025

Copy link
Copy Markdown
Member

- Refactor into a monorepo composed for four packages:
  - @weaviate/core: shared functionality
  - @weaviate/node: Node-client that uses `grpc-js` and `fs`
  - @weaviate/web: Browser-client that uses `nice-grpc` and `FileReader`
  - @weaviate/test: Tests the public APIs of the core/node pkgs
- Replace `jest` with `vitest`
- Use `pnpm` for managing the monorepo
- Use dependency injection to pipe node/browser deps into the common functionality of the client
@tsmith023
tsmith023 requested a review from a team as a code owner June 20, 2025 13:48

@orca-security-eu orca-security-eu 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.

Orca Security Scan Summary

Status Check Issues by priority
Passed Passed Infrastructure as Code high 0   medium 0   low 0   info 0 View in Orca
Passed Passed SAST high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Secrets high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Vulnerabilities high 0   medium 0   low 0   info 0 View in Orca

@weaviate-git-bot

Copy link
Copy Markdown

Great to see you again! Thanks for the contribution.

beep boop - the Weaviate bot 👋🤖

PS:
Are you already a member of the Weaviate Slack channel?

@orca-security-eu orca-security-eu 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.

Orca Security Scan Summary

Status Check Issues by priority
Passed Passed Infrastructure as Code high 0   medium 0   low 0   info 0 View in Orca
Passed Passed SAST high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Secrets high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Vulnerabilities high 0   medium 1   low 0   info 0 View in Orca
☢️ The following Vulnerabilities (CVEs) have been detected
PACKAGE FILE CVE ID INSTALLED VERSION FIXED VERSION
high ws ./pnpm-lock.yaml CVE-2026-48779 8.18.2 5.2.5, 6.2.4, 7.5.11, 8.21.0 View in code

@orca-security-eu orca-security-eu 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.

Orca Security Scan Summary

Status Check Issues by priority
Passed Passed Infrastructure as Code high 0   medium 0   low 0   info 0 View in Orca
Passed Passed SAST high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Secrets high 0   medium 0   low 0   info 0 View in Orca
Failed Failed Vulnerabilities high 1   medium 1   low 0   info 0 View in Orca
☢️ The following Vulnerabilities (CVEs) have been detected
PACKAGE FILE CVE ID INSTALLED VERSION FIXED VERSION
high ws ./pnpm-lock.yaml CVE-2026-48779 8.18.2 5.2.5, 6.2.4, 7.5.11, 8.21.0 View in code
high ws ./pnpm-lock.yaml CVE-2026-45736 8.18.2 8.20.1 View in code

'username and password, so this method is not supported by this client'
);
}
this.openidConfig.scopes.push('offline_access');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

issue: this is a breaking change, client should continue to add offline_access scope.

Sneaky having that at the end of something called "validate config" 😅
I missed it too while cherry-picking the commit but good thing the tests caught it.

@orca-security-eu orca-security-eu 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.

Orca Security Scan Summary

Status Check Issues by priority
Passed Passed Infrastructure as Code high 0   medium 0   low 0   info 0 View in Orca
Passed Passed SAST high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Secrets high 0   medium 0   low 0   info 0 View in Orca
Failed Failed Vulnerabilities high 2   medium 0   low 0   info 0 View in Orca
☢️ The following Vulnerabilities (CVEs) have been detected
PACKAGE FILE CVE ID INSTALLED VERSION FIXED VERSION
high ws ./pnpm-lock.yaml CVE-2026-48779 8.18.2 5.2.5, 6.2.4, 7.5.11, 8.21.0 View in code
high ws ./pnpm-lock.yaml CVE-2026-45736 8.18.2 8.20.1 View in code

(name.charAt(0).toUpperCase() + name.slice(1)) as N;

const collection = <T, N, V>(
const collection = <T, N, V, M>(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit/suggestion: if renaming generic parameters and formatting changes were their own PR(s) it'd be easier to focus on the key areas of the diff in this one

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Having went through the whole PR I want to emphasize much easier :)

private constructor(params: GrpcConnectionParams & { grpcMaxMessageLength: number }) {
private constructor(
transports: Transports,
params: GrpcConnectionParams & { grpcMaxMessageLength: number }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

question: Can grpcMaxMessageLength be included in the GrpcConnectionParams definition above on line 19?

Comment on lines +50 to 53
if (!params.skipInitChecks) {
grpcMaxMessageLength = await Promise.all([
(rest.get('/meta', true) as Promise<Meta>).then(
(res: Meta) => res.grpcMaxMessageSize || MAX_GRPC_MESSAGE_LENGTH

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

issue: it feels wrong that skipInitChecks can also make the client ignore the server's gRPC message size limit; perhaps it should only control compatibility checks?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I understand that calling /meta with skipInitChecks: false will effectively perform an init check despite their having been disabled. At the same time, respecting the server's transport configuration seems more important (?)

WDYT?

tenant
),
close: () => channel.close(),
close: () => {},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

question: why is close a no-op now?

return health
return transports.health
.check(
{ service: '/grpc.health.v1.Health/Check' },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It's quite surprising that HealthClient from Google's gRPC package doesn't have the name of the service "baked in", what?

const agent = context.agentMaker?.(httpSecure);

const { connection, dbVersionProvider, dbVersionSupport } = await ConnectionGRPC.use(
context.transportsMaker,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

tl;dr: I find the fact that ConnectionGRPC satisfies ConnectionREST so confusing.


Initially I wanted to ask this:

question: if agentMaker "Creates the HTTP(S) keep-alive agent for the REST/GraphQL connection", then why is it a part of the top-level Context and not some internal component of ConnectionREST?

Before posting that, I decided to look around and answer this for myself. But I couldn't find ConnectionREST mentioned anywhere here, and instead I saw connection returned by ConnectionGRPC.use() passed to alias(connection) which expects ConnectionREST (!).

I was rather surprised to learn that ConnectionGRPC extended ConnectionGQL even though they use completely different transports, and that ConnectionGQL was a thing separate from ConnectionREST even though both use the same transport / connection.


suggestion (wrt agentMaker): I see from it's description that web/ and node/ inject different agent makers. Perhaps each could instead provide a complete ConnectionREST object and make the injection "privately"?

host: `${scheme}://${httpHost}:${httpPort}${httpPath || ''}`,
scheme: scheme,
headers: params.headers,
grpcAddress: `${isGrpcWeb ? (grpcSecure ? 'https://' : 'http://') : ''}${grpcHost}:${grpcPort}${

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

question: why are there both httpSecure and grpcSecure parameters? Is there a real use-case for having one connection be secured and the other one not?


Suggested change
grpcAddress: `${isGrpcWeb ? (grpcSecure ? 'https://' : 'http://') : ''}${grpcHost}:${grpcPort}${
grpcAddress: `${isGrpcWeb ? (grpcSecure ? 'https' : 'http') : ''}://${grpcHost}:${grpcPort}${

nit: simplify the expression

Comment on lines 2084 to 2088
public static tenants<T, M>(tenants: T[], mapper: (tenant: T) => M): M[][] {
const mapped = [];
const mapped: M[][] = [];
const batches = Math.ceil(tenants.length / 100);
for (let i = 0; i < batches; i++) {
const batch = tenants.slice(i * 100, (i + 1) * 100);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

question: why does this method split the tenants array into batches or 100?


it('should be able to create a simple collection with a generic using a schema var with type', async () => {
const collectionName = 'TestCollectionSimpleGenericVarType';
afters.push(() => contextionary.collections.delete(collectionName));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

suggestion: would it make sense to add a test util for creating collections that would "schedule" the deletion automatically?

It's exactly as what you have with afters here, but packaged so that it's easier to reuse across tests and a tad more succinct. Just something I've thought about doing every time I had to create a collection in a test :)


// testutil.ts
export class Collectioner {
  private client WeaviateClient;
  private collections: []string;

  public create(c: CollectionConfig): Promise<CollectionHandle> {
    this.collections.push(c.name);
    return this.client.collections.create(c);
  }
  
  public cleanup(): Promise<void> {
      return Promise.all(this.collections.map(c => this.client.collections.delete(c)));
  }
}

Then use it in a test:

describe('stuff', async () => {
  const client = new WeaviateClient(...);
  const collections = new Collectioner(client);
  afterAll(() => collections.cleanup());
  
  ...
})

Comment thread packages/web/src/index.ts
Comment on lines +38 to +43
params.connectionParams.grpc = {
host: params.connectionParams.http.host,
port: params.connectionParams.http.port,
secure: params.connectionParams.http.secure,
path: '/v1/grpc-web',
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

question: could host, port, and secure be mapped in helpers? Seems like something that'd be common to both node and web, as opposed to path: /v1/grpc-web which is clearly specific to web/ package.

@parkerduckworth

Copy link
Copy Markdown
Contributor

Let's go @tsmith023 !! The time for a TS web client has finally come ✨

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

weaviate-client fails to bundle on Cloudflare Workers due to http2 dependency

5 participants