# SDK Reference

## Contents
- [SDK Generation](#sdk-generation)
- [Web SDK](#web-sdk)
- [Android SDK](#android-sdk)
- [iOS SDK](#ios-sdk)
- [Admin SDK](#admin-sdk)

---

## SDK Generation

Configure SDK generation in `connector.yaml`:

```yaml
connectorId: my-connector
generate:
  javascriptSdk:
    outputDir: "../web-app/src/lib/dataconnect"
    package: "@movie-app/dataconnect"
  kotlinSdk:
    outputDir: "../android-app/app/src/main/kotlin/com/example/dataconnect"
    package: "com.example.dataconnect"
  swiftSdk:
    outputDir: "../ios-app/DataConnect"
```

Generate SDKs:
```bash
npx -y firebase-tools@latest dataconnect:sdk:generate
```

---

## Web SDK

### Installation

```bash
npm install firebase
```

### Initialization

```typescript
import { initializeApp } from 'firebase/app';
import { getDataConnect, connectDataConnectEmulator } from 'firebase/data-connect';
import { connectorConfig } from '@movie-app/dataconnect';

const app = initializeApp(firebaseConfig);
const dc = getDataConnect(app, connectorConfig);

// For local development
if (import.meta.env.DEV) {
  connectDataConnectEmulator(dc, 'localhost', 9399);
}
```

### Calling Operations

```typescript
// Generated SDK provides typed functions
import { listMovies, createMovie, getMovie } from '@movie-app/dataconnect';

// Accessing Nested Fields
const movie = await getMovie({ id: '...' });
// Relations are just properties on the object
const director = movie.data.movie.metadata.director; 
const firstActor = movie.data.movie.actors[0].name;

// Query
const result = await listMovies();
console.log(result.data.movies);

// Query with variables
const movie = await getMovie({ id: 'uuid-here' });

// Mutation
const newMovie = await createMovie({ 
  title: 'New Movie', 
  genre: 'Action' 
});
console.log(newMovie.data.movie_insert); // Returns key
```

### Subscriptions

```typescript
import { listMoviesRef, subscribe } from '@movie-app/dataconnect';

const unsubscribe = subscribe(listMoviesRef(), {
  onNext: (result) => {
    console.log('Movies updated:', result.data.movies);
  },
  onError: (error) => {
    console.error('Subscription error:', error);
  }
});

// Later: unsubscribe();
```

### With Authentication

```typescript
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth';

const auth = getAuth(app);
await signInWithEmailAndPassword(auth, email, password);

// SDK automatically includes auth token in requests
const myReviews = await myReviews(); // @auth(level: USER) query from examples.md
```

---

## Android SDK

### Dependencies (build.gradle.kts)

```kotlin
dependencies {
    implementation(platform("com.google.firebase:firebase-bom:33.0.0"))
    implementation("com.google.firebase:firebase-dataconnect")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.0")
}
```

### Initialization

```kotlin
import com.google.firebase.Firebase
import com.google.firebase.dataconnect.dataConnect
import com.example.dataconnect.MyConnector

val connector = MyConnector.instance

// For emulator
connector.dataConnect.useEmulator("10.0.2.2", 9399)
```

### Calling Operations

```kotlin
// Query
val result = connector.listMovies.execute()
result.data.movies.forEach { movie ->
    println(movie.title)
    // Access nested fields directly
    println(movie.metadata?.director)
    println(movie.actors.firstOrNull()?.name)
}

// Query with variables
val movie = connector.getMovie.execute(id = "uuid-here")

// Mutation
val newMovie = connector.createMovie.execute(
    title = "New Movie",
    genre = "Action"
)
```

### Flow Subscription

```kotlin
connector.listMovies.flow().collect { result ->
    when (result) {
        is DataConnectResult.Success -> updateUI(result.data.movies)
        is DataConnectResult.Error -> showError(result.exception)
    }
}
```

---

## iOS SDK

### Dependencies (Package.swift or SPM)

```swift
dependencies: [
    .package(url: "https://github.com/firebase/firebase-ios-sdk.git", from: "11.0.0")
]
// Add FirebaseDataConnect to target dependencies
```

### Initialization

```swift
import FirebaseCore
import FirebaseDataConnect

FirebaseApp.configure()
let connector = MyConnector.shared

// For emulator
connector.useEmulator(host: "localhost", port: 9399)
```

### Calling Operations

```swift
// Query
let result = try await connector.listMovies.execute()
for movie in result.data.movies {
    print(movie.title)
    // Access nested fields directly
    print(movie.metadata?.director ?? "Unknown")
    print(movie.actors.first?.name ?? "No actors")
}

// Query with variables
let movie = try await connector.getMovie.execute(id: "uuid-here")

// Mutation
let newMovie = try await connector.createMovie.execute(
    title: "New Movie",
    genre: "Action"
)
```

### Combine Publisher

```swift
connector.listMovies.publisher
    .sink(
        receiveCompletion: { completion in
            if case .failure(let error) = completion {
                print("Error: \(error)")
            }
        },
        receiveValue: { result in
            self.movies = result.data.movies
        }
    )
    .store(in: &cancellables)
```

---



## Admin SDK

Server-side operations with elevated privileges (bypasses @auth):

### Node.js

```typescript
import { initializeApp, cert } from 'firebase-admin/app';
import { getDataConnect } from 'firebase-admin/data-connect';

initializeApp({
  credential: cert(serviceAccount)
});

const dc = getDataConnect();

// Execute operations (bypasses @auth)
const result = await dc.executeGraphql({
  query: `query { users { id email } }`,
  operationName: 'ListAllUsers'
});

// Or use generated Admin SDK
import { listAllUsers } from './admin-connector';
const users = await listAllUsers();
```

### Generate Admin SDK

In `connector.yaml`:

```yaml
generate:
  nodeAdminSdk:
    outputDir: "./admin-sdk"
    package: "@app/admin-dataconnect"
```

Generate:
```bash
npx -y firebase-tools@latest dataconnect:sdk:generate
```
