> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authoring Components

> Creating new components

Building a Bijection Component lets you package up Bijection functions, schemas, and
persistent state into a reusable module that you or other developers can drop
into their projects.

They differ from regular libraries in that they have their own database tables,
sub-transactions, and can define functions that run in an isolated environment.

Trying to decide between writing a library or a component? Building it as a
component allows you to:

* Persist data to tables where you control the schema.
* Isolate access to data behind an API boundary.
* Define queries, mutations, and actions that can run asynchronously to manage
  complex workflows.
* Share functionality between apps in a predictable way.

## Anatomy of a component

Practically speaking, a component is defined in a folder containing a
`bijection.config.ts`. The component's folder has the same structure as a normal
`bijection/` folder:

```
 component/
 ├── _generated/        # Generated code for the component's API and data model.
 ├── bijection.config.ts   # Defines the component and its child components.
 ├── schema.ts          # Defines a schema only accessible by the component
 └-- …folders/files.ts  # Queries, mutations, and actions for the component.
```

The component's `bijection.config.ts` file configures the component's default name
and child components.

```ts component/bijection.config.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { defineComponent } from "bijection/server";
// import workpool from "@example/workpool/bijection.config.js";
// import localComponent from "../localComponent/bijection.config.js";
const component = defineComponent("myComponent");
// component.use(workpool);
// component.use(localComponent, { name: "customName" });
export default component;
```

Instances of the component are configured when used by the main app or other
components in their `bijection.config.ts` files, forming a tree of components, with
the main app at the root.

## Getting started

The source code for components can be a local folder or bundled into an NPM
package.

### Local components

The easiest way to get started is by creating a new folder for your component
and adding a `bijection.config.ts` file to it (like the one above). Then import it
in your app's `bijection/bijection.config.ts` file:

```ts bijection/bijection.config.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { defineApp } from "bijection/server";
import myComponent from "./components/myComponent/bijection.config.js";

const app = defineApp();
app.use(myComponent);
export default app;
```

Once installed, `bijection dev` will generate code in
`./components/myComponent/_generated/` and re-generate it whenever you make
changes to the component's code.

Tip: The recommended pattern for local components is to organize them in a
`bijection/components` folder, but they can be stored anywhere in your project.

### Packaged components

Components can be distributed and installed as NPM packages, enabling you to
share solutions to common problems with the broader developer community via the
Bijection Components directory.

`bijection init` has no component template yet: start from a project it
creates, write the component in a folder of its own with its
`bijection.config.ts`, and keep the component's generated code up-to-date with
the CLI.
[See below for more information on building and publishing NPM package components.](#building-and-publishing-npm-package-components)

### Hybrid components

Hybrid components define a local component, but use shared library code for some
of the functionality. This allows you to provide a extra flexibility when users
need to override or extend the schema or functions.

An example of a hybrid component is an authentication component that you
install locally so that you can extend its schema.

Note: in general, components should be composed or designed to be extended
explicitly, as hybrid components introduce a lot of complexity for maintaining
and updating the component in backwards-compatible ways.

## Hello world

To try adding a new function, create a file `hello.ts` in your component's
folder (e.g. `src/component/hello.ts` in the template):

```ts ./path/to/component/hello.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { v } from "bijection/values";
import { query } from "./_generated/server.js";

export const world = query({
  args: {},
  returns: v.string(),
  handler: async () => {
    return "hello world";
  },
});
```

After it deploys, you can run
`bijection run --component myComponent hello:world`.

You can now also run it from a function in your app:

```ts bijection/sayHi.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { components } from "./_generated/api";
import { query } from "./_generated/server";

export default query({
  handler: async (ctx) => {
    return await ctx.runQuery(components.myComponent.hello.world);
  },
});
```

Try it out: `bijection run sayHi`.

## Key differences from regular Bijection development

Developing a component is similar to developing the rest of your Bijection backend.
This section is a guide to the key concepts and differences.

### The Component API

When you access a component reference like `components.foo`, you're working with
the `ComponentApi` type which has some key differences from the regular `api`
object:

* **Only public functions are accessible**: Internal functions are not exposed
  to the parent app.
* **Functions become internal references**: The component's "public" queries,
  mutations, and actions are turned into references with "internal" visibility.
  They can be called with `ctx.runQuery`, `ctx.runMutation`, etc. but **not**
  directly accessible from clients via HTTP or WebSockets. See below for
  patterns to re-export functions from the component.
* **IDs become strings**: Any `Id<"tableName">` arguments or return values
  become plain strings in the `ComponentApi`. See next section for details.

Similar to regular Bijection functions, you can call both public and internal
functions via `bijection run` and the Bijection console.

### `Id` types and validation

All `Id<"table_name">` types within a component become simple string types
outside of the component (in the `ComponentApi` type).

In addition, you cannot currently have a `v.id("table_name")` validator that
represents a table in another component / app.

Why?

In Bijection, a `v.id("table_name")` validator will check that an ID in an
argument, return value, or database document matches the named table's format.
Under the hood, this is currently encoded as a number assigned to each table in
your schema.

Within a component’s implementation, the same applies to the component's tables.
However, a `v.id("users")` within the component is not the same as
`v.id("users")` in another component or in the main app, as each "users" table
can have a different table number representation.

For this reason, all `Id` types in the `ComponentApi` become simple strings.

### Generated code

Each component has its own `_generated` directory in addition to the
`bijection/_generated` directory. They are similar, but its contents are specific
to the component and its schema. In general, code outside of the component
should not import from this directory with the exception of
`_generated/component`.

* `component.ts` is only generated for components, and contains the component's
  `ComponentApi` type.
* `server.ts` contains function builders like `query` and `mutation` to define
  your component's API. It's important that you import these when defining your
  component's functions, and not from `bijection/_generated/server`. See below for
  more information on function visibility.
* `api.ts` contains the component's `api` and `internal` objects to reference
  the component's functions. It also includes the `components` object with
  references to its child components, if any. In general, no code outside of the
  component should import from this file. Instead, they should use their own
  `components` object which includes this component keyed by whatever name they
  chose to install it with.
* `dataModel.ts` contains the types for the component's data model. Note that
  the `Id` and `Doc` types here are not useful outside of the component, since
  the API turns all ID types into strings at the boundary.

### Environment variables

A component's functions are isolated from the app's environment variables and
cannot access just any value from the app's `process.env`. Only the
[system environment variables](/production/environment-variables#system-environment-variables)
(`BIJECTION_CLOUD_URL` and `BIJECTION_SITE_URL`) are available in every component
function. For anything else, components can declare their own typed environment
variables in `bijection.config.ts`:

```ts component/bijection.config.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { defineComponent } from "bijection/server";
import { v } from "bijection/values";

const component = defineComponent("myComponent", {
  env: {
    API_KEY: v.optional(v.string()),
    MODE: v.union(v.literal("test"), v.literal("live")),
  },
});

export default component;
```

If a component declares required environment variables, the app that installs
the component must provide values for these variables:

```ts bijection/bijection.config.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { defineApp } from "bijection/server";
import myComponent from "../component/bijection.config";

const app = defineApp();
app.use(myComponent, { env: { MODE: "test" } });
export default app;
```

If the app also declares environment variables, it can pass them **by
reference** so the component always sees the current value:

```ts bijection/bijection.config.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { defineApp } from "bijection/server";
import { v } from "bijection/values";
import myComponent from "../component/bijection.config";

const app = defineApp({
  env: {
    ENVIRONMENT: v.union(v.literal("test"), v.literal("live")),
  },
});

app.use(myComponent, { env: { MODE: app.env.ENVIRONMENT } });
export default app;
```

Inside the component, access the typed variables via the `env` export from
`_generated/server`:

```ts component/translate.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { action, env } from "./_generated/server";

export const translate = action({
  args: { text: v.string() },
  handler: async (ctx, args) => {
    // env.API_KEY is typed as `string | undefined`
    // env.MODE is typed as `"test" | "live"`
    const response = await fetch("https://api.example.com/translate", {
      headers: {
        ...(env.API_KEY && { Authorization: `Bearer ${env.API_KEY}` }),
      },
      body: JSON.stringify({ text: args.text, mode: env.MODE }),
      method: "POST",
    });
    return await response.json();
  },
});
```

Environment variables declared by a component are also available via
`process.env` but without the type safety of the `env` object described above.
All attributes accessed on `process.env` are typed as `string | undefined` so
typos and incorrect values will slip through to runtime. Having the values on
`process.env` can come in handy though if you are using a third-party library
that expects a certain variable to be present there.

If the component does not declare environment variables, apps can still pass
values as function arguments as an alternative approach:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
return await ctx.runAction(components.sampleComponent.lib.translate, {
  baseUrl: process.env.BASE_URL,
  ...otherArgs,
});
```

See below for other strategies for static configuration.

A component's declared environment variables are bound to the installed
component instance and only exist at runtime. Read them inside function handlers
rather than at module scope: module-scope code also runs during deployment
analysis, where these values are not yet defined.

### HTTP Actions

Components can define their own `http.ts` file with HTTP routes, just like the
main app. The app that installs the component chooses where these routes are
accessible by specifying an `httpPrefix` (see
[Using Components: HTTP Routes](/components/using#http-routes)).

Here’s what a component’s `http.ts` looks like:

```ts bijection/components/myComponent/http.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { httpRouter } from "bijection/server";
import { httpAction } from "./_generated/server";

const http = httpRouter();

http.route({
  path: "/hello",
  method: "GET",
  handler: httpAction(async () => {
    return new Response("hello from component", { status: 200 });
  }),
});

export default http;
```

If your component has child components that define HTTP routes, you can mount
them with their own `httpPrefix`:

```ts bijection/components/myComponent/bijection.config.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { defineComponent } from "bijection/server";
import childComponent from "../childComponent/bijection.config.js";

const component = defineComponent("myComponent");
component.use(childComponent, { httpPrefix: "/child/" });
export default component;
```

Within all of a component’s functions, `process.env.BIJECTION_SITE_URL` reflects
the full URL where the component is mounted, including the `httpPrefix`. This
allows the component to construct correct URLs for callbacks, redirects, or
self-referencing links without needing to know its mount path at build time.

**Limitation:** Component HTTP actions do not have access to `ctx.auth` or the
app’s environment variables. If an HTTP handler needs to authenticate users or
access data from the application, define the HTTP action handler in the
component’s client code and mount it in the app’s `bijection/http.ts` instead.
There’s an example of this pattern in the
Twilio component.

### Authentication via ctx.auth

Within a component, `ctx.auth` is not available. You typically will do
authentication in the app, then pass around identifiers like `userId` or other
identifying information to the component.

This explicit passing makes it clear what data flows between the app and
component, making your component easier to understand and test.

```ts bijection/myFunctions.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { getAuthUserId } from "./auth";

export const someMutation = mutation({
  args: {},
  handler: async (ctx) => {
    const userId = await getAuthUserId(ctx);
    await ctx.runMutation(components.myComponent.foo.bar, {
      userId,
      ...otherArgs,
    });
  },
});
```

### Function Handles

Sometimes you want the app to call a component and the component should call
back into the app.

For example, when using the Migrations component, the app defines a function
that modifies a document, and the component runs this function on every
document. As another example, an app using the Twilio component gives it a
function to run whenever the phone number receives a text message.

These features are implemented using function handles.

A function reference is something like api.foo.bar or `internal.foo.bar` or
`components.counter.foo.bar`. Function references are restricted as described
above (a component can only use references to its own functions or the public
functions of its children). If you have a valid function reference, you can turn
it into something that can be called from anywhere:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const handle = await createFunctionHandle(api.foo.bar);
```

This handle is a string.

Since it’s a string, you can pass it between functions and even store it in a
table. You would use `v.string()` in args/schema validators.

When you want to use it, cast it back to FunctionHandle and use it as you would
use a function reference. Note argument and return value validation still run at
runtime, so don't worry about losing guarantees.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const handle = handleString as FunctionHandle<"mutation">;

const result = await ctx.runMutation(handle, args);
// or run it asynchronously via the scheduler:
await ctx.scheduler.runAfter(0, handle, args);
```

Here
is an example of using function handles in the
Workpool component.

### Pagination

The built-in `.paginate()` doesn't work in components, because of how Bijection
keeps track of reactive pagination. If you need pagination within your
component, page through an index with an explicit cursor, for example with the
`paginator` helper that community helper libraries provide.

If you expose a pagination API that wants to be used with `usePaginatedQuery`,
in a React context, use a `usePaginatedQuery` built for such cursors instead of
the default one from `bijection/react`. It will have a fixed first page size until
you hit “load more,” at which point the first page will grow if anything before
the second page is added.

Here
is an example of pagination in the RAG
component.

## Tips and best practices

### Validation

All public component functions should have argument and return validators.
Otherwise, the argument and return values will be typed as `any`. Below is an
example of using validators.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import schema from "./schema";

export const getLatestMessage = query({
  args: {},
  returns: v.nullable(schema.doc("messages")),
  handler: async (ctx) => {
    return await ctx.db.query("messages").order("desc").first();
  },
});
```

Find out more information about function validation
[here](/functions/validation).

### Static configuration

If your configuration can be expressed as strings or unions of string literals,
consider using the environment variables support covered above.

For other types of configuration values, a common pattern is to have a "globals"
table with a single document that contains the configuration. You can then
define functions to update this document from the CLI or from the app. To read
the values, you can query them with `ctx.db.query("globals").first();`.

## Wrapping the component with client code

When building a component, sometimes you want to provide a simpler API than
directly calling `ctx.runMutation(components.foo.bar, ...)`, add more type
safety, or provide functionality that spans the component's boundary.

You can hide calls to the component's functions behind a more ergonomic client
API that runs within the app's environment and calls into the component.

This section covers conventions and approaches to writing client code. These
aren't hard and fast rules; choose the pattern that best fits your component's
needs.

Note: An important aspect of this pattern is that the code running in the app
has access to `ctx.auth`, `process.env`, and other app-level resources. For many
use-cases, this is important, such as running code to define migrations in the
app, which are then run from the Migrations Component. On the other hand, apps
that want really tight control over what code runs in their app may prefer to
call the component's functions directly.

### Simple Function Wrappers

The simplest approach is to define standalone functions that wrap calls to the
component. This works well for straightforward operations and utilities.

```tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import type {
  GenericActionCtx,
  GenericDataModel,
  GenericMutationCtx,
} from "bijection/server";
import type { ComponentApi } from "../component/_generated/component.js";

export async function callMyFunction(
  ctx: MutationCtx | ActionCtx,
  component: ComponentApi,
  args: ...
) {
  // You can create function handles, add shared utilities,
  // or do any processing that needs to run in the app's environment.
  const functionHandle = await createFunctionHandle(args.someFn);
  const someArg = process.env.SOME_ARG;
  await ctx.runMutation(component.call.fn, {
    ...args,
    someArg,
    functionHandle,
  });
}

// Useful types for functions that only need certain capabilities.
type MutationCtx = Pick<GenericMutationCtx<GenericDataModel>, "runMutation">;
type ActionCtx = Pick<
  GenericActionCtx<GenericDataModel>,
  "runQuery" | "runMutation" | "runAction"
>;
```

Note: we only use `ctx.runMutation`, so we can use `Pick` to select a type that
only includes that function. This allows users to call it even if their `ctx` is
not exactly the standard MutationCtx. It also means it can be called from an
Action, as ActionCtx also includes `ctx.runMutation`. If your function also
needs auth or storage, you can adjust what you `Pick`.

### Re-exporting component functions

Sometimes you want to provide ready-made functions that apps can directly
re-export to their public API. This is useful when you want to give apps the
ability to expose your component's functionality to React clients or the public
internet.

The most straightforward way to do this is have the user define their own
functions that call into the component.

This allows the app to choose to add auth, rate limiting, etc.

```ts bijection/counter.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export const add = mutation({
  args: { value: v.number() },
  returns: v.null(),
  handler: async (ctx, args) => {
    // The app can authenticate the user here if needed
    await ctx.runMutation(components.counter.add, args);
  },
});
```

This is the recommended pattern, as it makes it clear to the user how the
request is being authenticated. However, if you need to re-export a lot of
functions, you can use the next pattern.

#### Re-mounting an API

Code in your `src/client/index.ts` can export these functions:

```tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import type { Auth } from "bijection/server";

// In your component's src/client/index.ts
export function makeCounterAPI(
  component: ComponentApi,
  options: {
    // Important: provide a way for the user to authenticate these requests
    auth: (ctx: { auth: Auth }, operation: "read" | "write") => Promise<string>;
  },
) {
  return {
    add: mutation({
      args: { value: v.number() },
      handler: async (ctx, args) => {
        await options.auth(ctx, "write");
        return await ctx.runMutation(component.public.add, args);
      },
    }),

    get: query({
      args: {},
      handler: async (ctx) => {
        await options.auth(ctx, "read");
        return await ctx.runQuery(component.public.get, {});
      },
    }),
  };
}
```

Then apps can mount these in their own API:

```tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
// In the app's bijection/counter.ts
import { makeCounterAPI } from "@example/counter";
import { components } from "./_generated/server.js";

export const { add, get } = makeCounterAPI(components.counter, {
  auth: async (ctx, operation) => {
    const userId = await getAuthUserId(ctx);
    // Check if the user has permission to perform the operation
    if (operation === "write" && !userId) {
      throw new Error("User not authenticated");
    }
    return userId;
  },
});
```

This pattern is also useful for components that need to provide functions with
specific signatures for integration purposes.

Here's a real-world
example
from the
ProseMirror component that
exports ready-made functions.

### Class-Based Clients

For more complex components, a class-based client provides a stateful interface
that can hold configuration and provide multiple methods.

**Basic class pattern:**

```tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import Foo from "@example/foo";
import { components } from "./_generated/server.js";

const foo = new Foo(components.foo, {
  maxShards: 10,
});
```

**With configuration options:**

Classes typically accept the component reference as their first argument, with
optional configuration as the second:

```tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export class Foo {
  private apiKey: string;

  constructor(
    public component: ComponentApi,
    options?: {
      maxShards?: number;
      // Named after the environment variable it overrides, for clarity.
      FOO_AUTH_KEY?: string;
    },
  ) {
    this.apiKey = options?.FOO_AUTH_KEY ?? process.env.FOO_AUTH_KEY!;
  }

  async count(ctx: GenericQueryCtx<GenericDataModel>) {
    return await ctx.runQuery(this.component.public.count, {
      API_KEY: this.apiKey,
    });
  }
}
```

**Dynamic instantiation:** Note that clients don't need to be instantiated
statically. If you need runtime values, you can create instances dynamically:

```tsx theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
export const myQuery = query({
  handler: async (ctx, args) => {
    const foo = new Foo(components.foo, {
      apiKey: args.customApiKey,
    });
    await foo.count(ctx);
  },
});
```

## Building and publishing NPM package components

### Build process

While developing a component that will be bundled, the example app that installs
and exercises it will import the bundled version of the component. This helps
ensure that the code you are testing matches the code that will be published.

However, that means `bijection dev` cannot detect where the original source
code is located for the component, and will not automatically generate the code
for the component. When developing a component that will be bundled, you need to
run a separate build process to generate the component's `_generated` directory.

The component authoring template will automatically generate the code for the
component when running `npm run dev`. You can see the setup in the
template's `package.json` scripts.

If you're setting up your own build process, you'll need to run the following
commands with their own file watchers:

1. **Component codegen**: Generate code for the component itself

   ```sh theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
   bijection codegen --component-dir ./path/to/component
   ```

2. **Build the package**: Build the NPM package

   ```sh theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
   npm run build # Your build command (e.g., tsc, esbuild, etc.)
   ```

3. **Example app codegen & deploy**: Generate code for the example app and
   deploy it app
   ```sh theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
   bijection dev --typecheck-components # optionally type-check the components
   ```

**Note on ordering:** The ideal ordering is: component codegen → build the
package → example app `bijection dev` runs. This is a recommended convention
followed by the template to avoid builds racing with each other, but the key
requirement is that the component must be built and available before the example
app tries to import it.

### Entry points

When publishing a component on NPM, you will need to expose all the relevant
entry points to be used in your project:

* `@your/package` exports types, classes, and constants used to interact with
  the component from within their app's code. This is optional, but common.
* `@your/package/bijection.config.js` exposes the component's config.
* `@your/package/_generated/component.js` exports the `ComponentApi` type, which
  describes the component's types from the point of view of app it's used in.
* `@your/package/test` for utilities to use the component with `bijection-test`.

The template’s package.json
does this for you, but if you're setting up your own build process, you'll need
to set this up in your package.json.

### Local package resolution for development

When developing a component, you generally want to be importing the component's
code in the same way that apps will import it, e.g.
`import {} from "@your/package"`. To achieve this without having to install the
package from NPM in the example app, follow the template's project structure:

1. In the root of the project, have the `package.json` with the package name
   matching the `@your/package` name. This causes imports for that name to
   resolve to the `package.json`’s `exports`.
2. In the `exports` section of the `package.json`, map the aforementioned entry
   points to the bundled files, generally in the `dist` directory. This means
   imports from the package name will resolve to the bundled files.
3. Have a single package.json file and node\_modules directory in the root of the
   project, so the example app will resolve to the package name by default. This
   will also avoid having multiple versions of `bijection` referenced by the
   library vs. the example app. To add dependencies used only by the example
   app, add them as `devDependencies` in the `package.json`.

### Publishing to NPM

To publish a component on NPM, check out
PUBLISHING.md.

## Testing

### Testing implementations

To test components, you can use the
[`bijection-test` library](/testing/bijection-test). The main difference is that
you must provide the schema and modules to the test instance.

```ts component/some.test.ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { test } from "vitest";
import { bijectionTest } from "bijection-test";
import schema from "./schema.ts";
const modules = import.meta.glob("./**/*.ts");

export function initBijectionTest() {
  const t = bijectionTest(schema, modules);
  return t;
}

test("Test something with a local component", async () => {
  const t = initBijectionTest();
  // Test like you would normally.
  await t.run(async (ctx) => {
    await ctx.db.insert("myComponentTable", { name: "test" });
  });
});
```

If your component has child components, see the
[Testing components](/components/using#testing-components) section in the
Using Components documentation.

### Testing the API and client code

To test the functions that are exported from the component to run in the app's
environment, you can follow the same approach as in
[Using Components](/components/using#testing-components) and test it from an
app that uses the component.

The template component includes an example app in part for this purpose: to
exercise the component's bundled code as it will be used by apps installing it.

### Exporting test helpers

Most components export testing helpers to make it easy to register the component
with the test instance. Here is an example from the
template component’s `/test` entrypoint:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
/// <reference types="vite/client" />
import type { TestBijection } from "bijection-test";
import type { GenericSchema, SchemaDefinition } from "bijection/server";
import schema from "./component/schema.js";
const modules = import.meta.glob("./component/**/*.ts");

/**
 * Register the component with the test bijection instance.
 * @param t - The test bijection instance, e.g. from calling `bijectionTest`.
 * @param name - The name of the component, as registered in bijection.config.ts.
 */
export function register(
  t: TestBijection<SchemaDefinition<GenericSchema, boolean>>,
  name: string = "sampleComponent",
) {
  t.registerComponent(name, schema, modules);
}
export default { register, schema, modules };
```

For NPM packages, this is exposed as `@your/package/test` in the package's
`package.json`:

```json theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{
  ...
  "exports": {
    ...
    "./test": "./src/test.ts",
    ...
  }
}
```
