Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 103 additions & 79 deletions bun.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import type { contract } from "@openkitten/world-contract";
import type * as contract from "@openkitten/world-contract";
import { createORPCClient } from "@orpc/client";
import { RPCLink } from "@orpc/client/fetch";
import type { ContractRouterClient } from "@orpc/contract";

type WorldClient = ContractRouterClient<typeof contract>;
type Client = ContractRouterClient<typeof contract>;

export interface CreateWorldClientOptions {
export interface CreateClientOptions {
getActiveOrganizationId?: () => string | undefined;
}

export function createWorldClient(
export function createClient(
serverURL: string,
options: CreateWorldClientOptions = {},
): WorldClient {
options: CreateClientOptions = {},
): Client {
const link = new RPCLink({
url: `${serverURL}/rpc`,
headers: () => {
Expand All @@ -23,5 +23,5 @@ export function createWorldClient(
fetch: (request, init) =>
globalThis.fetch(request, { ...init, credentials: "include" }),
});
return createORPCClient<WorldClient>(link);
return createORPCClient<Client>(link);
}
14 changes: 0 additions & 14 deletions packages/world/packages/client/lib/create-world-query.ts

This file was deleted.

5 changes: 2 additions & 3 deletions packages/world/packages/client/lib/main.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export type { CreateWorldClientOptions } from "./create-world-client";
export { createWorldClient } from "./create-world-client";
export { createWorldQuery } from "./create-world-query";
export type { CreateClientOptions } from "./create-client";
export { createClient } from "./create-client";
3 changes: 1 addition & 2 deletions packages/world/packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
"dependencies": {
"@openkitten/world-contract": "workspace:*",
"@orpc/client": "^1.14.0",
"@orpc/contract": "^1.14.0",
"@orpc/tanstack-query": "^1.14.0"
"@orpc/contract": "^1.14.0"
},
"devDependencies": {
"@vitest/coverage-istanbul": "^4.1.5",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { afterEach, beforeEach, expect, it, vi } from "vitest";
import { createWorldClient } from "~/lib/create-world-client";
import { createClient } from "~/lib/create-client";

const fetchMock = vi.fn(async (input: Request, init?: RequestInit) => {
void input;
Expand All @@ -19,14 +19,13 @@ afterEach(() => {
});

it("returns a typed client with the contract procedures", () => {
const client = createWorldClient("http://localhost:1234");
expect(typeof client.me).toBe("function");
const client = createClient("http://localhost:1234");
expect(typeof client.workspace.sync).toBe("function");
});

it("sends fetch calls with credentials included to the configured base url", async () => {
const client = createWorldClient("http://localhost:1234");
await client.me().catch(() => {});
const client = createClient("http://localhost:1234");
await client.workspace.sync().catch(() => {});

expect(fetchMock).toHaveBeenCalledTimes(1);
const call = fetchMock.mock.calls[0];
Expand All @@ -41,10 +40,10 @@ it("sends fetch calls with credentials included to the configured base url", asy
});

it("attaches the active organization header when getActiveOrganizationId returns a value", async () => {
const client = createWorldClient("http://localhost:1234", {
const client = createClient("http://localhost:1234", {
getActiveOrganizationId: () => "org_42",
});
await client.me().catch(() => {});
await client.workspace.sync().catch(() => {});

const call = fetchMock.mock.calls[0];
if (!call) throw new Error("Expected fetch to be called");
Expand All @@ -53,8 +52,8 @@ it("attaches the active organization header when getActiveOrganizationId returns
});

it("omits the active organization header when getActiveOrganizationId is not provided", async () => {
const client = createWorldClient("http://localhost:1234");
await client.me().catch(() => {});
const client = createClient("http://localhost:1234");
await client.workspace.sync().catch(() => {});

const call = fetchMock.mock.calls[0];
if (!call) throw new Error("Expected fetch to be called");
Expand All @@ -63,10 +62,10 @@ it("omits the active organization header when getActiveOrganizationId is not pro
});

it("omits the active organization header when getActiveOrganizationId returns undefined", async () => {
const client = createWorldClient("http://localhost:1234", {
const client = createClient("http://localhost:1234", {
getActiveOrganizationId: () => undefined,
});
await client.me().catch(() => {});
await client.workspace.sync().catch(() => {});

const call = fetchMock.mock.calls[0];
if (!call) throw new Error("Expected fetch to be called");
Expand Down
25 changes: 0 additions & 25 deletions packages/world/packages/client/test/create-world-query.test.ts

This file was deleted.

10 changes: 3 additions & 7 deletions packages/world/packages/client/test/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { expect, test } from "vitest";
import { createWorldClient, createWorldQuery } from "~/lib/main";
import { createClient } from "~/lib/main";

test("re-exports createWorldClient", () => {
expect(typeof createWorldClient).toBe("function");
});

test("re-exports createWorldQuery", () => {
expect(typeof createWorldQuery).toBe("function");
test("re-exports createClient", () => {
expect(typeof createClient).toBe("function");
});
9 changes: 0 additions & 9 deletions packages/world/packages/contract/lib/contract.ts

This file was deleted.

8 changes: 2 additions & 6 deletions packages/world/packages/contract/lib/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@ import type {
InferContractRouterInputs,
InferContractRouterOutputs,
} from "@orpc/contract";
import { contract } from "./contract";
import type * as contract from "./router";

export { publicContract } from "./public-contract";
export { userContract } from "./user-contract";
export { userSchema } from "./user-schema";
export { workspaceContract } from "./workspace";
export { contract };
export * from "./router";

export type ContractInputs = InferContractRouterInputs<typeof contract>;
export type ContractOutputs = InferContractRouterOutputs<typeof contract>;
1 change: 0 additions & 1 deletion packages/world/packages/contract/lib/public-contract.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/world/packages/contract/lib/router/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./workspace";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * as workspace from "./sync";
4 changes: 4 additions & 0 deletions packages/world/packages/contract/lib/router/workspace/sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { oc } from "@orpc/contract";
import { workspaceSchema } from "../../workspace-schema";

export const sync = oc.output(workspaceSchema);
6 changes: 0 additions & 6 deletions packages/world/packages/contract/lib/user-contract.ts

This file was deleted.

11 changes: 0 additions & 11 deletions packages/world/packages/contract/lib/user-schema.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { oc } from "@orpc/contract";
import zod from "zod";

const workspaceMemberSchema = zod.object({
Expand All @@ -22,7 +21,7 @@ const workspaceInvitationSchema = zod.object({
expiresAt: zod.date(),
});

const workspaceSchema = zod.object({
export const workspaceSchema = zod.object({
workspace: zod.object({
id: zod.number(),
userId: zod.string().nullable(),
Expand All @@ -47,7 +46,3 @@ const workspaceSchema = zod.object({
createdAt: zod.date(),
}),
});

export const workspaceContract = {
sync: oc.output(workspaceSchema),
};
4 changes: 4 additions & 0 deletions packages/world/packages/contract/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
".": {
"import": "./lib/main.ts",
"types": "./lib/main.ts"
},
"./router/*": {
"import": "./lib/router/*.ts",
"types": "./lib/router/*.ts"
}
},
"scripts": {
Expand Down
7 changes: 0 additions & 7 deletions packages/world/packages/contract/test/contract.test.ts

This file was deleted.

38 changes: 3 additions & 35 deletions packages/world/packages/contract/test/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,6 @@
import { expect, test } from "vitest";
import {
contract,
publicContract,
userContract,
userSchema,
workspaceContract,
} from "~/lib/main";
import { workspace } from "~/lib/main";

test("re-exports the merged contract", () => {
expect(contract.me).toBeDefined();
expect(contract.workspace.sync).toBeDefined();
});

test("re-exports the public contract", () => {
expect(publicContract).toBeDefined();
});

test("re-exports the user contract", () => {
expect(userContract.me).toBeDefined();
});

test("re-exports the workspace contract", () => {
expect(workspaceContract.sync).toBeDefined();
});

test("re-exports the user schema", () => {
const user = userSchema.parse({
id: "u_5",
name: "Linus",
email: "linus@example.com",
emailVerified: true,
image: null,
createdAt: new Date(),
updatedAt: new Date(),
});
expect(user.id).toBe("u_5");
test("re-exports the workspace router as a nested namespace with sync", () => {
expect(workspace.sync).toBeDefined();
});
6 changes: 0 additions & 6 deletions packages/world/packages/contract/test/public-contract.test.ts

This file was deleted.

6 changes: 6 additions & 0 deletions packages/world/packages/contract/test/router/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { expect, test } from "vitest";
import { workspace } from "~/lib/router";

test("re-exports the workspace folder as a nested router with sync", () => {
expect(workspace.sync).toBeDefined();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { expect, test } from "vitest";
import { workspace } from "~/lib/router/workspace";

test("aggregates the sync procedure under the workspace folder", () => {
expect(workspace.sync).toBeDefined();
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, test } from "vitest";
import { workspaceContract } from "~/lib/workspace";
import { sync } from "~/lib/router/workspace/sync";

const sampleWorkspace = {
workspace: {
Expand Down Expand Up @@ -40,21 +40,21 @@ const sampleWorkspace = {
},
};

test("sync procedure is defined", () => {
expect(workspaceContract.sync).toBeDefined();
test("exposes an output schema", () => {
expect(sync["~orpc"].outputSchema).toBeDefined();
});

test("sync output schema accepts a personal workspace shape", () => {
const def = workspaceContract.sync["~orpc"];
test("output schema accepts a personal workspace shape", () => {
const def = sync["~orpc"];
const result: unknown = def.outputSchema?.parse(sampleWorkspace);
expect(result).toMatchObject({
workspace: { isPersonal: true, userId: "u_1" },
house: { name: "Ada's House" },
});
});

test("sync output schema accepts a team workspace shape", () => {
const def = workspaceContract.sync["~orpc"];
test("output schema accepts a team workspace shape", () => {
const def = sync["~orpc"];
const result: unknown = def.outputSchema?.parse({
...sampleWorkspace,
workspace: {
Expand All @@ -77,20 +77,20 @@ test("sync output schema accepts a team workspace shape", () => {
});
});

test("sync output schema rejects when workspace is missing", () => {
const def = workspaceContract.sync["~orpc"];
test("output schema rejects when workspace is missing", () => {
const def = sync["~orpc"];
const { workspace: _w, ...rest } = sampleWorkspace;
expect(() => def.outputSchema?.parse(rest)).toThrow();
});

test("sync output schema rejects when activeMember is missing", () => {
const def = workspaceContract.sync["~orpc"];
test("output schema rejects when activeMember is missing", () => {
const def = sync["~orpc"];
const { activeMember: _a, ...rest } = sampleWorkspace;
expect(() => def.outputSchema?.parse(rest)).toThrow();
});

test("sync output schema rejects when a member is missing required user fields", () => {
const def = workspaceContract.sync["~orpc"];
test("output schema rejects when a member is missing required user fields", () => {
const def = sync["~orpc"];
expect(() =>
def.outputSchema?.parse({
...sampleWorkspace,
Expand Down
Loading