Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions plugins/emulate/.agents/skills/emulate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ slack:
name: My Slack App
redirect_uris:
- http://localhost:3000/api/auth/callback/slack
signing_secret: my_signing_secret

linear:
organization:
Expand Down Expand Up @@ -421,6 +422,8 @@ twilio:
- friendly_name: Local Conversations
```

`slack.signing_secret` signs every outbound event subscription callback. Signed callbacks include `X-Slack-Request-Timestamp` and `X-Slack-Signature`, calculated as `v0=<HMAC-SHA256(secret, "v0:<timestamp>:<raw-body>")>` over the exact serialized callback body. Configure the receiver with the same secret and verify the unparsed request body. Callbacks are unsigned when the secret is absent or empty.

GitHub App `private_key` values are intentionally omitted from starter configuration. Programmatic `createEmulator` calls generate an RSA key and expose it through `generatedSecrets`. CLI startup generates omitted keys only when `--generated-secrets-file <path>` is provided; otherwise the seed must contain an explicit, valid private key. Never use a placeholder PEM value.

GitHub organization `members` are optional. Entries reference seeded users by `login`; `role` defaults to `member`, while `admin` creates an organization administrator. Unknown users are ignored.
Expand Down Expand Up @@ -541,3 +544,7 @@ packages/
```

The core provides a generic `Store` with typed `Collection<T>` instances supporting CRUD, indexing, filtering, and pagination. Each service plugin registers routes with the shared internal app and uses the store for state.

## Custom emulators alongside built-ins

Use `npx emulate init --custom inventory` to scaffold a third-party API emulator and test. The command registers it in a discovered YAML, JSON, TypeScript, or JavaScript config, including one with existing services; unusual executable configs get printed manual registration steps. Run `npx emulate start --watch` to reload imports. Use the service URL and Inspector link in the startup banner for requests because the port depends on the config. Creating a missing local import outside the config directory also retries a failed reload. Successful reloads reset the run to seed. Existing flat seed configs still work; `--config` selects an explicit file. Node 26 loads erasable TypeScript; compile enums and parameter properties to JavaScript first. Node 24 also supports native TypeScript transforms. For authoring and testing third-party API emulators, see https://emulate.dev/docs/custom-emulators.
4 changes: 4 additions & 0 deletions plugins/emulate/.agents/skills/google/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -606,3 +606,7 @@ curl -X POST $BASE/gmail/v1/users/me/messages/send \
curl "$BASE/gmail/v1/users/me/threads?labelIds=INBOX" \
-H "Authorization: Bearer $TOKEN"
```

## Custom emulators alongside built-ins

Use `npx emulate init --custom inventory` to scaffold a third-party API emulator and test. Register it in `emulate.config.ts` with `defineConfig` from `emulate`, alongside built-in entries such as `{ emulator: "google" }`. Run `npx emulate start --watch` to reload imports and inspect custom state at the printed `/_emulate` URL. Successful reloads reset the run to seed. Existing flat seed configs still work; `--config` selects an explicit file. For authoring and testing third-party API emulators, see https://emulate.dev/docs/custom-emulators.
4 changes: 4 additions & 0 deletions plugins/emulate/.agents/skills/resend/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,7 @@ const res = await fetch(`${emu.url}/emails`, {
const { data: emails } = await res.json()
console.log(emails[0].html) // contains "123456"
```

## Custom HTTP APIs alongside built-ins

Use `npx emulate init --custom inventory` to scaffold a custom stateful API and test. Register it in `emulate.config.ts` with `defineConfig` from `emulate`, alongside built-in entries such as `{ emulator: "resend" }`. Run `npx emulate start --watch` to reload imports and inspect custom state at the printed `/_emulate` URL. Successful reloads reset the run to seed. Existing flat seed configs still work; `--config` selects an explicit file. For authoring and testing custom APIs, see https://emulate.dev/docs/custom-apis.
4 changes: 4 additions & 0 deletions plugins/emulate/.agents/skills/stripe/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,7 @@ const pi = await stripe.paymentIntents.create({
const confirmed = await stripe.paymentIntents.confirm(pi.id)
console.log(confirmed.status) // 'succeeded'
```

## Custom emulators alongside built-ins

Use `npx emulate init --custom inventory` to scaffold a third-party API emulator and test. Register it in `emulate.config.ts` with `defineConfig` from `emulate`, alongside built-in entries such as `{ emulator: "stripe" }`. Run `npx emulate start --watch` to reload imports and inspect custom state at the printed `/_emulate` URL. Successful reloads reset the run to seed. Existing flat seed configs still work; `--config` selects an explicit file. For authoring and testing third-party API emulators, see https://emulate.dev/docs/custom-emulators.
7 changes: 7 additions & 0 deletions plugins/emulate/agent/skills/emulate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ slack:
name: My Slack App
redirect_uris:
- http://localhost:3000/api/auth/callback/slack
signing_secret: my_signing_secret

linear:
organization:
Expand Down Expand Up @@ -426,6 +427,8 @@ twilio:
- friendly_name: Local Conversations
```

`slack.signing_secret` signs every outbound event subscription callback. Signed callbacks include `X-Slack-Request-Timestamp` and `X-Slack-Signature`, calculated as `v0=<HMAC-SHA256(secret, "v0:<timestamp>:<raw-body>")>` over the exact serialized callback body. Configure the receiver with the same secret and verify the unparsed request body. Callbacks are unsigned when the secret is absent or empty.

GitHub App `private_key` values are intentionally omitted from starter configuration. Programmatic `createEmulator` calls generate an RSA key and expose it through `generatedSecrets`. CLI startup generates omitted keys only when `--generated-secrets-file <path>` is provided; otherwise the seed must contain an explicit, valid private key. Never use a placeholder PEM value.

GitHub organization `members` are optional. Entries reference seeded users by `login`; `role` defaults to `member`, while `admin` creates an organization administrator. Unknown users are ignored.
Expand Down Expand Up @@ -546,3 +549,7 @@ packages/
```

The core provides a generic `Store` with typed `Collection<T>` instances supporting CRUD, indexing, filtering, and pagination. Each service plugin registers routes with the shared internal app and uses the store for state.

## Custom emulators alongside built-ins

Use `npx emulate init --custom inventory` to scaffold a third-party API emulator and test. The command registers it in a discovered YAML, JSON, TypeScript, or JavaScript config, including one with existing services; unusual executable configs get printed manual registration steps. Run `npx emulate start --watch` to reload imports. Use the service URL and Inspector link in the startup banner for requests because the port depends on the config. Creating a missing local import outside the config directory also retries a failed reload. Successful reloads reset the run to seed. Existing flat seed configs still work; `--config` selects an explicit file. Node 26 loads erasable TypeScript; compile enums and parameter properties to JavaScript first. Node 24 also supports native TypeScript transforms. For authoring and testing third-party API emulators, see https://emulate.dev/docs/custom-emulators.
4 changes: 4 additions & 0 deletions plugins/emulate/agent/skills/google/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -612,3 +612,7 @@ curl -X POST $BASE/gmail/v1/users/me/messages/send \
curl "$BASE/gmail/v1/users/me/threads?labelIds=INBOX" \
-H "Authorization: Bearer $TOKEN"
```

## Custom emulators alongside built-ins

Use `npx emulate init --custom inventory` to scaffold a third-party API emulator and test. Register it in `emulate.config.ts` with `defineConfig` from `emulate`, alongside built-in entries such as `{ emulator: "google" }`. Run `npx emulate start --watch` to reload imports and inspect custom state at the printed `/_emulate` URL. Successful reloads reset the run to seed. Existing flat seed configs still work; `--config` selects an explicit file. For authoring and testing third-party API emulators, see https://emulate.dev/docs/custom-emulators.
4 changes: 4 additions & 0 deletions plugins/emulate/agent/skills/resend/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,7 @@ const res = await fetch(`${emu.url}/emails`, {
const { data: emails } = await res.json()
console.log(emails[0].html) // contains "123456"
```

## Custom HTTP APIs alongside built-ins

Use `npx emulate init --custom inventory` to scaffold a custom stateful API and test. Register it in `emulate.config.ts` with `defineConfig` from `emulate`, alongside built-in entries such as `{ emulator: "resend" }`. Run `npx emulate start --watch` to reload imports and inspect custom state at the printed `/_emulate` URL. Successful reloads reset the run to seed. Existing flat seed configs still work; `--config` selects an explicit file. For authoring and testing custom APIs, see https://emulate.dev/docs/custom-apis.
4 changes: 4 additions & 0 deletions plugins/emulate/agent/skills/stripe/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,7 @@ const pi = await stripe.paymentIntents.create({
const confirmed = await stripe.paymentIntents.confirm(pi.id)
console.log(confirmed.status) // 'succeeded'
```

## Custom emulators alongside built-ins

Use `npx emulate init --custom inventory` to scaffold a third-party API emulator and test. Register it in `emulate.config.ts` with `defineConfig` from `emulate`, alongside built-in entries such as `{ emulator: "stripe" }`. Run `npx emulate start --watch` to reload imports and inspect custom state at the printed `/_emulate` URL. Successful reloads reset the run to seed. Existing flat seed configs still work; `--config` selects an explicit file. For authoring and testing third-party API emulators, see https://emulate.dev/docs/custom-emulators.
8 changes: 4 additions & 4 deletions plugins/emulate/skills-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"source": "vercel-labs/emulate",
"sourceType": "github",
"skillPath": "skills/emulate/SKILL.md",
"computedHash": "a0d283a15db864b6afeaa0d69f30340e863520d4c334af0427b7b6b274ce4fc7"
"computedHash": "ebc9ed29875d7e356c9d9299b218bfdfe3583afad84e4b1ccf07adc91f908b61"
},
"github": {
"source": "vercel-labs/emulate",
Expand All @@ -29,7 +29,7 @@
"source": "vercel-labs/emulate",
"sourceType": "github",
"skillPath": "skills/google/SKILL.md",
"computedHash": "d674361ee9a5422986affc8f0589471d3b0ba78879cab5af7e3228f1561d75e3"
"computedHash": "a80de94e5149e55daa865f7d5da60bdfd63f46c82682b0eb91ebb3db151c7a8e"
},
"linear": {
"source": "vercel-labs/emulate",
Expand All @@ -53,7 +53,7 @@
"source": "vercel-labs/emulate",
"sourceType": "github",
"skillPath": "skills/resend/SKILL.md",
"computedHash": "06b0de0e8863ee3c2c6a2dbd3c97bb9337b7415ff9cfed2778a3a2ac83ac0598"
"computedHash": "56161171fb5dc02b27b323c258976a541abd76141e3f85c7001a9f97bb10d20c"
},
"slack": {
"source": "vercel-labs/emulate",
Expand All @@ -65,7 +65,7 @@
"source": "vercel-labs/emulate",
"sourceType": "github",
"skillPath": "skills/stripe/SKILL.md",
"computedHash": "1a2a421108ed517e769ae751dcafc29301db6db19ea1e3d66a2c3a72efd80097"
"computedHash": "80159ad0e34e8e62ca1f4cca305ba73c5ec8a4bf95e9582afe94966934092be5"
},
"vercel": {
"source": "vercel-labs/emulate",
Expand Down
17 changes: 11 additions & 6 deletions plugins/firebase/.agents/skills/firebase-auth-basics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,16 @@ Configure Firebase Authentication in `firebase.json` by adding an 'auth' block:
```
{
"auth": {
"authorizedDomains": ["localhost"],
"providers": {
"anonymous": true,
"emailPassword": true,
"googleSignIn": {
"oAuthBrandDisplayName": "Your Brand Name",
"supportEmail": "support@example.com"
"supportEmail": "support@example.com",
"authorizedRedirectUris": [
"https://my-project-id.firebaseapp.com/__/auth/handler",
"http://localhost:4000"
]
}
}
}
Expand All @@ -82,10 +85,10 @@ Configure Firebase Authentication in `firebase.json` by adding an 'auth' block:
> [!NOTE] If the Google Sign-In popup opens and immediately closes with the
> error `[firebase_auth/unauthorized-domain]`, it means the domain is not
> authorized. For local development, ensure `localhost` is included in the
> **Authorized Domains** list in the Firebase Console or via the
> `authorizedDomains` field in `firebase.json`. **CRITICAL**: Do NOT include the
> protocol or port number in the Authorized Domains list (e.g., use `localhost`,
> NOT `http://localhost:9090`).
> **Authorized Domains** list in the Firebase Console (Authentication >
> Settings > Authorized domains). **CRITICAL**: Do NOT include the protocol or
> port number in the Authorized Domains list (e.g., use `localhost`, NOT
> `http://localhost:9090`).

**CRITICAL**: After configuring `firebase.json`, you MUST deploy the auth
configuration to the Firebase backend for the changes to take effect. This is
Expand Down Expand Up @@ -113,6 +116,8 @@ Enable other providers in the Firebase Console.
**Android (Kotlin)** See
[references/client_sdk_android.md](references/client_sdk_android.md).

**iOS (Swift)** See [references/ios_setup.md](references/ios_setup.md).

### 3. Security Rules

Secure your data using `request.auth` in Firestore/Storage rules.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ ______________________________________________________________________
In your Activity or Fragment, initialize the `FirebaseAuth` instance:

```kotlin
import com.google.firebase.Firebase
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.ktx.auth
import com.google.firebase.ktx.Firebase
import com.google.firebase.auth.auth

class MainActivity : AppCompatActivity() {

Expand All @@ -48,7 +48,6 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
auth = Firebase.auth

setContent {
MaterialTheme {
Text("Auth initialized!")
Expand All @@ -75,7 +74,7 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val auth = Firebase.auth

setContent {
MaterialTheme {
Text("Auth initialized!")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ signInWithPopup(auth, provider)
> it means the domain hosting your app is not authorized for OAuth operations in
> your Firebase project.
>
> - **Fix**: Add your domain (e.g., `localhost` for local testing) to the
> Authorized Domains list in the Firebase Console (Authentication > Settings >
> Authorized domains) or in your `firebase.json` auth config.
> - **Fix**: Add your domain (e.g., `localhost` for local testing) to the
> Authorized Domains list in the Firebase Console (Authentication >
> Settings > Authorized domains).
> - **CRITICAL**: Do NOT include the protocol or port number when adding the
> domain (e.g., use `localhost`, NOT `http://localhost:9090`).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,17 @@ platform-specific quirks.
`<meta name="google-signin-client_id" ... />` tag in `web/index.html`, the
Dart Web Debug Service (DWDS) and the app will throw an assertion error and
**hang infinitely**, resulting in a blank screen.
- **Common Workaround**: If you intend to use Firebase Auth's
`signInWithPopup(GoogleAuthProvider())` for the web, you can conditionally
skip the local `GoogleSignIn` package initialization entirely:
```dart
import 'package:flutter/foundation.dart' show kIsWeb;
- **Common Workaround**: If you intend to use Firebase Auth's
`signInWithPopup(GoogleAuthProvider())` for the web, you can conditionally
skip the local `GoogleSignIn` package initialization entirely:

if (!kIsWeb) {
```dart
import 'package:flutter/foundation.dart' show kIsWeb;

if (!kIsWeb) {
await GoogleSignIn.instance.initialize();
}
```
}
```

## 3. Web Logout Crashes

Expand All @@ -42,14 +43,15 @@ platform-specific quirks.
`await GoogleSignIn.instance.signOut();` during the user's logout flow on the
Web platform evaluates against an uninitialized context or unsupported
environment, crashing the app.
- **Solution**: Conditionally separate the logout logic for Web to rely entirely
on `FirebaseAuth`:
```dart
if (!kIsWeb) {
- **Solution**: Conditionally separate the logout logic for Web to rely
entirely on `FirebaseAuth`:

```dart
if (!kIsWeb) {
await GoogleSignIn.instance.signOut();
}
await FirebaseAuth.instance.signOut();
```
}
await FirebaseAuth.instance.signOut();
```

## 4. Prototyping Workaround: Bypassing Firestore Composite Indices

Expand Down Expand Up @@ -99,19 +101,17 @@ class AuthService {
return await _auth.signInWithPopup(authProvider);
} else {
// Mobile uses standard flow
final GoogleSignInAccount? googleUser = await GoogleSignIn.instance.authenticate();
if (googleUser == null) return null; // Cancelled
final GoogleSignInAccount googleUser = await GoogleSignIn.instance.authenticate();
final GoogleSignInAuthentication googleAuth = googleUser.authentication;

final GoogleSignInAuthentication googleAuth = await googleUser.authentication;

final AuthCredential credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
);

return await _auth.signInWithCredential(credential);
}
} catch (e) {
print("Error during Google Sign-In: \$e");
print("Error during Google Sign-In: $e");
return null;
}
}
Expand All @@ -124,7 +124,7 @@ class AuthService {
}
await _auth.signOut();
} catch (e) {
print("Error signing out: \$e");
print("Error signing out: $e");
}
}
}
Expand All @@ -140,9 +140,8 @@ closes.
`Sign-in failed: [firebase_auth/unauthorized-domain] This domain is not authorized for OAuth operation for your Firebase project.`
- **Cause**: The domain (usually `localhost` during local testing) is not listed
in the Authorized Domains in the Firebase Console.
- **Solution**: Add `localhost` to the Authorized Domains list in the Firebase
Console (Authentication > Settings > Authorized domains) or in your
`firebase.json` auth config.
- **Solution**: Add `localhost` to the Authorized Domains list in the Firebase
Console (Authentication > Settings > Authorized domains).
- **CRITICAL**: Do NOT include the protocol or port number when adding the
domain (e.g., use `localhost`, NOT `http://localhost:9090`). Flutter Web often
runs on random ports or specific ports, but Firebase Auth only cares about the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Authentication in Security Rules

Firebase Security Rules work with Firebase Authentication to provide rule-based
access control. For better advice on writing safe security rules, enable the
`firebase-firestore-basics` or `firebase-storage-basics` skills.
access control. For Firestore Security Rules (`firestore.rules`), delegate to the
`firestore-rules-author` subagent if subagent delegation is available, or
see the `firestore-rules-creation` skill otherwise. For Cloud Storage rules,
enable the `firebase-storage-basics` skill.

The `request.auth` variable contains authentication information for the user
requesting data.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ generate:
package: "com.example.dataconnect"
swiftSdk:
outputDir: "../ios-app/DataConnect"
package: "DataConnectGenerated"
```

Generate SDKs:
Expand Down Expand Up @@ -175,7 +176,7 @@ Follow these patterns based on your current task:
`npx -y firebase-tools@latest emulators:start --only dataconnect`.
1. Write schema and operations.
1. Seed local test data into `seed_data.gql`. Read
[reference/data_seeding.md](reference/data_seeding.md#local-prototyping-data-seeding).
[reference/data_seeding.md](reference/data_seeding.md#1-local-prototyping-data-seeding).
1. Run `npx -y firebase-tools@latest dataconnect:compile` or
`npx -y firebase-tools@latest dataconnect:sdk:generate` to validate them.
1. Use the operations in your app and build it.
Expand Down
Loading
Loading