[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › [local‑first/Relay](https://evolu.dev/docs/api-reference/common/local-first/Relay) › RelayConfig

Defined in: [packages/common/src/local-first/Relay.ts:43](https://github.com/evoluhq/evolu/blob/49ea8ca499566aba270f8cb601e7f49aa62320f8/packages/common/src/local-first/Relay.ts#L43)

## Extends

- [`StorageConfig`](https://evolu.dev/docs/api-reference/common/local-first/Storage/interfaces/StorageConfig)

## Extended by

- [`NodeJsRelayConfig`](https://evolu.dev/docs/api-reference/nodejs/interfaces/NodeJsRelayConfig)

## Properties

<a id="isownerallowed"></a>

### isOwnerAllowed?

```ts
readonly optional isOwnerAllowed?: (ownerId: string & Brand<"Id"> & Brand<"OwnerId">, options: {
  signal: AbortSignal;
}) => Awaitable<boolean>;
```

Defined in: [packages/common/src/local-first/Relay.ts:126](https://github.com/evoluhq/evolu/blob/49ea8ca499566aba270f8cb601e7f49aa62320f8/packages/common/src/local-first/Relay.ts#L126)

Optional callback to check if an [OwnerId](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/OwnerId) is allowed to access the
relay. If this callback is not provided, all owners are allowed.

The callback receives the [OwnerId](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/OwnerId) and an options object with an
abort `AbortSignal`, and returns a [Awaitable](https://evolu.dev/docs/api-reference/common/Types/type-aliases/Awaitable) boolean: `true` to
allow access, or `false` to deny.

The callback can be synchronous (for SQLite or in-memory checks) or
asynchronous (for calling remote APIs).

The callback returns a boolean rather than an error type because error
handling and logging are the responsibility of the callback
implementation.

OwnerId is used rather than short-lived tokens because this only controls
relay access, not write permissions. Since all data is encrypted on the
relay, OwnerId exposure is safe.

Owners specify which relays to connect to via `OwnerTransport`. In
WebSocket-based implementations, this check occurs before accepting the
connection, with the OwnerId typically extracted from the URL query string
(e.g., `ws://localhost:4000?ownerId=...`). The relay requires the URL to be
in the correct format for OwnerId extraction.

### Example

```ts
import {
  AppName,
  createAppOwner,
  createEvolu,
  createOwnerWebSocketTransport,
  createOwnerSecret,
  createRandomBytes,
  id,
  type AnyTask,
} from "@evolu/common";

// Create once, persist the mnemonic securely, and restore it on later runs.
const appOwner = createAppOwner(
  createOwnerSecret({ randomBytes: createRandomBytes() }),
);
// Client: include the OwnerId so the relay can authenticate the connection.
const transport = createOwnerWebSocketTransport({
  url: "wss://relay.evolu.dev",
  ownerId: appOwner.id,
});

const createTodoEvolu = createEvolu(
  { todo: { id: id("Todo") } },
  {
    appName: AppName.orThrow("AuthenticatedRelayExample"),
    appOwner,
    transports: [transport],
  },
);
expectTypeOf(createTodoEvolu).toExtend<AnyTask>();

// Relay: accept owners allowed by the app's access policy.
type IsOwnerAllowed = NonNullable<RelayConfig["isOwnerAllowed"]>;
const allowedOwnerIds = new Set([appOwner.id]);
const isOwnerAllowed: IsOwnerAllowed = (ownerId, { signal }) =>
  !signal.aborted && allowedOwnerIds.has(ownerId);

expect(
  isOwnerAllowed(appOwner.id, {
    signal: new AbortController().signal,
  }),
).toBe(true);
expect(transport.url).toContain(`ownerId=${appOwner.id}`);
```

### isOwnerWithinQuota

```ts
readonly isOwnerWithinQuota: (ownerId: string & Brand<"Id"> & Brand<"OwnerId">, requiredBytes: number & Brand<"NonNaN"> & Brand<"Finite"> & Brand<"Int"> & Brand<"NonNegative"> & Brand<"Positive">) => Awaitable<boolean>;
```

Defined in: [packages/common/src/local-first/Storage.ts:98](https://github.com/evoluhq/evolu/blob/49ea8ca499566aba270f8cb601e7f49aa62320f8/packages/common/src/local-first/Storage.ts#L98)

Callback called before an attempt to write, to check if an [OwnerId](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/OwnerId)
has sufficient quota for the write.

The callback receives the [OwnerId](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/OwnerId) and the total bytes that would be
stored after the write (current stored bytes plus incoming bytes), and
returns a [Awaitable](https://evolu.dev/docs/api-reference/common/Types/type-aliases/Awaitable) boolean: `true` to allow the write, or `false`
to deny it due to quota limits.

The callback can be synchronous (for SQLite or in-memory checks) or
asynchronous (for calling remote APIs).

The callback returns a boolean rather than an error because error handling
and logging are the responsibility of the callback implementation.

Relay deployments configure this callback. Client applications can observe
a denied relay write as a `ProtocolQuotaError` by subscribing once to the
shared `EvoluErrorDep.evoluError` store returned by `createEvoluDeps`.

### Example

```ts
import {
  createAppOwner,
  createOwnerSecret,
  createRandomBytes,
  PositiveInt,
} from "@evolu/common";

// Create once, persist the mnemonic securely, and restore it on later runs.
const appOwner = createAppOwner(
  createOwnerSecret({ randomBytes: createRandomBytes() }),
);
const maxBytes = PositiveInt.orThrow(1024);
const relayStorageConfig: StorageConfig = {
  isOwnerWithinQuota: (ownerId, requiredBytes) =>
    ownerId === appOwner.id && requiredBytes <= maxBytes,
};

expect(
  await relayStorageConfig.isOwnerWithinQuota(
    appOwner.id,
    PositiveInt.orThrow(2048),
  ),
).toBe(false);
```

#### Inherited from

[`StorageConfig`](https://evolu.dev/docs/api-reference/common/local-first/Storage/interfaces/StorageConfig).[`isOwnerWithinQuota`](https://evolu.dev/docs/api-reference/common/local-first/Storage/interfaces/StorageConfig#isownerwithinquota)

---

<a id="name"></a>

### name?

```ts
readonly optional name?: string & Brand<"UrlSafeString"> & Brand<"Name">;
```

Defined in: [packages/common/src/local-first/Relay.ts:50](https://github.com/evoluhq/evolu/blob/49ea8ca499566aba270f8cb601e7f49aa62320f8/packages/common/src/local-first/Relay.ts#L50)

The relay name.

Implementations can use this for identification purposes (e.g., database
file name, logging).