From ccc84071a16db934ba1f46f8ed3f13b6a8e96ed9 Mon Sep 17 00:00:00 2001 From: Rae McKelvey <633012+okdistribute@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:05:27 -0700 Subject: [PATCH 1/5] docs(add-a-relay): show relay config in all four languages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The relay setup snippet was Rust-only. Add Python, Swift, and Kotlin, all going through the iroh-services preset so every example is authenticated — dedicated relays reject an endpoint without a relay-scoped access token. Also correct the free-project note: it told you to omit relay URLs, which the bindings reject. That path is Rust-only. Depends on iroh-ffi#284, which adds preset_iroh_services to the bindings. Co-Authored-By: Claude Opus 5 (1M context) --- snippets/relay-preset-config.mdx | 92 +++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 8 deletions(-) diff --git a/snippets/relay-preset-config.mdx b/snippets/relay-preset-config.mdx index beb7a5f..cb327f4 100644 --- a/snippets/relay-preset-config.mdx +++ b/snippets/relay-preset-config.mdx @@ -1,17 +1,20 @@ -Your dedicated relays require authentication by default. Your endpoint -authenticates to them with your project's API key. The `iroh_services::preset()` builder handles -this for you: it mints a short-lived access token scoped to your endpoint's key -and configures the endpoint to use your relays. +Your dedicated relays require authentication. Your endpoint authenticates to +them with your project's API key: the iroh-services preset mints a short-lived +access token scoped to your endpoint's key and to relay use only, then +configures the endpoint to use your relays. -Add the `iroh-services` crate to your project: +In Rust, add the `iroh-services` crate to your project: ```bash cargo add iroh-services ``` -Then build a preset and bind your endpoint with it: +The Python, Swift, and Kotlin bindings ship the preset as part of `iroh-ffi`, +with no extra dependency needed. -```rust + + +```rust Rust use iroh::Endpoint; #[tokio::main] @@ -36,6 +39,79 @@ async fn main() -> anyhow::Result<()> { } ``` +```python Python +import asyncio +import iroh + +async def main(): + # Build a preset pointing at your dedicated relays, authenticated with + # your project's API key. In production, load the key from a config file + # or environment variable instead of hardcoding it. + preset = iroh.preset_iroh_services( + iroh.ServicesPresetOptions( + relays=["YOUR_RELAY_URL_US", "YOUR_RELAY_URL_EU"], + api_secret="YOUR_API_KEY", + ) + ) + + # Bind the endpoint with the preset, then wait until it's online to + # confirm it has an authorized connection to a relay. + ep = await iroh.Endpoint.bind(iroh.EndpointOptions(preset=preset)) + await ep.online() + +asyncio.run(main()) +``` + +```swift Swift +import IrohLib + +// Build a preset pointing at your dedicated relays, authenticated with your +// project's API key. In production, load the key from a config file or +// environment variable instead of hardcoding it. +let preset = try presetIrohServices(options: ServicesPresetOptions( + relays: ["YOUR_RELAY_URL_US", "YOUR_RELAY_URL_EU"], + apiSecret: "YOUR_API_KEY" +)) + +// Bind the endpoint with the preset, then wait until it's online to confirm +// it has an authorized connection to a relay. +let ep = try await Endpoint.bind(options: EndpointOptions(preset: preset)) +await ep.online() +``` + +```kotlin Kotlin +import computer.iroh.* +import kotlinx.coroutines.runBlocking + +fun main() = runBlocking { + // Build a preset pointing at your dedicated relays, authenticated with + // your project's API key. In production, load the key from a config file + // or environment variable instead of hardcoding it. + val preset = presetIrohServices( + ServicesPresetOptions( + relays = listOf("YOUR_RELAY_URL_US", "YOUR_RELAY_URL_EU"), + apiSecret = "YOUR_API_KEY", + ), + ) + + // Bind the endpoint with the preset, then wait until it's online to + // confirm it has an authorized connection to a relay. + val ep = Endpoint.bind(EndpointOptions(preset = preset)) + ep.online() + ep.shutdown() +} +``` + + + - Custom relay URLs are available on Pro and Enterprise projects. On a free project, pass your API key to the preset without `relays(...)` to authenticate against the public relays and surface your relay traffic on the dashboard. + Custom relay URLs are available on Pro and Enterprise projects. On a free project, use the n0 preset (`presets::N0`, `preset_n0()`) — in Rust you can also pass your API key to `iroh_services::preset()` without `relays(...)` to authenticate against the public relays and surface your relay traffic on the dashboard. + +The access token is minted when you build the preset, and is scoped to the +endpoint's key. Both are handled for you if you let the preset generate the key. +To pin your endpoint's identity instead, pass your saved key to the preset — +in the bindings that's `ServicesPresetOptions.secretKey`, not +`EndpointOptions.secretKey`. Option fields are layered on top of the preset, so +a key set there replaces the one the token is scoped to and the relays will +reject the endpoint. From a60488cc36fc687868ebdacf77d6bb70d27f7f56 Mon Sep 17 00:00:00 2001 From: rae <633012+okdistribute@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:18:11 -0700 Subject: [PATCH 2/5] Update relay-preset-config.mdx --- snippets/relay-preset-config.mdx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/snippets/relay-preset-config.mdx b/snippets/relay-preset-config.mdx index cb327f4..443fedb 100644 --- a/snippets/relay-preset-config.mdx +++ b/snippets/relay-preset-config.mdx @@ -105,13 +105,7 @@ fun main() = runBlocking { - Custom relay URLs are available on Pro and Enterprise projects. On a free project, use the n0 preset (`presets::N0`, `preset_n0()`) — in Rust you can also pass your API key to `iroh_services::preset()` without `relays(...)` to authenticate against the public relays and surface your relay traffic on the dashboard. + Custom relay URLs are available on Pro and Enterprise projects, or if you self-host your own relay. -The access token is minted when you build the preset, and is scoped to the -endpoint's key. Both are handled for you if you let the preset generate the key. -To pin your endpoint's identity instead, pass your saved key to the preset — -in the bindings that's `ServicesPresetOptions.secretKey`, not -`EndpointOptions.secretKey`. Option fields are layered on top of the preset, so -a key set there replaces the one the token is scoped to and the relays will -reject the endpoint. +On a free project, use the n0 preset (`presets::N0`, `preset_n0()`) — in Rust you can also pass your API key to `iroh_services::preset()` without `relays(...)` to authenticate against the public relays and surface your relay traffic on the dashboard. From e403d03d89a8f1466885d6ba8e81aead61216d12 Mon Sep 17 00:00:00 2001 From: Rae McKelvey <633012+okdistribute@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:23:28 -0700 Subject: [PATCH 3/5] docs(add-a-relay): add JavaScript, use endpointSecretKey JavaScript applies presets as functions on an EndpointBuilder rather than passing them to bind(), so the tab uses Endpoint.builder() and a short note explains why. Also renames secretKey to endpointSecretKey to match iroh-ffi#284, and folds the "don't set the key outside the preset" warning into one sentence covering both EndpointOptions and EndpointBuilder. Co-Authored-By: Claude Opus 5 (1M context) --- snippets/relay-preset-config.mdx | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/snippets/relay-preset-config.mdx b/snippets/relay-preset-config.mdx index 443fedb..54abc0a 100644 --- a/snippets/relay-preset-config.mdx +++ b/snippets/relay-preset-config.mdx @@ -9,8 +9,8 @@ In Rust, add the `iroh-services` crate to your project: cargo add iroh-services ``` -The Python, Swift, and Kotlin bindings ship the preset as part of `iroh-ffi`, -with no extra dependency needed. +The Python, Swift, Kotlin, and JavaScript bindings ship the preset as part of +`iroh-ffi`, with no extra dependency needed. @@ -102,8 +102,30 @@ fun main() = runBlocking { } ``` +```javascript JavaScript +import { Endpoint, presetIrohServices } from '@number0/iroh' + +// Apply a preset pointing at your dedicated relays, authenticated with your +// project's API key. In production, load the key from a config file or +// environment variable instead of hardcoding it. +const builder = Endpoint.builder() +presetIrohServices(builder, { + relays: ['YOUR_RELAY_URL_US', 'YOUR_RELAY_URL_EU'], + apiSecret: 'YOUR_API_KEY', +}) + +// Bind the endpoint, then wait until it's online to confirm it has an +// authorized connection to a relay. +const ep = await builder.bind() +await ep.online() +``` + +In JavaScript, presets are functions applied to an `EndpointBuilder`, so use +`Endpoint.builder()` rather than `Endpoint.bind()` — `bind()` always applies the +n0 preset. + Custom relay URLs are available on Pro and Enterprise projects, or if you self-host your own relay. From 240ec312cb6762d3f81244a8cf43ed715a89f5e1 Mon Sep 17 00:00:00 2001 From: Rae McKelvey <633012+okdistribute@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:29:48 -0700 Subject: [PATCH 4/5] docs(add-a-relay): drop the Rust-only free-tier relay clause Passing an API key to iroh_services::preset() without relays is a Rust-only path, and pointing at it from a page about dedicated relays reads as a workaround. The n0 preset is the free-project answer in every language. Co-Authored-By: Claude Opus 5 (1M context) --- snippets/relay-preset-config.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snippets/relay-preset-config.mdx b/snippets/relay-preset-config.mdx index 54abc0a..a787048 100644 --- a/snippets/relay-preset-config.mdx +++ b/snippets/relay-preset-config.mdx @@ -130,4 +130,4 @@ n0 preset. Custom relay URLs are available on Pro and Enterprise projects, or if you self-host your own relay. -On a free project, use the n0 preset (`presets::N0`, `preset_n0()`) — in Rust you can also pass your API key to `iroh_services::preset()` without `relays(...)` to authenticate against the public relays and surface your relay traffic on the dashboard. +On a free project, use the n0 preset (`presets::N0`, `preset_n0()`) instead. From 685731efd5661b34ac2e8701a24ac9e674d0f534 Mon Sep 17 00:00:00 2001 From: Rae McKelvey <633012+okdistribute@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:51:45 -0700 Subject: [PATCH 5/5] docs(add-a-relay): free projects omit relay URLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the bindings match Rust and fall back to the n0 relays, omitting the relay URLs is the free-project path in every language — simpler than pointing at a different preset, and it keeps the API key in play. Co-Authored-By: Claude Opus 5 (1M context) --- snippets/relay-preset-config.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snippets/relay-preset-config.mdx b/snippets/relay-preset-config.mdx index a787048..13d73a9 100644 --- a/snippets/relay-preset-config.mdx +++ b/snippets/relay-preset-config.mdx @@ -130,4 +130,4 @@ n0 preset. Custom relay URLs are available on Pro and Enterprise projects, or if you self-host your own relay. -On a free project, use the n0 preset (`presets::N0`, `preset_n0()`) instead. +On a free project, omit the relay URLs — the preset then authenticates against the n0 public relays.