# snoozestack-swift — Swift

> The Swift client SDK for snoozestack (iOS, macOS, tvOS, watchOS).

[HTML version](https://snoozestack.com/docs/sdk-swift/) · [Docs index](https://snoozestack.com/llms.txt)

snoozestack-swift v1.13.0 · [Install or upgrade](https://snoozestack.com/docs/installation.md)

`snoozestack-swift` is the client for Apple platforms (iOS, macOS, tvOS, watchOS): application identity, functions, push registration, and signals. There is no query builder, by design — a table is reachable only through a committed function (see [Permissions](https://snoozestack.com/docs/permissions.md)). Add it from [snoozestack.com/swift](https://snoozestack.com/docs/installation.md). Two library products — `SnoozeStack` (the full client) and `SnoozeStackSignals` (signals only, a single dependency-free file).

```bash title="setup"
import SnoozeStack

// Once, at launch (e.g. in your App init). URL + anon key: Project Overview.
let snoozestack = SnoozeStack.createClient(
    url: "https://<project-ref>.snzzz.com",   // SNOOZESTACK_URL
    key: "<SNOOZESTACK_ANON_KEY>"
)
```

### Database

A table is only reachable from inside a [function](https://snoozestack.com/docs/functions.md); call it the same way as any other:

```swift
struct Club: Decodable { let id: Int; let name: String; let distance: Int }

struct ClubsResponse: Decodable { let clubs: [Club] }

let response: ClubsResponse = try await snoozestack.functions
    .invoke("list-clubs")
    .value
```

### Application identity

`SnoozeStackIdentity` is the auth surface — the same four sign-in methods as [snoozestack-js](https://snoozestack.com/docs/sdk-js.md) (magic link, Google, Apple, email/password) with async/await and Keychain-backed sessions.

```swift
let identity = SnoozeStackIdentity(url: projectURL, apiKey: anonKey)

// Magic link: request, then complete from the universal link's token
try await identity.requestMagicLink(email: email, redirectTo: callbackURL)
let result = try await identity.completeMagicLink(token: token)

// Google / Apple: open the returned URL, then complete on the callback.
// (Apple private-relay addresses come back as the user's email as-is.)
let url = identity.startOAuth(provider: "apple", redirectTo: callbackURL)
let oauth = try await identity.completeOAuthCallback(url: incomingURL)

// Email/password: sign-up stays pending until the verification email is
// proven; sign-in is immediate once a password exists.
let verificationRequired = try await identity.signUpWithPassword(
    email: email, password: password, redirectTo: callbackURL)
let user = try await identity.signInWithPassword(email: email, password: password)

// A magic-link/OAuth-only user sets a first password by passing nil.
try await identity.changePassword(currentPassword: current, newPassword: new)

// Self-serve deletion (App Store 5.1.1(v)): remove your own data about the
// user first, then this deletes the identity and signs out locally.
try await identity.deleteAccount()

// Native sign-in — no web sheet, no redirect. Google's SDK and
// ASAuthorizationController each hand you a signed id_token directly, so
// there is nothing for completeOAuthCallback to read. Pass the RAW nonce you
// generated, never its SHA-256: Apple puts the hash in the token and the
// server compares the two.
let appleUser = try await identity.signInWithIdToken(
    provider: "apple", idToken: appleIDToken, nonce: rawNonce)
let googleUser = try await identity.signInWithIdToken(
    provider: "google", idToken: googleIDToken)
```

### Functions

```swift
// POST by default. The signed-in session is attached automatically.
let reply: ChatReply = try await snoozestack.functions
    .invoke("chat", body: ["messages": messages])

// A reading function is a GET.
let wallets: [Wallet] = try await snoozestack.functions.invoke("wallets", method: .get)
```

There is no storage client: uploads go through a function of yours that returns a presigned URL, which the app then PUTs to directly. A public bucket needs no call — the object URL is stable at `<SNOOZESTACK_URL>/storage/v1/object/public/<bucket>/<path>`.

### Signals

Every client has a `signals` handle; events are persisted to disk (so they survive app kills) and flushed on a timer, at batch size, and when the app is backgrounded. See [Signals](https://snoozestack.com/docs/signals.md).

```swift
snoozestack.signals.identify(user.id.uuidString)
snoozestack.signals.track("signup", properties: ["plan": "pro"])
```

### Push notifications

```swift
// After registerForRemoteNotifications() hands you the token:
try await snoozestack.push.register(deviceToken: token)
try await snoozestack.push.unregister()   // on sign-out
```

See [Push Notifications](https://snoozestack.com/docs/push-notifications.md) for the APNs setup, environments, and sending. Realtime subscriptions are not supported.
