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

```ts
const RelayUrlFromString: transform(
  "RelayUrlFromString",
  String,
  RelayUrl,
  {
    from: (value: string): Result<string, RelayUrlFromStringError> => {
      const url = WebSocketUrlFromString.fromUnknown(value);
      return url.ok && !url.value.includes("?")
        ? ok(url.value)
        : err({ type: "RelayUrlFromString", value });
    },
    to: (value: RelayUrl) => value,
  },
  (error) =>
    `The value ${JSON.stringify(error.value)} is not a valid relay URL.`,
);
```

Defined in: [packages/common/src/local-first/Owner.ts:640](https://github.com/evoluhq/evolu/blob/aa223771feea747ffb1b0f5f3271574455633e37/packages/common/src/local-first/Owner.ts#L640)

Transforms a relay URL into its canonical [RelayUrl](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/RelayUrl).

Accepts what [WebSocketUrlFromString](https://evolu.dev/docs/api-reference/common/WebSocket/variables/WebSocketUrlFromString) accepts when the result has no
query. Encoding returns the canonical spelling, not the original one.

### Example

```ts
import {
  assertEqual,
  assertErr,
  assertOk,
  RelayUrlFromString,
} from "@evolu/common";

assertOk(
  RelayUrlFromString.fromUnknown("wss://free.evoluhq.com"),
  "wss://free.evoluhq.com/",
);

const invalid = RelayUrlFromString.fromUnknown("free.evoluhq.com");
assertErr(invalid, {
  type: "RelayUrlFromString",
  value: "free.evoluhq.com",
});
assertEqual(
  RelayUrlFromString.formatError(invalid.error),
  'The value "free.evoluhq.com" is not a valid relay URL.',
);
```