From 1acbb3cd277e22d7d1b556b46a7f4eacb2a5233d Mon Sep 17 00:00:00 2001 From: Zakariya Mohummed Date: Mon, 20 Jul 2026 21:16:12 +0100 Subject: [PATCH] docs: say "connector token" and "web calling token" throughout Settles on one name per credential across the docs, examples, and the SDK's user-facing copy. - "API key" -> "connector token" in prose. The repo had already started this migration (README/PolyVoice.md snippets were annotated "// connector token", and e2e-validation.sh reads POLY_CONNECTOR_TOKEN), so this finishes it. Uses "connector token" rather than a bare "token" because a voice call takes two tokens and the docs are trying to tell them apart. - "WebRTC token" -> "web calling token", for the credential ONLY. Every reference to WebRTC-the-protocol or the WebRTC dependency (media, binary, xcframework, audio engine, WebRTC-lib) is left alone -- those are factual and renaming them would make correct docs wrong. - A third name for the same credential ("gateway token") is folded into "web calling token". - Placeholders: YOUR_API_KEY -> YOUR_CONNECTOR_TOKEN, YOUR_WEBRTC_TOKEN -> YOUR_WEB_CALLING_TOKEN, in both the READMEs and the example sources so they can't drift. scripts/e2e-validation.sh substitutes YOUR_API_KEY at test time and is updated to match -- without that, e2e would have built the examples with an unsubstituted placeholder. - User-facing SDK copy that contradicted the new docs: PolyError's "Your API key was rejected", SessionState's "Invalid API key", and the initialize() fatalError hint. No public API symbols were renamed. Configuration.apiKey and VoiceOptions.webrtcToken are untouched, so this is not a breaking change and every snippet still compiles -- 72b54a9 settled that surface for 0.9.0 and this does not reopen it. The tradeoff is that prose now says "connector token" next to a symbol still called apiKey; renaming the symbols would be a separate, breaking PR. swift build clean; 283 tests pass. --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/copilot-instructions.md | 4 +-- CHANGELOG.md | 2 +- CONTRIBUTING.md | 4 +-- Examples/README.md | 2 +- Examples/SwiftUI/Chat/01-Hello/HelloApp.swift | 2 +- Examples/SwiftUI/Chat/01-Hello/README.md | 10 +++--- .../Chat/02-Standard/App/StandardApp.swift | 4 +-- Examples/SwiftUI/Chat/02-Standard/README.md | 2 +- .../03-RichContent/App/RichContentApp.swift | 4 +-- .../SwiftUI/Chat/03-RichContent/README.md | 2 +- .../04-Resilience/App/ResilienceApp.swift | 4 +-- Examples/SwiftUI/Chat/04-Resilience/README.md | 2 +- .../Chat/05-Handoff/App/HandoffApp.swift | 4 +-- Examples/SwiftUI/Chat/05-Handoff/README.md | 2 +- .../App/FullReferenceApp.swift | 2 +- .../SwiftUI/Chat/06-FullReference/README.md | 4 +-- .../07-Playground/App/PlaygroundApp.swift | 2 +- Examples/SwiftUI/Chat/07-Playground/README.md | 4 +-- .../SwiftUI/Voice/01-Hello/ContentView.swift | 4 +-- Examples/SwiftUI/Voice/01-Hello/README.md | 8 ++--- .../Voice/02-CallKit/ContentView.swift | 4 +-- Examples/SwiftUI/Voice/02-CallKit/README.md | 2 +- .../UIKit/Chat/01-Hello/AppDelegate.swift | 4 +-- Examples/UIKit/Chat/01-Hello/README.md | 10 +++--- .../Chat/02-Standard/App/AppDelegate.swift | 4 +-- Examples/UIKit/Chat/02-Standard/README.md | 2 +- .../Chat/03-RichContent/App/AppDelegate.swift | 4 +-- Examples/UIKit/Chat/03-RichContent/README.md | 2 +- .../Chat/04-Resilience/App/AppDelegate.swift | 4 +-- Examples/UIKit/Chat/04-Resilience/README.md | 2 +- .../Chat/05-Handoff/App/AppDelegate.swift | 4 +-- Examples/UIKit/Chat/05-Handoff/README.md | 2 +- .../06-FullReference/App/AppDelegate.swift | 2 +- .../UIKit/Chat/06-FullReference/README.md | 4 +-- .../Chat/07-Playground/App/AppDelegate.swift | 2 +- Examples/UIKit/Chat/07-Playground/README.md | 4 +-- .../Voice/01-Hello/CallViewController.swift | 4 +-- Examples/UIKit/Voice/01-Hello/README.md | 8 ++--- .../Voice/02-CallKit/CallViewController.swift | 4 +-- Examples/UIKit/Voice/02-CallKit/README.md | 2 +- README.md | 32 +++++++++---------- Sources/PolyMessaging/Configuration.swift | 2 +- .../Internal/Voice/IceServersProvider.swift | 2 +- Sources/PolyMessaging/PolyMessaging.swift | 4 +-- .../PolyMessaging/Public/ChatSession.swift | 4 +-- .../PolyMessaging/Public/DevSettings.swift | 8 ++--- Sources/PolyMessaging/Public/PolyError.swift | 2 +- .../PolyMessaging/Public/SessionState.swift | 2 +- .../PolyMessaging/Public/Voice/PolyCall.swift | 4 +-- Sources/PolyVoice/PolyVoice.swift | 2 +- Sources/PolyVoice/VoiceOptions.swift | 8 ++--- .../PolyErrorDescriptionTests.swift | 2 +- .../Voice/LiveSignalingProbeTests.swift | 2 +- docs/PolyVoice.md | 12 +++---- scripts/e2e-validation.sh | 6 ++-- 56 files changed, 120 insertions(+), 120 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0c8bece..66413db 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -27,7 +27,7 @@ Closes # - [ ] Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) - [ ] No third-party dependencies added to `Package.swift` -- [ ] No API keys, session IDs, or credentials in the diff +- [ ] No connector tokens, session IDs, or credentials in the diff - [ ] `README.md` updated if public API or behavior changed - [ ] SwiftUI and UIKit example ladders mirrored (if SDK behavior changed) - [ ] `Version.swift` not touched (it is bumped only when cutting a release) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 1962e31..a5fb330 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -76,7 +76,7 @@ The agent joins and greets automatically. Full walkthrough: README **Step 1**. rendering for you. - **Suggestion pills** render under the last agent message and clear when the user sends (see the example `ChatViewController` / `MessageBubbleView`). -- **Never log the API key.** +- **Never log the connector token.** ## Verifying changes @@ -90,4 +90,4 @@ The agent joins and greets automatically. Full walkthrough: README **Step 1**. - **Don't add third-party dependencies** — this package is intentionally dependency-free. - When integrating into an app, **consume the public API**; don't edit `Sources/PolyMessaging/` to make integration "easier." -- Keep credentials out of source — set the API key via `initialize(...)`. +- Keep credentials out of source — set the connector token via `initialize(...)`. diff --git a/CHANGELOG.md b/CHANGELOG.md index c5126a3..06e67f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ signaling pipeline. ### Added - **`PolyVoice.call(config:options:)`** → a `PolyCall` backed by a real WebRTC audio engine (audio-only Opus, offer / answer / trickle ICE, mute). `VoiceOptions.webrtcToken` - is required — a distinct token from the API key. + is required — a distinct token from the connector token. - **CallKit support** (`PolyVoice`): opt in with `VoiceOptions(callKit: true)` to run a call as a system call. The SDK defers audio-session activation and the WebRTC audio unit to CallKit; three new statics forward the `CXProviderDelegate` moments — diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 19a19ef..78c604b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,7 +56,7 @@ If you change the SDK, mirror the change across the SwiftUI and UIKit example la - Public types and methods need a doc comment (`///`) describing **why** to use them, not just what they do. - Don't introduce comments that simply restate the code. Only comment non-obvious invariants. - The SDK is `@MainActor` where it touches `ChatSession` state — preserve those annotations. -- Never log API keys or session identifiers. +- Never log connector tokens or session identifiers. ## Commit conventions @@ -101,5 +101,5 @@ For UI/example changes, open the relevant `Examples//` projec - **No third-party dependencies.** This package is intentionally dependency-free. - **Don't edit `Sources/PolyMessaging/` to make integration "easier"** — the public API is the contract; integration changes belong in the consuming app. -- **Keep credentials out of source.** API keys are set via `PolyMessaging.initialize(...)` at runtime, never committed. +- **Keep credentials out of source.** Connector tokens are set via `PolyMessaging.initialize(...)` at runtime, never committed. diff --git a/Examples/README.md b/Examples/README.md index 1d9b0e3..a7eded7 100644 --- a/Examples/README.md +++ b/Examples/README.md @@ -32,4 +32,4 @@ open Examples/SwiftUI/Chat/01-Hello/HelloSwiftUI.xcodeproj # or any other # Cmd+R on an iPhone simulator ``` -If you change `project.yml`, regenerate with `xcodegen` from inside that folder. Set your API key where the example calls `PolyMessaging.initialize(...)`. +If you change `project.yml`, regenerate with `xcodegen` from inside that folder. Set your connector token where the example calls `PolyMessaging.initialize(...)`. diff --git a/Examples/SwiftUI/Chat/01-Hello/HelloApp.swift b/Examples/SwiftUI/Chat/01-Hello/HelloApp.swift index 7a40438..7bff79e 100644 --- a/Examples/SwiftUI/Chat/01-Hello/HelloApp.swift +++ b/Examples/SwiftUI/Chat/01-Hello/HelloApp.swift @@ -17,7 +17,7 @@ struct HelloApp: App { // works anywhere in the app with no arguments. // Replace with your connector token from Agent Studio before shipping. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) if CommandLine.arguments.contains("-uiTestFreshStart") { PolyMessaging.clearResumableSession() } } diff --git a/Examples/SwiftUI/Chat/01-Hello/README.md b/Examples/SwiftUI/Chat/01-Hello/README.md index 260eeb8..029572d 100644 --- a/Examples/SwiftUI/Chat/01-Hello/README.md +++ b/Examples/SwiftUI/Chat/01-Hello/README.md @@ -9,7 +9,7 @@ open HelloSwiftUI.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `HelloApp.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `HelloApp.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates @@ -32,7 +32,7 @@ Configure the SDK once at launch: ```swift PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" // from Agent Studio → Connector Settings + apiKey: "YOUR_CONNECTOR_TOKEN" // from Agent Studio → Connector Settings // environment defaults to .us — add .uk / .euw / .cluster("dev") / .custom(...) only if needed )) ``` @@ -44,7 +44,7 @@ In an `@main` App: struct HelloApp: App { init() { PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) } var body: some Scene { WindowGroup { ContentView() } } @@ -53,7 +53,7 @@ struct HelloApp: App { After this, `PolyMessaging.chat()` works from any view. -**Under the hood:** `initialize` just stashes your API key and environment process-wide — no network happens yet. The work starts when you call `chat()`. +**Under the hood:** `initialize` just stashes your connector token and environment process-wide — no network happens yet. The work starts when you call `chat()`. *See [Quick start](../../../../README.md#quick-start).* @@ -178,7 +178,7 @@ Sending stays available even while offline or reconnecting — gate only on `has *See [Integration guide › The core pattern](../../../../README.md#the-core-pattern-render-messages-yourself).* -### Catch a bad API key — `ContentView.swift` +### Catch a bad connector token — `ContentView.swift` Detect a terminal failure + offer retry: diff --git a/Examples/SwiftUI/Chat/02-Standard/App/StandardApp.swift b/Examples/SwiftUI/Chat/02-Standard/App/StandardApp.swift index aa304ec..f0a3cc4 100644 --- a/Examples/SwiftUI/Chat/02-Standard/App/StandardApp.swift +++ b/Examples/SwiftUI/Chat/02-Standard/App/StandardApp.swift @@ -15,9 +15,9 @@ struct StandardApp: App { init() { // Initialize once at app launch. After this, PolyMessaging.chat() // works anywhere in the app with no arguments. - // Replace YOUR_API_KEY with your connector token from Agent Studio. + // Replace YOUR_CONNECTOR_TOKEN with your connector token from Agent Studio. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) if CommandLine.arguments.contains("-uiTestFreshStart") { PolyMessaging.clearResumableSession() } } diff --git a/Examples/SwiftUI/Chat/02-Standard/README.md b/Examples/SwiftUI/Chat/02-Standard/README.md index a9dd41b..b550a91 100644 --- a/Examples/SwiftUI/Chat/02-Standard/README.md +++ b/Examples/SwiftUI/Chat/02-Standard/README.md @@ -11,7 +11,7 @@ open StandardSwiftUI.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `App/StandardApp.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `App/StandardApp.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates diff --git a/Examples/SwiftUI/Chat/03-RichContent/App/RichContentApp.swift b/Examples/SwiftUI/Chat/03-RichContent/App/RichContentApp.swift index 0852a92..0c4d472 100644 --- a/Examples/SwiftUI/Chat/03-RichContent/App/RichContentApp.swift +++ b/Examples/SwiftUI/Chat/03-RichContent/App/RichContentApp.swift @@ -15,9 +15,9 @@ struct RichContentApp: App { init() { // Initialize once at app launch. After this, PolyMessaging.chat() // works anywhere in the app with no arguments. - // Replace YOUR_API_KEY with your connector token from Agent Studio. + // Replace YOUR_CONNECTOR_TOKEN with your connector token from Agent Studio. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) if CommandLine.arguments.contains("-uiTestFreshStart") { PolyMessaging.clearResumableSession() } } diff --git a/Examples/SwiftUI/Chat/03-RichContent/README.md b/Examples/SwiftUI/Chat/03-RichContent/README.md index 4989a6a..ebb78aa 100644 --- a/Examples/SwiftUI/Chat/03-RichContent/README.md +++ b/Examples/SwiftUI/Chat/03-RichContent/README.md @@ -11,7 +11,7 @@ open RichContentSwiftUI.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `App/RichContentApp.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `App/RichContentApp.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates diff --git a/Examples/SwiftUI/Chat/04-Resilience/App/ResilienceApp.swift b/Examples/SwiftUI/Chat/04-Resilience/App/ResilienceApp.swift index ec901a7..0079a23 100644 --- a/Examples/SwiftUI/Chat/04-Resilience/App/ResilienceApp.swift +++ b/Examples/SwiftUI/Chat/04-Resilience/App/ResilienceApp.swift @@ -15,9 +15,9 @@ struct ResilienceApp: App { init() { // Initialize once at app launch. After this, PolyMessaging.chat() // works anywhere in the app with no arguments. - // Replace YOUR_API_KEY with your connector token from Agent Studio. + // Replace YOUR_CONNECTOR_TOKEN with your connector token from Agent Studio. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) if CommandLine.arguments.contains("-uiTestFreshStart") { PolyMessaging.clearResumableSession() } } diff --git a/Examples/SwiftUI/Chat/04-Resilience/README.md b/Examples/SwiftUI/Chat/04-Resilience/README.md index ff7266c..15169cb 100644 --- a/Examples/SwiftUI/Chat/04-Resilience/README.md +++ b/Examples/SwiftUI/Chat/04-Resilience/README.md @@ -9,7 +9,7 @@ open ResilienceSwiftUI.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `ResilienceApp.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `ResilienceApp.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates diff --git a/Examples/SwiftUI/Chat/05-Handoff/App/HandoffApp.swift b/Examples/SwiftUI/Chat/05-Handoff/App/HandoffApp.swift index 783a114..88ac611 100644 --- a/Examples/SwiftUI/Chat/05-Handoff/App/HandoffApp.swift +++ b/Examples/SwiftUI/Chat/05-Handoff/App/HandoffApp.swift @@ -15,9 +15,9 @@ struct HandoffApp: App { init() { // Initialize once at app launch. After this, PolyMessaging.chat() // works anywhere in the app with no arguments. - // Replace YOUR_API_KEY with your connector token from Agent Studio. + // Replace YOUR_CONNECTOR_TOKEN with your connector token from Agent Studio. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) if CommandLine.arguments.contains("-uiTestFreshStart") { PolyMessaging.clearResumableSession() } } diff --git a/Examples/SwiftUI/Chat/05-Handoff/README.md b/Examples/SwiftUI/Chat/05-Handoff/README.md index f67a9ff..0f8b3ff 100644 --- a/Examples/SwiftUI/Chat/05-Handoff/README.md +++ b/Examples/SwiftUI/Chat/05-Handoff/README.md @@ -9,7 +9,7 @@ open HandoffSwiftUI.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `HandoffApp.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `HandoffApp.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates diff --git a/Examples/SwiftUI/Chat/06-FullReference/App/FullReferenceApp.swift b/Examples/SwiftUI/Chat/06-FullReference/App/FullReferenceApp.swift index 41c69cf..cebe72b 100644 --- a/Examples/SwiftUI/Chat/06-FullReference/App/FullReferenceApp.swift +++ b/Examples/SwiftUI/Chat/06-FullReference/App/FullReferenceApp.swift @@ -10,7 +10,7 @@ struct FullReferenceApp: App { // live. ContentView's resume / start-new flows use the no-arg facade // (chat(), start(), hasResumableSession()), which reuse this config. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY", + apiKey: "YOUR_CONNECTOR_TOKEN", environment: .us, streamingEnabled: true, logLevel: .error diff --git a/Examples/SwiftUI/Chat/06-FullReference/README.md b/Examples/SwiftUI/Chat/06-FullReference/README.md index 9f70286..8af848e 100644 --- a/Examples/SwiftUI/Chat/06-FullReference/README.md +++ b/Examples/SwiftUI/Chat/06-FullReference/README.md @@ -9,7 +9,7 @@ open FullReferenceSwiftUI.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `FullReferenceApp.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `FullReferenceApp.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates @@ -98,7 +98,7 @@ struct ContentView: View { } ``` -**Under the hood:** `initialize` stashes the API key and environment process-wide — no network happens yet. The no-arg facade calls (`chat()`, `start()`, `hasResumableSession()`) reuse that config from any view. `chat()` resumes the persisted session when it's still valid (within the session timeout) and otherwise creates a fresh one; `start()` always discards. `hasResumableSession()` is a pure on-disk probe with no side effects, so it's safe to call on every render of the connect screen. +**Under the hood:** `initialize` stashes the connector token and environment process-wide — no network happens yet. The no-arg facade calls (`chat()`, `start()`, `hasResumableSession()`) reuse that config from any view. `chat()` resumes the persisted session when it's still valid (within the session timeout) and otherwise creates a fresh one; `start()` always discards. `hasResumableSession()` is a pure on-disk probe with no side effects, so it's safe to call on every render of the connect screen. *See [Integration guide › Quick start](../../../../README.md#quick-start) and [Integration guide › Session lifecycle](../../../../README.md#session-lifecycle).* diff --git a/Examples/SwiftUI/Chat/07-Playground/App/PlaygroundApp.swift b/Examples/SwiftUI/Chat/07-Playground/App/PlaygroundApp.swift index 020ac61..7f0bdcc 100644 --- a/Examples/SwiftUI/Chat/07-Playground/App/PlaygroundApp.swift +++ b/Examples/SwiftUI/Chat/07-Playground/App/PlaygroundApp.swift @@ -10,7 +10,7 @@ struct PlaygroundApp: App { // Configuration from DevSettings on every connect, so this just primes a // sane default. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY", + apiKey: "YOUR_CONNECTOR_TOKEN", environment: .us )) if CommandLine.arguments.contains("-uiTestFreshStart") { PolyMessaging.clearResumableSession() } diff --git a/Examples/SwiftUI/Chat/07-Playground/README.md b/Examples/SwiftUI/Chat/07-Playground/README.md index e9285fa..8637518 100644 --- a/Examples/SwiftUI/Chat/07-Playground/README.md +++ b/Examples/SwiftUI/Chat/07-Playground/README.md @@ -11,7 +11,7 @@ open PlaygroundSwiftUI.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `PlaygroundApp.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `PlaygroundApp.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates @@ -29,7 +29,7 @@ Each subsection leads with **the SDK call(s)** (the actual API), then shows **ho ### Runtime configuration via `DevSettings` — `Views/SettingsSheet.swift` -`DevSettings` is a **public SDK type** (`Sources/PolyMessaging/Public/DevSettings.swift`) — an `@MainActor open class DevSettings: ObservableObject` backed by `UserDefaults`. Construct it with no arguments after `initialize(_:)`; it reads the API key from `PolyMessaging.currentConfig` and seeds its environment from there, so it bakes in no credentials. Edit the published knobs live; `buildConfiguration()` folds them into a `Configuration` the SDK consumes on the **next** session. +`DevSettings` is a **public SDK type** (`Sources/PolyMessaging/Public/DevSettings.swift`) — an `@MainActor open class DevSettings: ObservableObject` backed by `UserDefaults`. Construct it with no arguments after `initialize(_:)`; it reads the connector token from `PolyMessaging.currentConfig` and seeds its environment from there, so it bakes in no credentials. Edit the published knobs live; `buildConfiguration()` folds them into a `Configuration` the SDK consumes on the **next** session. The SDK calls: diff --git a/Examples/SwiftUI/Voice/01-Hello/ContentView.swift b/Examples/SwiftUI/Voice/01-Hello/ContentView.swift index 8c9588c..c80e816 100644 --- a/Examples/SwiftUI/Voice/01-Hello/ContentView.swift +++ b/Examples/SwiftUI/Voice/01-Hello/ContentView.swift @@ -33,11 +33,11 @@ struct ContentView: View { private func startCall() { // Fill in your connector from Agent Studio › Connector Settings. - let config = Configuration(apiKey: "YOUR_API_KEY") + let config = Configuration(apiKey: "YOUR_CONNECTOR_TOKEN") do { let newCall = try PolyVoice.call( config: config, - options: VoiceOptions(webrtcToken: "YOUR_WEBRTC_TOKEN") + options: VoiceOptions(webrtcToken: "YOUR_WEB_CALLING_TOKEN") ) setupFailure = nil call = newCall diff --git a/Examples/SwiftUI/Voice/01-Hello/README.md b/Examples/SwiftUI/Voice/01-Hello/README.md index 913b195..212f921 100644 --- a/Examples/SwiftUI/Voice/01-Hello/README.md +++ b/Examples/SwiftUI/Voice/01-Hello/README.md @@ -9,7 +9,7 @@ open VoiceSwiftUI.xcodeproj # from this folder ``` 1. Set your team under **Signing & Capabilities** (a device build needs one). -2. In `ContentView.swift`, fill in both credentials from **Agent Studio › Connector Settings**: `apiKey` (your connector token, currently `"YOUR_API_KEY"`) and `webrtcToken` (the gateway token — a **distinct** value, currently `"YOUR_WEBRTC_TOKEN"`). +2. In `ContentView.swift`, fill in both credentials from **Agent Studio › Connector Settings**: `apiKey` (your connector token, currently `"YOUR_CONNECTOR_TOKEN"`) and `webrtcToken` (the web calling token — a **distinct** value, currently `"YOUR_WEB_CALLING_TOKEN"`). 3. Run on a **physical iPhone** — the simulator can't carry WebRTC media. Allow the microphone, tap **Start call**, and talk. Mic permission (`NSMicrophoneUsageDescription`) and the `audio` background mode are already configured via `project.yml`, so the call keeps running when you background the app. @@ -32,8 +32,8 @@ Each subsection leads with **the SDK call** (the actual API), then shows **how i ```swift let call = try PolyVoice.call( - config: Configuration(apiKey: "YOUR_API_KEY"), // connector token - options: VoiceOptions(webrtcToken: "YOUR_WEBRTC_TOKEN") // gateway token — a distinct value + config: Configuration(apiKey: "YOUR_CONNECTOR_TOKEN"), // connector token + options: VoiceOptions(webrtcToken: "YOUR_WEB_CALLING_TOKEN") // web calling token — a distinct value ) // throws PolyError.invalidConfiguration on a blank token, // or a .custom environment without VoiceOptions.signalingHost ``` @@ -50,7 +50,7 @@ do { call = newCall ``` -**Under the hood:** building the call does no network work — it validates the tokens and wires the WebRTC engine to the same REST/session/signaling pipeline the SDK's tests exercise. Everything starts at `start()`. The two tokens do different jobs: the API key authenticates the call session, the WebRTC token authenticates the signaling offer and the ICE-servers fetch. +**Under the hood:** building the call does no network work — it validates the tokens and wires the WebRTC engine to the same REST/session/signaling pipeline the SDK's tests exercise. Everything starts at `start()`. The two tokens do different jobs: the connector token authenticates the call session, the web calling token authenticates the signaling offer and the ICE-servers fetch. *See [voice guide › Credentials](../../../../docs/PolyVoice.md#credentials).* diff --git a/Examples/SwiftUI/Voice/02-CallKit/ContentView.swift b/Examples/SwiftUI/Voice/02-CallKit/ContentView.swift index 009de8a..2549d92 100644 --- a/Examples/SwiftUI/Voice/02-CallKit/ContentView.swift +++ b/Examples/SwiftUI/Voice/02-CallKit/ContentView.swift @@ -72,13 +72,13 @@ struct ContentView: View { private func startCall() { // Fill in your connector from Agent Studio › Connector Settings. - let config = Configuration(apiKey: "YOUR_API_KEY") + let config = Configuration(apiKey: "YOUR_CONNECTOR_TOKEN") let newCall: PolyCall do { newCall = try PolyVoice.call( config: config, options: VoiceOptions( - webrtcToken: "YOUR_WEBRTC_TOKEN", + webrtcToken: "YOUR_WEB_CALLING_TOKEN", callKit: callKitAvailable // audio start/stop deferred to CallKit ) ) diff --git a/Examples/SwiftUI/Voice/02-CallKit/README.md b/Examples/SwiftUI/Voice/02-CallKit/README.md index b79eaff..65d9d19 100644 --- a/Examples/SwiftUI/Voice/02-CallKit/README.md +++ b/Examples/SwiftUI/Voice/02-CallKit/README.md @@ -5,7 +5,7 @@ ## Run it 1. Open `VoiceCallKitSwiftUI.xcodeproj` (or `xcodegen generate` first if you changed `project.yml`). -2. Drop your **connector token** and **WebRTC token** into the `PolyVoice.call(...)` block in `ContentView.swift` (both from Agent Studio › Connector Settings — see the [voice guide › Credentials](../../../../docs/PolyVoice.md#credentials)). +2. Drop your **connector token** and **web calling token** into the `PolyVoice.call(...)` block in `ContentView.swift` (both from Agent Studio › Connector Settings — see the [voice guide › Credentials](../../../../docs/PolyVoice.md#credentials)). 3. Everything the app needs is preconfigured in `project.yml`: the mic permission (`NSMicrophoneUsageDescription` — allow it on first call) and `UIBackgroundModes: [audio, voip]`. Note that **`voip` is required** — without it CallKit refuses every transaction (`requesttransaction Code=1`) and the Start button appears dead. 4. Run on a **physical device**. WebRTC media can't cross the simulator, and CallKit itself is broken there (iOS 17+ simulators auto-end the call; `didActivate` never fires) — on the simulator this example deliberately falls back to a plain `01-Hello`-style call. diff --git a/Examples/UIKit/Chat/01-Hello/AppDelegate.swift b/Examples/UIKit/Chat/01-Hello/AppDelegate.swift index 96b7730..aa39ae6 100644 --- a/Examples/UIKit/Chat/01-Hello/AppDelegate.swift +++ b/Examples/UIKit/Chat/01-Hello/AppDelegate.swift @@ -19,9 +19,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ) -> Bool { // Initialize once at app launch. After this, PolyMessaging.chat() // works anywhere in the app with no arguments. - // Replace YOUR_API_KEY with your connector token from Agent Studio. + // Replace YOUR_CONNECTOR_TOKEN with your connector token from Agent Studio. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) // UITests pass -uiTestFreshStart to force a brand-new greeting + // suggestions instead of resuming a prior conversation. diff --git a/Examples/UIKit/Chat/01-Hello/README.md b/Examples/UIKit/Chat/01-Hello/README.md index be47047..f298d42 100644 --- a/Examples/UIKit/Chat/01-Hello/README.md +++ b/Examples/UIKit/Chat/01-Hello/README.md @@ -12,7 +12,7 @@ open HelloUIKit.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `AppDelegate.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `AppDelegate.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates @@ -35,7 +35,7 @@ Configure the SDK once at launch: ```swift PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" // from Agent Studio → Connector Settings + apiKey: "YOUR_CONNECTOR_TOKEN" // from Agent Studio → Connector Settings // environment defaults to .us — add .uk / .euw / .cluster("dev") / .custom(...) only if needed )) ``` @@ -50,7 +50,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) return true } @@ -59,7 +59,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { After this, `PolyMessaging.chat()` works from any view controller with no arguments. -**Under the hood:** `initialize` just stashes your API key and environment process-wide — no network happens yet. The work starts when you call `chat()`. +**Under the hood:** `initialize` just stashes your connector token and environment process-wide — no network happens yet. The work starts when you call `chat()`. *See [Quick start](../../../../README.md#quick-start).* @@ -184,7 +184,7 @@ In a view controller: *See [Integration guide › The core pattern](../../../../README.md#the-core-pattern-render-messages-yourself).* -### Catch a bad API key — `ChatViewController.swift` +### Catch a bad connector token — `ChatViewController.swift` Detect a terminal failure + offer retry: diff --git a/Examples/UIKit/Chat/02-Standard/App/AppDelegate.swift b/Examples/UIKit/Chat/02-Standard/App/AppDelegate.swift index f92f25f..5003107 100644 --- a/Examples/UIKit/Chat/02-Standard/App/AppDelegate.swift +++ b/Examples/UIKit/Chat/02-Standard/App/AppDelegate.swift @@ -19,9 +19,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ) -> Bool { // Initialize once at app launch. After this, PolyMessaging.chat() // works anywhere in the app with no arguments. - // Replace YOUR_API_KEY with your connector token from Agent Studio. + // Replace YOUR_CONNECTOR_TOKEN with your connector token from Agent Studio. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) // UITests pass -uiTestFreshStart to force a brand-new greeting + // suggestions instead of resuming a prior conversation. diff --git a/Examples/UIKit/Chat/02-Standard/README.md b/Examples/UIKit/Chat/02-Standard/README.md index 5ae528b..a1e1d84 100644 --- a/Examples/UIKit/Chat/02-Standard/README.md +++ b/Examples/UIKit/Chat/02-Standard/README.md @@ -14,7 +14,7 @@ open StandardUIKit.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `App/AppDelegate.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `App/AppDelegate.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates diff --git a/Examples/UIKit/Chat/03-RichContent/App/AppDelegate.swift b/Examples/UIKit/Chat/03-RichContent/App/AppDelegate.swift index 018b8d0..0fa71ee 100644 --- a/Examples/UIKit/Chat/03-RichContent/App/AppDelegate.swift +++ b/Examples/UIKit/Chat/03-RichContent/App/AppDelegate.swift @@ -19,9 +19,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ) -> Bool { // Initialize once at app launch. After this, PolyMessaging.chat() // works anywhere in the app with no arguments. - // Replace YOUR_API_KEY with your connector token from Agent Studio. + // Replace YOUR_CONNECTOR_TOKEN with your connector token from Agent Studio. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) // UITests pass -uiTestFreshStart to force a brand-new greeting + // suggestions instead of resuming a prior conversation. diff --git a/Examples/UIKit/Chat/03-RichContent/README.md b/Examples/UIKit/Chat/03-RichContent/README.md index 46389ba..beaf52f 100644 --- a/Examples/UIKit/Chat/03-RichContent/README.md +++ b/Examples/UIKit/Chat/03-RichContent/README.md @@ -11,7 +11,7 @@ open RichContentUIKit.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `App/AppDelegate.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `App/AppDelegate.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates diff --git a/Examples/UIKit/Chat/04-Resilience/App/AppDelegate.swift b/Examples/UIKit/Chat/04-Resilience/App/AppDelegate.swift index 5dbd92a..b8d9077 100644 --- a/Examples/UIKit/Chat/04-Resilience/App/AppDelegate.swift +++ b/Examples/UIKit/Chat/04-Resilience/App/AppDelegate.swift @@ -19,9 +19,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ) -> Bool { // Initialize once at app launch. After this, PolyMessaging.chat() // works anywhere in the app with no arguments. - // Replace YOUR_API_KEY with your connector token from Agent Studio. + // Replace YOUR_CONNECTOR_TOKEN with your connector token from Agent Studio. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) // UITests pass -uiTestFreshStart to force a brand-new greeting + // suggestions instead of resuming a prior conversation. diff --git a/Examples/UIKit/Chat/04-Resilience/README.md b/Examples/UIKit/Chat/04-Resilience/README.md index f92a801..2c63ee9 100644 --- a/Examples/UIKit/Chat/04-Resilience/README.md +++ b/Examples/UIKit/Chat/04-Resilience/README.md @@ -12,7 +12,7 @@ open ResilienceUIKit.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `AppDelegate.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `AppDelegate.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates diff --git a/Examples/UIKit/Chat/05-Handoff/App/AppDelegate.swift b/Examples/UIKit/Chat/05-Handoff/App/AppDelegate.swift index dcc5ce4..b6f93d2 100644 --- a/Examples/UIKit/Chat/05-Handoff/App/AppDelegate.swift +++ b/Examples/UIKit/Chat/05-Handoff/App/AppDelegate.swift @@ -19,9 +19,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ) -> Bool { // Initialize once at app launch. After this, PolyMessaging.chat() // works anywhere in the app with no arguments. - // Replace YOUR_API_KEY with your connector token from Agent Studio. + // Replace YOUR_CONNECTOR_TOKEN with your connector token from Agent Studio. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) // UITests pass -uiTestFreshStart to force a brand-new greeting + // suggestions instead of resuming a prior conversation. diff --git a/Examples/UIKit/Chat/05-Handoff/README.md b/Examples/UIKit/Chat/05-Handoff/README.md index f6946f0..697b6bd 100644 --- a/Examples/UIKit/Chat/05-Handoff/README.md +++ b/Examples/UIKit/Chat/05-Handoff/README.md @@ -12,7 +12,7 @@ open HandoffUIKit.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `AppDelegate.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `AppDelegate.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates diff --git a/Examples/UIKit/Chat/06-FullReference/App/AppDelegate.swift b/Examples/UIKit/Chat/06-FullReference/App/AppDelegate.swift index 8728c6a..9a7581f 100644 --- a/Examples/UIKit/Chat/06-FullReference/App/AppDelegate.swift +++ b/Examples/UIKit/Chat/06-FullReference/App/AppDelegate.swift @@ -21,7 +21,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // live. The connect screen and resume / start-new flows use the no-arg // facade (chat(), start(), hasResumableSession()), which reuse this config. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY", + apiKey: "YOUR_CONNECTOR_TOKEN", environment: .us, streamingEnabled: true, logLevel: .error diff --git a/Examples/UIKit/Chat/06-FullReference/README.md b/Examples/UIKit/Chat/06-FullReference/README.md index 1f18855..0342ea9 100644 --- a/Examples/UIKit/Chat/06-FullReference/README.md +++ b/Examples/UIKit/Chat/06-FullReference/README.md @@ -12,7 +12,7 @@ open FullReferenceUIKit.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `AppDelegate.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `AppDelegate.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates @@ -92,7 +92,7 @@ final class RootViewController: UIViewController { } ``` -**Under the hood:** `initialize` stashes the API key and environment process-wide — no network happens yet. The no-arg facade calls (`chat()`, `start()`, `hasResumableSession()`) reuse that config from any view controller. `chat()` resumes the persisted session when it's still valid; `start()` always discards. `hasResumableSession()` is a pure on-disk probe with no side effects. +**Under the hood:** `initialize` stashes the connector token and environment process-wide — no network happens yet. The no-arg facade calls (`chat()`, `start()`, `hasResumableSession()`) reuse that config from any view controller. `chat()` resumes the persisted session when it's still valid; `start()` always discards. `hasResumableSession()` is a pure on-disk probe with no side effects. *See [Integration guide › Quick start](../../../../README.md#quick-start) and [Integration guide › Session lifecycle](../../../../README.md#session-lifecycle).* diff --git a/Examples/UIKit/Chat/07-Playground/App/AppDelegate.swift b/Examples/UIKit/Chat/07-Playground/App/AppDelegate.swift index 45b0e3b..acc5f37 100644 --- a/Examples/UIKit/Chat/07-Playground/App/AppDelegate.swift +++ b/Examples/UIKit/Chat/07-Playground/App/AppDelegate.swift @@ -22,7 +22,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY", + apiKey: "YOUR_CONNECTOR_TOKEN", environment: .us, streamingEnabled: true, logLevel: .debug diff --git a/Examples/UIKit/Chat/07-Playground/README.md b/Examples/UIKit/Chat/07-Playground/README.md index 9482e84..c5077db 100644 --- a/Examples/UIKit/Chat/07-Playground/README.md +++ b/Examples/UIKit/Chat/07-Playground/README.md @@ -14,7 +14,7 @@ open PlaygroundUIKit.xcodeproj # from this folder # Cmd+R on an iPhone simulator ``` -Set your API key in `AppDelegate.swift` (currently `"YOUR_API_KEY"`). +Set your connector token in `AppDelegate.swift` (currently `"YOUR_CONNECTOR_TOKEN"`). ## What this example demonstrates @@ -32,7 +32,7 @@ Each subsection leads with **the SDK call(s)** (the actual API), then shows **ho ### Runtime configuration via `DevSettings` — `Views/SettingsViewController.swift` -`DevSettings` is a **public SDK type** (`Sources/PolyMessaging/Public/DevSettings.swift`) — an `@MainActor open class DevSettings: ObservableObject` backed by `UserDefaults`. Construct it with no arguments after `initialize(_:)`; it reads the API key from `PolyMessaging.currentConfig` and seeds its environment from there, so it bakes in no credentials. Edit the published knobs live; `buildConfiguration()` folds them into a `Configuration` the SDK consumes on the **next** session. +`DevSettings` is a **public SDK type** (`Sources/PolyMessaging/Public/DevSettings.swift`) — an `@MainActor open class DevSettings: ObservableObject` backed by `UserDefaults`. Construct it with no arguments after `initialize(_:)`; it reads the connector token from `PolyMessaging.currentConfig` and seeds its environment from there, so it bakes in no credentials. Edit the published knobs live; `buildConfiguration()` folds them into a `Configuration` the SDK consumes on the **next** session. The SDK calls: diff --git a/Examples/UIKit/Voice/01-Hello/CallViewController.swift b/Examples/UIKit/Voice/01-Hello/CallViewController.swift index 1fc7b94..1ab3cdb 100644 --- a/Examples/UIKit/Voice/01-Hello/CallViewController.swift +++ b/Examples/UIKit/Voice/01-Hello/CallViewController.swift @@ -74,12 +74,12 @@ final class CallViewController: UIViewController { private func startCall() { // Fill in your connector from Agent Studio › Connector Settings. - let config = Configuration(apiKey: "YOUR_API_KEY") + let config = Configuration(apiKey: "YOUR_CONNECTOR_TOKEN") let newCall: PolyCall do { newCall = try PolyVoice.call( config: config, - options: VoiceOptions(webrtcToken: "YOUR_WEBRTC_TOKEN") + options: VoiceOptions(webrtcToken: "YOUR_WEB_CALLING_TOKEN") ) } catch { state = .failed(error as? PolyError ?? .voice(.signalingFailed("\(error)"))) diff --git a/Examples/UIKit/Voice/01-Hello/README.md b/Examples/UIKit/Voice/01-Hello/README.md index d3da874..13d469c 100644 --- a/Examples/UIKit/Voice/01-Hello/README.md +++ b/Examples/UIKit/Voice/01-Hello/README.md @@ -9,7 +9,7 @@ open VoiceUIKit.xcodeproj # from this folder ``` 1. Set your team under **Signing & Capabilities** (a device build needs one). -2. In `CallViewController.swift`, fill in both credentials from **Agent Studio › Connector Settings**: `apiKey` (your connector token, currently `"YOUR_API_KEY"`) and `webrtcToken` (the gateway token — a **distinct** value, currently `"YOUR_WEBRTC_TOKEN"`). +2. In `CallViewController.swift`, fill in both credentials from **Agent Studio › Connector Settings**: `apiKey` (your connector token, currently `"YOUR_CONNECTOR_TOKEN"`) and `webrtcToken` (the web calling token — a **distinct** value, currently `"YOUR_WEB_CALLING_TOKEN"`). 3. Run on a **physical iPhone** — the simulator can't carry WebRTC media. Allow the microphone, tap **Start call**, and talk. Mic permission (`NSMicrophoneUsageDescription`) and the `audio` background mode are already configured via `project.yml`, so the call keeps running when you background the app. @@ -32,8 +32,8 @@ Each subsection leads with **the SDK call** (the actual API), then shows **how i ```swift let call = try PolyVoice.call( - config: Configuration(apiKey: "YOUR_API_KEY"), // connector token - options: VoiceOptions(webrtcToken: "YOUR_WEBRTC_TOKEN") // gateway token — a distinct value + config: Configuration(apiKey: "YOUR_CONNECTOR_TOKEN"), // connector token + options: VoiceOptions(webrtcToken: "YOUR_WEB_CALLING_TOKEN") // web calling token — a distinct value ) // throws PolyError.invalidConfiguration on a blank token, // or a .custom environment without VoiceOptions.signalingHost ``` @@ -50,7 +50,7 @@ do { call = newCall ``` -**Under the hood:** building the call does no network work — it validates the tokens and wires the WebRTC engine to the same REST/session/signaling pipeline the SDK's tests exercise. Everything starts at `start()`. The two tokens do different jobs: the API key authenticates the call session, the WebRTC token authenticates the signaling offer and the ICE-servers fetch. +**Under the hood:** building the call does no network work — it validates the tokens and wires the WebRTC engine to the same REST/session/signaling pipeline the SDK's tests exercise. Everything starts at `start()`. The two tokens do different jobs: the connector token authenticates the call session, the web calling token authenticates the signaling offer and the ICE-servers fetch. *See [voice guide › Credentials](../../../../docs/PolyVoice.md#credentials).* diff --git a/Examples/UIKit/Voice/02-CallKit/CallViewController.swift b/Examples/UIKit/Voice/02-CallKit/CallViewController.swift index f2acd1b..121464d 100644 --- a/Examples/UIKit/Voice/02-CallKit/CallViewController.swift +++ b/Examples/UIKit/Voice/02-CallKit/CallViewController.swift @@ -112,13 +112,13 @@ final class CallViewController: UIViewController { private func startCall() { // Fill in your connector from Agent Studio › Connector Settings. - let config = Configuration(apiKey: "YOUR_API_KEY") + let config = Configuration(apiKey: "YOUR_CONNECTOR_TOKEN") let newCall: PolyCall do { newCall = try PolyVoice.call( config: config, options: VoiceOptions( - webrtcToken: "YOUR_WEBRTC_TOKEN", + webrtcToken: "YOUR_WEB_CALLING_TOKEN", callKit: callKitAvailable // audio start/stop deferred to CallKit ) ) diff --git a/Examples/UIKit/Voice/02-CallKit/README.md b/Examples/UIKit/Voice/02-CallKit/README.md index a0e83d1..724c2ef 100644 --- a/Examples/UIKit/Voice/02-CallKit/README.md +++ b/Examples/UIKit/Voice/02-CallKit/README.md @@ -5,7 +5,7 @@ ## Run it 1. Open `VoiceCallKitUIKit.xcodeproj` (or `xcodegen generate` first if you changed `project.yml`). -2. Drop your **connector token** and **WebRTC token** into the `PolyVoice.call(...)` block in `CallViewController.swift` (both from Agent Studio › Connector Settings — see the [voice guide › Credentials](../../../../docs/PolyVoice.md#credentials)). +2. Drop your **connector token** and **web calling token** into the `PolyVoice.call(...)` block in `CallViewController.swift` (both from Agent Studio › Connector Settings — see the [voice guide › Credentials](../../../../docs/PolyVoice.md#credentials)). 3. Everything the app needs is preconfigured in `project.yml`: the mic permission (`NSMicrophoneUsageDescription` — allow it on first call) and `UIBackgroundModes: [audio, voip]`. Note that **`voip` is required** — without it CallKit refuses every transaction (`requesttransaction Code=1`) and the Start button appears dead. 4. Run on a **physical device**. WebRTC media can't cross the simulator, and CallKit itself is broken there (iOS 17+ simulators auto-end the call; `didActivate` never fires) — on the simulator this example deliberately falls back to a plain `01-Hello`-style call. diff --git a/README.md b/README.md index d834c6c..b434627 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ targets: Then initialize once at app launch. The exact placement — SwiftUI's `@main` App init, or UIKit's `AppDelegate.application(_:didFinishLaunchingWithOptions:)` — is shown in full in the [Quick start](#quick-start) below. -> Your app's bundle identifier is sent automatically as the `X-Host` header — it must match the host registered in Agent Studio for your API key. +> Your app's bundle identifier is sent automatically as the `X-Host` header — it must match the host registered in Agent Studio for your connector token. --- @@ -97,7 +97,7 @@ import PolyMessaging struct MyApp: App { init() { PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" // Agent Studio → Connector Settings + apiKey: "YOUR_CONNECTOR_TOKEN" // Agent Studio → Connector Settings )) } var body: some Scene { WindowGroup { ContentView() } } @@ -158,7 +158,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Initialize the SDK once at launch. No network happens here — // chat() / start() does the work later. PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" // Agent Studio → Connector Settings + apiKey: "YOUR_CONNECTOR_TOKEN" // Agent Studio → Connector Settings )) return true } @@ -257,7 +257,7 @@ final class ViewController: UIViewController, UITableViewDataSource { ```swift PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY", + apiKey: "YOUR_CONNECTOR_TOKEN", streamingEnabled: false // off → completed bubbles only )) ``` @@ -285,8 +285,8 @@ import PolyMessaging import PolyVoice let call = try PolyVoice.call( - config: Configuration(apiKey: "YOUR_API_KEY"), // connector token - options: VoiceOptions(webrtcToken: "YOUR_WEBRTC_TOKEN") // WebRTC token — distinct; both from Agent Studio + config: Configuration(apiKey: "YOUR_CONNECTOR_TOKEN"), // connector token + options: VoiceOptions(webrtcToken: "YOUR_WEB_CALLING_TOKEN") // web calling token — distinct; both from Agent Studio ) Task { for await state in call.states { render(state) } } // .connecting → .connected → … try await call.start() // after the microphone permission (NSMicrophoneUsageDescription) is granted @@ -294,7 +294,7 @@ try await call.start() // after the microphone permission (NSMicrophoneUsageDe A call needs **two credentials, both required and distinct**, from [Agent Studio](https://studio.poly.ai) › **Connector Settings** (the same connector you use for chat): -the **API key** (`Configuration.apiKey`, authenticates the connector) and the **WebRTC token** +the **connector token** (`Configuration.apiKey`, authenticates the connector) and the **web calling token** (`VoiceOptions.webrtcToken`, authenticates the media gateway). Add **`PolyVoice`** via SPM (`.product(name: "PolyVoice", package: "ios-sdk")`) or CocoaPods @@ -319,7 +319,7 @@ Runnable demos: [`Examples/SwiftUI/Voice`](Examples/SwiftUI/Voice/01-Hello/) · | `agentAvatarUrl` | `URL?` | latest agent / live-agent avatar | | `hasStarted` | `Bool` | the conversation has begun | | `hasEnded` | `Bool` | conversation is over — swap the composer for a "start new" CTA | -| `failureReason` | `PolyError?` | non-nil once the chat hits a terminal failure it can't auto-recover from — invalid API key, reconnect budget exhausted, session expired | +| `failureReason` | `PolyError?` | non-nil once the chat hits a terminal failure it can't auto-recover from — invalid connector token, reconnect budget exhausted, session expired | **Methods you call:** @@ -471,7 +471,7 @@ The agent's reply arrives as a sequence of chunks. `ChatSession` reassembles the ```swift PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY", + apiKey: "YOUR_CONNECTOR_TOKEN", streamingEnabled: true // default — set to false for complete messages only )) @@ -1455,7 +1455,7 @@ Subscribe *before* sending — `events` is lazy-start. Runnable in the **03 Rich ```swift PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY" + apiKey: "YOUR_CONNECTOR_TOKEN" )) ``` @@ -1463,7 +1463,7 @@ PolyMessaging.initialize(.init( | Field | Default | Description | |---|---|---| -| `apiKey` | — (required) | API key from Agent Studio. Treat as a credential — never log it. | +| `apiKey` | — (required) | Connector token from Agent Studio. Treat as a credential — never log it. | | `environment` | `.us` | Production region (`.us` / `.uk` / `.euw`) or escape hatch (see below) | | `hostIdentifier` | Bundle ID | `X-Host` for connector validation; auto-derived from `Bundle.main.bundleIdentifier` | | `streamingEnabled` | `true` | `true`: agent replies grow token-by-token (ChatGPT-style). `false`: complete-message bubbles only. See [Streaming](#streaming) | @@ -1485,7 +1485,7 @@ Most apps don't need to set `environment` at all. Pass it only when targeting a ```swift // Run against the dev cluster instead of production US: PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY", + apiKey: "YOUR_CONNECTOR_TOKEN", environment: .cluster("dev") )) ``` @@ -1494,7 +1494,7 @@ A fully-specified configuration (every value here has a working default — set ```swift PolyMessaging.initialize(.init( - apiKey: "YOUR_API_KEY", + apiKey: "YOUR_CONNECTOR_TOKEN", environment: .us, // .us (default) | .uk | .euw | .cluster("dev") | .custom(...) hostIdentifier: "com.yourapp.ios", // X-Host for connector validation; defaults to your bundle id streamingEnabled: true, // server streams agent replies as chunks @@ -1520,7 +1520,7 @@ do { } switch error { -case .auth(.unauthorized): showError("Invalid API key") +case .auth(.unauthorized): showError("Invalid connector token") case .session(.sessionExpired): showError("Session timed out") case .transport(.networkError(let reason)): showError("Network: \(reason)") default: showError("\(error)") @@ -1532,7 +1532,7 @@ Every case `PolyError` can throw, and when: | Case | Fires when | Retryable | |---|---|---| | `.auth(.tokenAcquisitionFailed)` | the access-token request failed | no | -| `.auth(.unauthorized)` | the API key was rejected (401/403) | no | +| `.auth(.unauthorized)` | the connector token was rejected (401/403) | no | | `.session(.sessionCreationFailed(code))` | the server refused to create a session (`code` says why) | no | | `.session(.unexpectedDisconnect(code:reason:))` | the socket dropped unexpectedly | yes | | `.session(.maxReconnectAttemptsExceeded)` | reconnects were exhausted (terminal — offer `resume()`) | yes | @@ -1639,7 +1639,7 @@ A 7-rung ladder — each level builds on the previous one; see its README for wh A one-screen **tap-to-call** demo on the separate [`PolyVoice`](docs/PolyVoice.md) product — build a `PolyCall`, observe its lifecycle, start / mute / end, with a speaker toggle. Set your connector token + -WebRTC token in the `PolyVoice.call(...)` block. Needs a **physical device** (the simulator can't carry +web calling token in the `PolyVoice.call(...)` block. Needs a **physical device** (the simulator can't carry WebRTC media). See [Voice calling](#voice-calling-polyvoice). | Level | What it covers | SwiftUI · UIKit | diff --git a/Sources/PolyMessaging/Configuration.swift b/Sources/PolyMessaging/Configuration.swift index 54cbf8d..c26fe72 100644 --- a/Sources/PolyMessaging/Configuration.swift +++ b/Sources/PolyMessaging/Configuration.swift @@ -6,7 +6,7 @@ public struct Configuration: Sendable { public let apiKey: String public let environment: Environment /// When nil, defaults to the app's bundle identifier (e.g. `com.yourcompany.app`). - /// Must match the host domain registered in Agent Studio when generating the API key. + /// Must match the host domain registered in Agent Studio when generating the connector token. public let hostIdentifier: String? public let streamingEnabled: Bool public let logLevel: LogLevel diff --git a/Sources/PolyMessaging/Internal/Voice/IceServersProvider.swift b/Sources/PolyMessaging/Internal/Voice/IceServersProvider.swift index 5bf4340..9f99923 100644 --- a/Sources/PolyMessaging/Internal/Voice/IceServersProvider.swift +++ b/Sources/PolyMessaging/Internal/Voice/IceServersProvider.swift @@ -15,7 +15,7 @@ struct StaticIceServersProvider: IceServersProviding { } /// Fetches ICE servers from the gateway (`GET /api/v1/ice-servers?token=…`), -/// authenticated with the gateway (WebRTC) token. Best-effort: any failure — or +/// authenticated with the web calling token. Best-effort: any failure — or /// an empty list — falls back to public STUN so a call still connects on open /// NATs. struct GatewayIceServersFetcher: IceServersProviding { diff --git a/Sources/PolyMessaging/PolyMessaging.swift b/Sources/PolyMessaging/PolyMessaging.swift index d67fe89..a69635c 100644 --- a/Sources/PolyMessaging/PolyMessaging.swift +++ b/Sources/PolyMessaging/PolyMessaging.swift @@ -10,7 +10,7 @@ public enum PolyMessaging { public static func initialize(_ config: Configuration) { guard !config.apiKey.isEmpty else { - fatalError("PolyMessaging: apiKey must not be empty. Get your key from Agent Studio.") + fatalError("PolyMessaging: apiKey must not be empty. Get your connector token from Agent Studio.") } configLock.lock() _config = config @@ -37,7 +37,7 @@ public enum PolyMessaging { private static func makeClient(_ config: Configuration) -> PolyMessagingClient { guard !config.apiKey.isEmpty else { - fatalError("PolyMessaging: apiKey must not be empty. Get your key from Agent Studio.") + fatalError("PolyMessaging: apiKey must not be empty. Get your connector token from Agent Studio.") } return PolyMessagingClient(config: config) } diff --git a/Sources/PolyMessaging/Public/ChatSession.swift b/Sources/PolyMessaging/Public/ChatSession.swift index 72512ba..9889ad2 100644 --- a/Sources/PolyMessaging/Public/ChatSession.swift +++ b/Sources/PolyMessaging/Public/ChatSession.swift @@ -15,7 +15,7 @@ public final class ChatSession: ObservableObject { /// True once the session can exchange messages. @Published public private(set) var isReady: Bool = false /// Non-nil when the chat has hit a terminal failure it can't auto-recover - /// from. Today that covers an invalid API key rejected during the + /// from. Today that covers an invalid connector token rejected during the /// initial connect, the reconnect budget being exhausted, and an expired /// session. UIs typically render this as a full-screen error state with a /// manual retry affordance that calls `client.resume()`. @@ -120,7 +120,7 @@ public final class ChatSession: ObservableObject { guard let self else { return } self.isReady = state.isReady self.applySessionIdChange(state.sessionId) - // An invalid API key rejected during the initial + // An invalid connector token rejected during the initial // connect throws inside Coordinator.start() and never reaches // connectionStatus.failed. Surface it here so failureReason // remains the single source of truth for terminal failures. diff --git a/Sources/PolyMessaging/Public/DevSettings.swift b/Sources/PolyMessaging/Public/DevSettings.swift index 68f16f5..2a61ef9 100644 --- a/Sources/PolyMessaging/Public/DevSettings.swift +++ b/Sources/PolyMessaging/Public/DevSettings.swift @@ -8,7 +8,7 @@ import Combine /// and protocol testing. Backed by `UserDefaults`, observable from both /// SwiftUI (`@StateObject` / `@ObservedObject`) and UIKit (Combine `sink`). /// -/// The API key is taken from the config you passed to +/// The connector token is taken from the config you passed to /// ``PolyMessaging/initialize(_:)`` — call `initialize` first, then construct /// `DevSettings()` with no arguments. The default environment is seeded from /// that same config, and the `X-Host` is derived from the selected environment @@ -79,8 +79,8 @@ open class DevSettings: ObservableObject { // MARK: - Init - /// Call ``PolyMessaging/initialize(_:)`` first — the API key and the - /// seed environment are read from that config. + /// Call ``PolyMessaging/initialize(_:)`` first — the connector token and + /// the seed environment are read from that config. /// /// - Parameters: /// - hostIdentifier: Optional `X-Host` override. nil = derive from the @@ -200,7 +200,7 @@ open class DevSettings: ObservableObject { lastAppliedStreamingEnabled = streamingEnabled } - /// Builds a ``Configuration`` from the `initialize(_:)` API key and + /// Builds a ``Configuration`` from the `initialize(_:)` connector token and /// the current runtime knobs. The `X-Host` is left to the SDK to derive from /// the selected environment unless a `hostIdentifier` override was supplied. /// Override this method to customise. diff --git a/Sources/PolyMessaging/Public/PolyError.swift b/Sources/PolyMessaging/Public/PolyError.swift index d3baf73..1944771 100644 --- a/Sources/PolyMessaging/Public/PolyError.swift +++ b/Sources/PolyMessaging/Public/PolyError.swift @@ -109,7 +109,7 @@ extension PolyError: CustomStringConvertible { case .auth(.tokenAcquisitionFailed): return "Couldn't get an access token. Check your connection and try again." case .auth(.unauthorized): - return "Your API key was rejected. Please contact support." + return "Your connector token was rejected. Please contact support." case .session(.sessionCreationFailed(let code)): // code.rawValue is the human-readable string the backend sent diff --git a/Sources/PolyMessaging/Public/SessionState.swift b/Sources/PolyMessaging/Public/SessionState.swift index 18fe8bb..857619c 100644 --- a/Sources/PolyMessaging/Public/SessionState.swift +++ b/Sources/PolyMessaging/Public/SessionState.swift @@ -27,7 +27,7 @@ public struct SessionState: Sendable, Equatable { public extension SessionState { var isError: Bool { hasInvalidApiKey || error != nil } - var errorMessage: String? { hasInvalidApiKey ? "Invalid API key" : error?.rawValue } + var errorMessage: String? { hasInvalidApiKey ? "Invalid connector token" : error?.rawValue } var canSendMessages: Bool { isReady && !isError } var isTerminal: Bool { status == .ended || status == .expired } } diff --git a/Sources/PolyMessaging/Public/Voice/PolyCall.swift b/Sources/PolyMessaging/Public/Voice/PolyCall.swift index a0288a9..0fb7026 100644 --- a/Sources/PolyMessaging/Public/Voice/PolyCall.swift +++ b/Sources/PolyMessaging/Public/Voice/PolyCall.swift @@ -149,8 +149,8 @@ public extension PolyCall { /// the same internal REST/session/signaling pipeline the tests exercise. /// /// - Parameters: - /// - config: the shared messaging `Configuration` (api key, environment, host). - /// - webrtcToken: the WebRTC gateway token (the offer `authToken` + ICE-servers auth). + /// - config: the shared messaging `Configuration` (connector token, environment, host). + /// - webrtcToken: the web calling token (the offer `authToken` + ICE-servers auth). /// - signalingHost: optional gateway-host override (required for `.custom`). /// - mediaEngine: the platform WebRTC engine that produces the SDP offer and carries audio. /// - Throws: `PolyError.invalidConfiguration` for a `.custom` environment without a `signalingHost`. diff --git a/Sources/PolyVoice/PolyVoice.swift b/Sources/PolyVoice/PolyVoice.swift index fdaa48c..5a61b5b 100644 --- a/Sources/PolyVoice/PolyVoice.swift +++ b/Sources/PolyVoice/PolyVoice.swift @@ -28,7 +28,7 @@ public enum PolyVoice { /// it — observe `PolyCall.states` and call `PolyCall.start()`. /// /// - Parameters: - /// - config: the shared messaging `Configuration` (api key, environment, host). + /// - config: the shared messaging `Configuration` (connector token, environment, host). /// - options: voice options — `VoiceOptions.webrtcToken` is required. /// - Throws: `PolyError.invalidConfiguration` if `apiKey`/`webrtcToken` is empty, or the /// environment is `.custom` without `VoiceOptions.signalingHost`. diff --git a/Sources/PolyVoice/VoiceOptions.swift b/Sources/PolyVoice/VoiceOptions.swift index 4a4a6e6..d1eb44e 100644 --- a/Sources/PolyVoice/VoiceOptions.swift +++ b/Sources/PolyVoice/VoiceOptions.swift @@ -4,12 +4,12 @@ import Foundation /// Options for ``PolyVoice/call(config:options:)``. /// -/// `webrtcToken` is **required** — every voice call needs the WebRTC gateway -/// token, a distinct value from the API key (both come from Agent Studio › -/// Connector Settings). +/// `webrtcToken` is **required** — every voice call needs the web calling +/// token, a distinct value from the connector token (both come from Agent +/// Studio › Connector Settings). public struct VoiceOptions: Sendable { - /// The connector's WebRTC token — authenticates the signaling offer + the + /// The connector's web calling token — authenticates the signaling offer + the /// ICE-servers fetch. Always distinct from `Configuration.apiKey`. public let webrtcToken: String diff --git a/Tests/PolyMessagingTests/PolyErrorDescriptionTests.swift b/Tests/PolyMessagingTests/PolyErrorDescriptionTests.swift index 0815350..a30f446 100644 --- a/Tests/PolyMessagingTests/PolyErrorDescriptionTests.swift +++ b/Tests/PolyMessagingTests/PolyErrorDescriptionTests.swift @@ -80,7 +80,7 @@ final class PolyErrorDescriptionTests: XCTestCase { func testAuthUnauthorizedWording() { let s = PolyError.auth(.unauthorized).description - XCTAssertTrue(s.contains("API key"), s) + XCTAssertTrue(s.contains("connector token"), s) XCTAssertTrue(s.contains("rejected") || s.contains("invalid") || s.contains("Please"), s) } diff --git a/Tests/PolyMessagingTests/Voice/LiveSignalingProbeTests.swift b/Tests/PolyMessagingTests/Voice/LiveSignalingProbeTests.swift index b2a6f5d..f9069d4 100644 --- a/Tests/PolyMessagingTests/Voice/LiveSignalingProbeTests.swift +++ b/Tests/PolyMessagingTests/Voice/LiveSignalingProbeTests.swift @@ -17,7 +17,7 @@ import XCTest /// faithful check of everything except the on-device audio. final class LiveSignalingProbeTests: XCTestCase { - /// API key for the live probe. Supply it via the `POLY_LIVE_VOICE_TOKEN` + /// connector token for the live probe. Supply it via the `POLY_LIVE_VOICE_TOKEN` /// environment variable when running; defaults to empty otherwise. private let devToken = "" diff --git a/docs/PolyVoice.md b/docs/PolyVoice.md index 933ab6f..90b0146 100644 --- a/docs/PolyVoice.md +++ b/docs/PolyVoice.md @@ -37,8 +37,8 @@ import PolyMessaging import PolyVoice let call = try PolyVoice.call( - config: Configuration(apiKey: "YOUR_API_KEY"), // connector token — Agent Studio › Connector Settings - options: VoiceOptions(webrtcToken: "YOUR_WEBRTC_TOKEN") // WebRTC token — same place, a distinct value + config: Configuration(apiKey: "YOUR_CONNECTOR_TOKEN"), // connector token — Agent Studio › Connector Settings + options: VoiceOptions(webrtcToken: "YOUR_WEB_CALLING_TOKEN") // web calling token — same place, a distinct value ) // throws PolyError.invalidConfiguration on a blank token or a .custom env without signalingHost // Observe the lifecycle: .idle → .connecting → .connected → .ended / .failed @@ -128,8 +128,8 @@ you use for chat): | Value | What it is | Sent as | |---|---|---| -| **API key** — `Configuration.apiKey` | your connector token | `X-Token` (authenticates the call) | -| **WebRTC token** — `VoiceOptions.webrtcToken` | the gateway auth token — a **distinct** token from the API key | the offer `authToken` + ICE-servers fetch | +| **Connector token** — `Configuration.apiKey` | your connector token | `X-Token` (authenticates the call) | +| **Web calling token** — `VoiceOptions.webrtcToken` | the media-gateway auth token — a **distinct** token from the connector token | the offer `authToken` + ICE-servers fetch | > **Region:** calls default to the US gateway. For a UK / EUW / other-region (or dev) agent, set the > environment on the shared `Configuration` — e.g. `Configuration(apiKey: …, environment: .cluster("…"))`, @@ -166,7 +166,7 @@ Both example apps ship a **speaker toggle**. ## Troubleshooting -- **"API key was rejected" / fails while connecting** — both tokens come from the *same* +- **"Connector token was rejected" / fails while connecting** — both tokens come from the *same* connector in Agent Studio › Connector Settings, and the `Configuration` must match that connector's **environment** (region/cluster) and registered **host** (`hostIdentifier` / the app's bundle id). A token from one environment silently 401s on another. @@ -212,4 +212,4 @@ signaling pipeline (auth → session → link → signaling → offer/answer/ICE **Example:** a one-screen tap-to-call demo in both toolkits — [`Examples/SwiftUI/Voice/01-Hello`](../Examples/SwiftUI/Voice/01-Hello) · [`Examples/UIKit/Voice/01-Hello`](../Examples/UIKit/Voice/01-Hello). Drop your connector token + -WebRTC token into the `PolyVoice.call(...)` block and run. +web calling token into the `PolyVoice.call(...)` block and run. diff --git a/scripts/e2e-validation.sh b/scripts/e2e-validation.sh index 945eb17..16c6dd5 100755 --- a/scripts/e2e-validation.sh +++ b/scripts/e2e-validation.sh @@ -8,7 +8,7 @@ # × 03/06/07, then (3b) the reboot/resume-dedupe test on SwiftUI 06. # 4. Drops everything into /tmp/poly-e2e/ + prints a pass/fail summary. # -# The API key MUST be provided via POLY_CONNECTOR_TOKEN env var — +# The connector token MUST be provided via POLY_CONNECTOR_TOKEN env var — # never hard-coded. # # Usage: @@ -136,7 +136,7 @@ echo "==> Using simulator UDID: $BOOTED_UDID" # --------------------------------------------------------------------------- # Patch token into all example App.swift files # --------------------------------------------------------------------------- -echo "==> Patching API key into example App.swift files (will revert on exit)" +echo "==> Patching connector token into example App.swift files (will revert on exit)" mkdir -p "$BACKUP_DIR" # patch_app @@ -159,7 +159,7 @@ import os, re, sys path = sys.argv[1] tok, env, host = os.environ["TOKEN"], os.environ.get("ENVV",""), os.environ.get("HOSTID","") s = open(path).read() -s = s.replace("YOUR_API_KEY", tok) +s = s.replace("YOUR_CONNECTOR_TOKEN", tok) if env: fields = [f'apiKey: "{tok}"', f'environment: {env}'] if host: