fireemu 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +375 -72
- package/bin/fireemu.mjs +9 -4
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,122 +1,425 @@
|
|
|
1
|
+
<!-- Generated from README.md by npm/scripts/prepare-launcher.mjs at pack time. Edit README.md in the repository, not this file. -->
|
|
2
|
+
|
|
1
3
|
# Fireemu
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
Fireemu is a local emulator for testing applications built with Firebase. It aims to match production Firebase behavior as closely as possible, so you can test locally and in CI without using a real Firebase project.
|
|
6
|
+
|
|
7
|
+
Passing tests against the official emulator does not always mean your application will behave the same way in production. Some features are not supported by the official emulator, and some execution conditions are difficult to reproduce locally. These gaps can leave you relying on a real Firebase project for part of your testing.
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
Fireemu is being developed to close these gaps. For example, it provides:
|
|
6
10
|
|
|
7
|
-
Fireemu
|
|
11
|
+
- **Validation of configuration required in production:** Fireemu detects issues that the official emulator misses, such as missing Firestore index definitions.
|
|
12
|
+
- **Support for features not available in the official emulator:** Fireemu also supports features such as TOTP-based multi-factor authentication.
|
|
13
|
+
- **Control over test execution conditions:** You can set an arbitrary time and run scheduled functions to verify their behavior without waiting for the actual scheduled time.
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
- keep local test runs fast, with no JVM emulator to start and a single command that starts the services, runs the test command, and shuts everything down.
|
|
15
|
+
Fireemu is still in development and does not yet reproduce every feature and behavior of production Firebase. Before relying on Fireemu’s test results in CI or other automated workflows, we recommend differential testing against production Firebase services for the features and critical workflows your application uses. Run the same tests against Fireemu and a dedicated Firebase test project, and check for differences in results and behavior that could affect your application. Use a dedicated test project, not your live production project.
|
|
11
16
|
|
|
12
|
-
|
|
17
|
+
See the [capability manifest](https://github.com/t-k/fireemu/blob/v0.10.0/crates/fireemu/src/capabilities.json) and [compatibility documentation](https://github.com/t-k/fireemu/blob/v0.10.0/docs/compatibility-contract.md) for supported features, known differences, and the status of compatibility verification.
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
## Quick start
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
Node.js 20 or newer is required.
|
|
17
22
|
|
|
18
23
|
```sh
|
|
19
|
-
npm install -
|
|
24
|
+
npm install --save-dev fireemu
|
|
20
25
|
npx fireemu init
|
|
21
|
-
|
|
26
|
+
|
|
27
|
+
# Start the emulator
|
|
28
|
+
# UI (default): http://127.0.0.1:4000
|
|
29
|
+
npx fireemu up
|
|
22
30
|
```
|
|
23
31
|
|
|
32
|
+
Open the UI in your browser to inspect and manage data. Press `Ctrl+C` to stop the emulator.
|
|
33
|
+
|
|
34
|
+
To run the emulator only for the duration of a command, use `exec` instead of `up`.
|
|
35
|
+
|
|
24
36
|
```sh
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
# Start the emulator, run a command, and stop when the command exits
|
|
38
|
+
npx fireemu exec -- <command>
|
|
39
|
+
|
|
40
|
+
# Example: run tests
|
|
41
|
+
npx fireemu exec -- npm test
|
|
27
42
|
```
|
|
28
43
|
|
|
29
|
-
|
|
30
|
-
launcher; the daemon for your platform arrives as an optional dependency
|
|
31
|
-
(`@fireemu/darwin-arm64` and friends), so npm installs exactly one binary and skips the rest.
|
|
32
|
-
An install that resolved from a cache or a private registry is a complete, offline installation.
|
|
44
|
+
### Supported platforms
|
|
33
45
|
|
|
34
|
-
|
|
46
|
+
| OS | Architecture |
|
|
47
|
+
|---|---|
|
|
48
|
+
| macOS 13 or newer | Apple silicon, Intel |
|
|
49
|
+
| Linux | x86-64, arm64 |
|
|
50
|
+
| Windows 10 or newer | x86-64 |
|
|
35
51
|
|
|
36
|
-
|
|
52
|
+
Running Functions requires `firebase-functions` v6 or v7 in the codebase.
|
|
37
53
|
|
|
38
|
-
|
|
54
|
+
## Supported scope
|
|
55
|
+
|
|
56
|
+
Fireemu supports Cloud Firestore, Firebase Authentication (Identity Platform), Cloud Storage for Firebase, Cloud Functions for Firebase, Cloud Pub/Sub, and Eventarc. It also provides a local Firebase App Check implementation and a UI for managing data and viewing logs.
|
|
57
|
+
|
|
58
|
+
### Key unsupported features and limitations
|
|
59
|
+
|
|
60
|
+
| Product | Key unsupported features and limitations |
|
|
61
|
+
|---|---|
|
|
62
|
+
| Cloud Firestore | The Enterprise Pipeline API supports a limited subset of read operations. Full-text search supports index definition validation, but local search execution is not supported. |
|
|
63
|
+
| Firebase Authentication (Identity Platform) | Authentication flows that communicate with external identity providers, authorization-code exchange, and SAML XML signature verification are outside the supported scope. These are separate from local authentication behavior and provider configuration. |
|
|
64
|
+
| Cloud Storage for Firebase | Object versioning, signed URLs, ACL-based access control, object composition (`compose`), and notification configuration are not supported. |
|
|
65
|
+
| Cloud Functions for Firebase | Triggers that depend on unsupported products, such as Realtime Database (deferred), Remote Config, and Data Connect (deferred), cannot run. Storage archive events do not occur because object versioning is not supported. |
|
|
66
|
+
| Cloud Pub/Sub | Schemas, BigQuery and Cloud Storage subscription delivery, and some APIs such as `UpdateTopic` are not supported. |
|
|
67
|
+
| Firebase App Check | Local testing with debug tokens is supported. Real attestation through Play Integrity, App Attest, DeviceCheck, or reCAPTCHA, and replay protection using limited-use tokens, are not supported. |
|
|
68
|
+
|
|
69
|
+
This table highlights key limitations; it is not exhaustive. Check individual API support and conditions with the following command or the [capability manifest](https://github.com/t-k/fireemu/blob/v0.10.0/crates/fireemu/src/capabilities.json).
|
|
39
70
|
|
|
40
71
|
```sh
|
|
41
|
-
npx fireemu
|
|
42
|
-
|
|
72
|
+
npx fireemu capabilities
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
See the [Functions support inventory](https://github.com/t-k/fireemu/blob/v0.10.0/docs/functions-export-inventory.md) for support by trigger type.
|
|
76
|
+
|
|
77
|
+
### Unsupported products
|
|
78
|
+
|
|
79
|
+
Realtime Database, Firebase Hosting, App Hosting, and Data Connect are not currently supported. Firebase Extensions support is not planned.
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
### Select services
|
|
84
|
+
|
|
85
|
+
Use `--only` to select the services to start.
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
# Start only Firebase Authentication (Identity Platform), Firestore, and Storage
|
|
89
|
+
npx fireemu up --only auth,firestore,storage
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
You can also select an individual Functions codebase.
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
npx fireemu up --only functions:<codebase>
|
|
43
96
|
```
|
|
44
97
|
|
|
45
|
-
|
|
98
|
+
### Run a command
|
|
99
|
+
|
|
100
|
+
Service selection also works with `exec`.
|
|
46
101
|
|
|
47
102
|
```sh
|
|
48
|
-
npx fireemu
|
|
103
|
+
npx fireemu exec --only auth,firestore,storage -- npm test
|
|
49
104
|
```
|
|
50
105
|
|
|
51
|
-
`exec`
|
|
52
|
-
|
|
53
|
-
|
|
106
|
+
`exec` sets the Firebase SDK emulator host environment variables for the child command and returns its exit status. SIGINT and SIGTERM are forwarded to the child command.
|
|
107
|
+
|
|
108
|
+
The official CLI command names are also available as aliases.
|
|
54
109
|
|
|
55
110
|
```sh
|
|
56
|
-
npx fireemu
|
|
111
|
+
npx fireemu emulators:start
|
|
112
|
+
npx fireemu emulators:exec -- npm test
|
|
57
113
|
```
|
|
58
114
|
|
|
59
|
-
|
|
60
|
-
`FIREBASE_STORAGE_EMULATOR_HOST` / `STORAGE_EMULATOR_HOST`, `GOOGLE_CLOUD_PROJECT` /
|
|
61
|
-
`GCLOUD_PROJECT`, and `FIREEMU_CONTROL_TOKEN` / `FIREEMU_CONTROL_URL` for the control API.
|
|
115
|
+
### UI
|
|
62
116
|
|
|
63
|
-
|
|
64
|
-
(`--ui-port 0` turns it off).
|
|
117
|
+
The default UI address is `http://127.0.0.1:4000`. Use `--ui-port` to specify a port.
|
|
65
118
|
|
|
66
|
-
|
|
119
|
+
```sh
|
|
120
|
+
# Start the UI on port 4001
|
|
121
|
+
npx fireemu up --ui-port 4001
|
|
122
|
+
```
|
|
67
123
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
| `@fireemu/linux-arm64` | Linux (any libc) | arm64 | `aarch64-unknown-linux-musl`, static |
|
|
74
|
-
| `@fireemu/win32-x64` | Windows 10+ | x86-64 | `x86_64-pc-windows-msvc` |
|
|
124
|
+
`exec` does not start the UI by default. Add `--ui` to use it while the command runs.
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
npx fireemu exec --ui -- npm test
|
|
128
|
+
```
|
|
75
129
|
|
|
76
|
-
|
|
77
|
-
distroless and Alpine containers.
|
|
130
|
+
Use `--ui-port 0` to disable the UI. When automatic UI startup cannot bind the default port, the emulator starts without the UI. Check the startup output if the UI is unavailable.
|
|
78
131
|
|
|
79
|
-
|
|
132
|
+
When a Functions codebase is loaded, the Functions page shows registered functions, triggers, invocation results, and logs. You can run scheduled functions immediately or advance the virtual clock to their next scheduled execution.
|
|
80
133
|
|
|
81
|
-
|
|
82
|
-
Node; Firestore, Auth, Storage and the UI are served by the binary itself.
|
|
83
|
-
- **No Java.** Unlike the Firebase Emulator Suite, `fireemu` runs no JVM emulator.
|
|
84
|
-
- For `--functions <dir>`: the codebase's own `node_modules`, with `firebase-functions` v6 or v7
|
|
85
|
-
and `firebase-admin`. `npx fireemu doctor` prints the range the bundled runner supports.
|
|
134
|
+
### Export data
|
|
86
135
|
|
|
87
|
-
|
|
136
|
+
To save data from a running emulator, run the following command in another terminal.
|
|
137
|
+
|
|
138
|
+
```sh
|
|
139
|
+
npx fireemu emulators:export ./emulator-data
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
On Windows, `emulators:export` and `--export-on-exit` are not currently available. Import and other emulator functionality remain available.
|
|
143
|
+
|
|
144
|
+
On Unix-like systems, the destination and its ancestor directories are subject to ownership and permission restrictions. Use a dedicated, non-shared directory rather than `/tmp` or a shared directory.
|
|
145
|
+
|
|
146
|
+
### Troubleshooting
|
|
147
|
+
|
|
148
|
+
For startup or installation problems, inspect the environment and bundled files with:
|
|
88
149
|
|
|
89
150
|
```sh
|
|
90
151
|
npx fireemu doctor
|
|
91
152
|
```
|
|
92
153
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
154
|
+
The command reports information about the Fireemu binary, UI, Functions runner, and Node.js, and suggests remedies when it finds missing components or problems.
|
|
155
|
+
|
|
156
|
+
## Configuration
|
|
157
|
+
|
|
158
|
+
### Initial setup and reusing `firebase.json`
|
|
159
|
+
|
|
160
|
+
`fireemu init` creates `fireemu.json` in the current directory. The interactive setup lets you choose a compatibility profile and whether to reuse an existing `firebase.json`.
|
|
161
|
+
|
|
162
|
+
When reusing `firebase.json`, Fireemu references the file rather than copying its settings. Rules, indexes, Functions codebases, and emulator ports are read from it each time Fireemu starts.
|
|
163
|
+
|
|
164
|
+
Use the non-interactive form for CI or scripted setup.
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
npx fireemu init --yes
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
An existing `fireemu.json` is not overwritten unless `--force` is supplied.
|
|
171
|
+
|
|
172
|
+
### Compatibility profiles
|
|
173
|
+
|
|
174
|
+
| Profile | Behavior |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `strict` | Matches production Firebase behavior and constraints as closely as possible within the supported scope. This is the default profile |
|
|
177
|
+
| `emulator` | Targets the behavior of a pinned version of the official emulator. Known differences are documented in the compatibility documentation |
|
|
178
|
+
|
|
179
|
+
Use `strict` when testing against production Firebase behavior. Add `emulator` to your test targets when you also need to check alignment with the official emulator.
|
|
180
|
+
|
|
181
|
+
Under the `emulator` profile, a request that names a tenant the project does not have creates that tenant, and the number of tenants is not limited, as in the official emulator. The `strict` profile refuses such a request, as production does. A request that Fireemu refuses (a wrong credential, a browser page without the control token on the emulator routes, App Check, an unknown API key) creates nothing. As in the official emulator, a plain `GET` without an `Origin` header to a tenant route of `127.0.0.1` creates the tenant, so any web page you visit while the emulator runs can add tenants to it (not read them); use the `strict` profile where that matters.
|
|
182
|
+
|
|
183
|
+
### Basic configuration
|
|
184
|
+
|
|
185
|
+
The initial configuration selects Standard edition Firestore with the Native API.
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"$schema": "https://fireemu.dev/spec/config/fireemu.schema.json",
|
|
190
|
+
"schemaVersion": 1,
|
|
191
|
+
"profile": "strict",
|
|
192
|
+
"firestore": {
|
|
193
|
+
"edition": "standard",
|
|
194
|
+
"apiMode": "native"
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
You can specify the configuration file with `--config`.
|
|
200
|
+
|
|
201
|
+
```sh
|
|
202
|
+
npx fireemu up --config ./fireemu.json
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Keep Fireemu-specific settings in a Fireemu configuration file containing `"schemaVersion": 1`, rather than in `firebase.json`. See the [configuration schema](https://github.com/t-k/fireemu/blob/v0.10.0/spec/config/fireemu.schema.json) for all available settings.
|
|
206
|
+
|
|
207
|
+
### Firebase Authentication (Identity Platform) configuration
|
|
208
|
+
|
|
209
|
+
The `auth` section of `fireemu.json` lets you configure sign-in methods, password policies, account permissions, and other authentication settings. Match your application’s configuration to test registration, sign-in, and account management behavior.
|
|
210
|
+
|
|
211
|
+
| What you can configure | Main settings |
|
|
212
|
+
|---|---|
|
|
213
|
+
| Enable or disable email/password, anonymous, and phone sign-in | `auth.signIn` |
|
|
214
|
+
| Test phone numbers and verification codes | `auth.signIn.phoneNumber.testPhoneNumbers` |
|
|
215
|
+
| Initial authorized domains for action-link continue URLs | `auth.authorizedDomains` |
|
|
216
|
+
| Handling of accounts that share an email address | `auth.signIn.allowDuplicateEmails` |
|
|
217
|
+
| Password length and character requirements, and policy enforcement at sign-in | `auth.passwordPolicy` |
|
|
218
|
+
| TOTP-based multi-factor authentication | `auth.totp` |
|
|
219
|
+
| Initial multi-factor authentication (MFA) configuration of a project, such as enabling TOTP under the `strict` profile | `auth.mfa` |
|
|
220
|
+
| Tenants that exist when the daemon starts, and the multi-tenancy switch | `auth.tenants`, `auth.multiTenant` |
|
|
221
|
+
| Restrictions on end-user account creation and deletion | `auth.client.permissions` |
|
|
222
|
+
| Email enumeration protection | `auth.improvedEmailPrivacy` |
|
|
223
|
+
| Project- and tenant-specific password policies and account permissions | `auth.passwordPolicyOverrides`, `auth.configOverrides` |
|
|
224
|
+
| Blocking functions before account creation or sign-in, and credential forwarding to those functions | `auth.blockingFunctions` |
|
|
225
|
+
| Initial custom OIDC and SAML provider resources | `auth.providers.oidc`, `auth.providers.saml` |
|
|
226
|
+
| Public keys for verifying custom tokens and OIDC ID tokens | `auth.customTokenSigners`, `auth.idpSigners` |
|
|
227
|
+
| Sign-up quota configuration and local quota-exceeded simulation | `auth.quota`, `auth.quotaSimulation` |
|
|
228
|
+
|
|
229
|
+
See the [configuration schema](https://github.com/t-k/fireemu/blob/v0.10.0/spec/config/fireemu.schema.json) for the format and accepted values of each setting.
|
|
230
|
+
|
|
231
|
+
Declare `auth.authorizedDomains`, for example `["localhost", "app.test"]`, to set the initial project-wide list in either profile. The list replaces the defaults, so include `localhost` if your tests use it. An empty list authorizes no host under `strict`; an absent or `null` setting keeps the existing defaults (`localhost` and the project's `firebaseapp.com` and `web.app` domains). Validation uses the Admin API's rules for the selected profile, including its conversion of numeric and boolean entries to strings and omission of `null` entries; use strings when writing the list. Fireemu intentionally keeps `localhost` in its defaults for development. The [recorded production sandbox baseline](https://github.com/t-k/fireemu/blob/v0.10.0/conformance/auth-action-production.json) does not include it; new production projects may also omit it. This default is a Fireemu-only convenience, and declaring the list replaces it. Tenant-scoped strict action links currently check the tenant's default domains rather than this project declaration; support for the parent project's live list is pending.
|
|
232
|
+
|
|
233
|
+
An Admin update changes the live list. A session reset restores the declared list, when present, and preserves an Admin-written list when no initial list was declared. Projects created later receive the declaration word for word, independently of the default project's live list; listing a particular project's `firebaseapp.com` or `web.app` domain therefore gives later projects that same domain. Clearing accounts leaves the live list alone. Auth export/import carries accounts without the domain list or its declaration. The `emulator` profile accepts the setting and exposes the list, while continuing to allow action-link continue URLs outside it.
|
|
234
|
+
|
|
235
|
+
Declare project OIDC and SAML resources with `auth.providers.oidc` and `auth.providers.saml`, using the Admin v2 resource fields and an ID-only `name` such as `oidc.fixture` or `saml.fixture`. Full resource names are refused. For example, `"providers": {"oidc": [{"name": "oidc.fixture", "enabled": true, "clientId": "local-client", "issuer": "https://issuer.test", "responseType": {"idToken": true}}]}` initializes that provider in both profiles. Strict OIDC sign-in also needs matching public issuer keys in `auth.idpSigners`; no key is fetched. Strict SAML uses the declared provider certificates and retains its existing assertion checks.
|
|
236
|
+
|
|
237
|
+
Each declared array replaces that provider kind; `[]` explicitly starts it empty, while an absent or `null` kind declares no initial resources. Admin operations change live resources until a session reset restores the declared kinds. Later session and routed projects inherit the declaration independently of the default project's live changes. Tenant resources and built-in providers remain separate. Clearing accounts preserves live resources; snapshots and Auth export/import transfer no provider resources or declarations. The emulator profile continues to accept its unsigned fixture credentials without requiring configured or enabled provider resources. These declarations require a canonical document with `"schemaVersion": 1`; a Firebase deployment `auth.providers` section without that version remains deployment data and installs no provider seeds.
|
|
238
|
+
|
|
239
|
+
#### Example configuration
|
|
240
|
+
|
|
241
|
+
This example enables email/password and phone sign-in while disabling anonymous sign-in. It requires passwords of at least 12 characters containing uppercase letters, lowercase letters, and numbers, and prevents users from deleting their own accounts. Phone sign-in uses a configured test phone number and verification code.
|
|
242
|
+
|
|
243
|
+
```json
|
|
244
|
+
{
|
|
245
|
+
"$schema": "https://fireemu.dev/spec/config/fireemu.schema.json",
|
|
246
|
+
"schemaVersion": 1,
|
|
247
|
+
"profile": "strict",
|
|
248
|
+
"firestore": {
|
|
249
|
+
"edition": "standard",
|
|
250
|
+
"apiMode": "native"
|
|
251
|
+
},
|
|
252
|
+
"auth": {
|
|
253
|
+
"signIn": {
|
|
254
|
+
"allowDuplicateEmails": false,
|
|
255
|
+
"email": {
|
|
256
|
+
"enabled": true,
|
|
257
|
+
"passwordRequired": true
|
|
258
|
+
},
|
|
259
|
+
"anonymous": {
|
|
260
|
+
"enabled": false
|
|
261
|
+
},
|
|
262
|
+
"phoneNumber": {
|
|
263
|
+
"enabled": true,
|
|
264
|
+
"testPhoneNumbers": {
|
|
265
|
+
"+16505550101": "123456"
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"passwordPolicy": {
|
|
270
|
+
"enforcementState": "ENFORCE",
|
|
271
|
+
"forceUpgradeOnSignin": true,
|
|
272
|
+
"constraints": {
|
|
273
|
+
"minLength": 12,
|
|
274
|
+
"requireUppercase": true,
|
|
275
|
+
"requireLowercase": true,
|
|
276
|
+
"requireNumeric": true
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
"client": {
|
|
280
|
+
"permissions": {
|
|
281
|
+
"disabledUserSignup": false,
|
|
282
|
+
"disabledUserDeletion": true
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
"improvedEmailPrivacy": true
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
For an existing `fireemu.json`, add the settings you need to its `auth` section. Adjust the values to match your application’s requirements.
|
|
291
|
+
|
|
292
|
+
#### Project- and tenant-specific settings
|
|
293
|
+
|
|
294
|
+
Use `auth.passwordPolicyOverrides` to specify different password policies for individual projects or tenants. Use `auth.configOverrides` to customize account creation and deletion permissions and email enumeration protection.
|
|
295
|
+
|
|
296
|
+
These settings are separate from creating the project or tenant. Naming a tenant in `auth.configOverrides` or `auth.passwordPolicyOverrides` does not create it (declare it in `auth.tenants` to have it created).
|
|
297
|
+
|
|
298
|
+
#### Enable multi-factor authentication at start
|
|
299
|
+
|
|
300
|
+
Under the `strict` profile, TOTP is enabled only through the project's MFA configuration, as in production, so `auth.totp` alone enables nothing there. Use `auth.mfa` to declare that configuration in the file instead of calling the Admin API in every session. It has the shape Identity Platform uses (`state`, `enabledProviders`, and `providerConfigs` with `totpProviderConfig.adjacentIntervals`):
|
|
301
|
+
|
|
302
|
+
```json
|
|
303
|
+
{
|
|
304
|
+
"schemaVersion": 1,
|
|
305
|
+
"profile": "strict",
|
|
306
|
+
"auth": {
|
|
307
|
+
"mfa": {
|
|
308
|
+
"state": "ENABLED",
|
|
309
|
+
"providerConfigs": [
|
|
310
|
+
{ "state": "ENABLED", "totpProviderConfig": { "adjacentIntervals": 1 } }
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
- The configuration applies when the daemon starts, in both profiles, and to every project created afterward (not the default project's current value). It is validated as the Admin API validates an update of `mfa`, and a value production would refuse stops the daemon at startup.
|
|
318
|
+
- Nothing else changes. An Admin API update replaces the current configuration, and disabling MFA refuses TOTP as production does. A tenant follows its own `mfaConfig`, not this setting.
|
|
319
|
+
- `POST /v1/sessions/{session}/reset` returns the project to the declared configuration. Without `auth.mfa`, a reset leaves a configuration set through the Admin API alone, as it does the rest of the project configuration. `DELETE /emulator/v1/projects/{project}/accounts` clears accounts only.
|
|
320
|
+
- An export does not carry the project's `mfa` configuration, so an imported project keeps its own `auth.mfa` or Admin-set configuration.
|
|
321
|
+
- The `emulator` profile keeps `auth.totp` working. Under `strict`, `auth.totp` without an `auth.mfa` that enables TOTP prints a startup warning naming `auth.mfa`.
|
|
322
|
+
|
|
323
|
+
#### Enable multi-tenancy
|
|
324
|
+
|
|
325
|
+
Under the `strict` profile, enable `multiTenant.allowTenants` before using multi-tenancy: through the Admin API, or with `auth.multiTenant` in the file (see "Start with tenants" below). See the [compatibility documentation](https://github.com/t-k/fireemu/blob/v0.10.0/docs/compatibility-contract.md) for the supported Admin API scope.
|
|
326
|
+
|
|
327
|
+
#### Start with tenants
|
|
328
|
+
|
|
329
|
+
Instead of creating tenants through the Admin API in every session, declare the default project's tenants and the multi-tenancy switch in the file. Each entry of `auth.tenants` is an Admin v2 `Tenant` document plus its `tenantId`, which has the form production generates, the display name, a hyphen, and five characters of `a-z0-9`:
|
|
330
|
+
|
|
331
|
+
```json
|
|
332
|
+
{
|
|
333
|
+
"schemaVersion": 1,
|
|
334
|
+
"profile": "strict",
|
|
335
|
+
"auth": {
|
|
336
|
+
"multiTenant": { "allowTenants": true },
|
|
337
|
+
"tenants": [
|
|
338
|
+
{
|
|
339
|
+
"tenantId": "acme-x7k2q",
|
|
340
|
+
"displayName": "acme",
|
|
341
|
+
"allowPasswordSignup": true,
|
|
342
|
+
"mfaConfig": { "state": "ENABLED", "enabledProviders": ["PHONE_SMS"] }
|
|
343
|
+
}
|
|
344
|
+
]
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
- A document is read by the code the Admin tenant create route reads one with, so a value production refuses stops the daemon at startup. The tenants are created empty, in file order, and settings such as `mfaConfig` and `passwordPolicyConfig` come from the document. The file is stricter than the route in the `emulator` profile: it also refuses an unknown member and a missing or invalid `displayName`, as production does.
|
|
350
|
+
- A declared tenant has what an Admin create with that document gives: an omitted `allowPasswordSignup`, `enableEmailLinkSignin` or `enableAnonymousUser` is off and multi-factor is off. A tenant the `emulator` profile creates on the way for a request that names an unknown id gets the official emulator's defaults instead (all three on, `PHONE_SMS` multi-factor), so declare what your test needs.
|
|
351
|
+
- Under the `strict` profile tenants are created only in a project that allows them, as in production, so `auth.tenants` needs `auth.multiTenant.allowTenants: true` (the daemon refuses to start otherwise). The `emulator` profile takes tenants without the switch.
|
|
352
|
+
- The default project and every session project (`POST /v1/sessions`) start with the declared switch and tenants. `POST /v1/sessions/{session}/reset` (the default session's included) creates them again, empty, and returns the switch to the declared value; without these keys a reset leaves an Admin-set switch alone. A namespace the `emulator` profile creates for an unknown project id (as the official emulator does) starts with the declared switch and tenants too: it is created by the requests that already created one (a user, a provider or a project setting written there) and by a request that writes a tenant there (creating one, or naming one that does not exist yet), not by a read alone. A session created for that project id (`POST /v1/sessions`) replaces the namespace, tenants included, and starts with the declared ones.
|
|
353
|
+
- With `--import`, an imported tenant is authoritative for its id, and a declared tenant the import did not carry is still created. If you keep re-importing your own export (`--import dir --export-on-exit dir`), an edit to a declared tenant is therefore ignored once its exported copy exists: the daemon prints a warning naming the tenant when the imported tenant's document differs from the declared one (every setting the file can declare is compared). The switch is the other way round: a declared `allowTenants` wins over the import. After a reset the declared version of a tenant comes back, not the imported one.
|
|
354
|
+
|
|
355
|
+
#### Test quota-exceeded behavior
|
|
356
|
+
|
|
357
|
+
Use `auth.quotaSimulation` to test sign-up quota-exceeded behavior locally. For example, set `auth.quotaSimulation` to:
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"mode": "enforce",
|
|
362
|
+
"defaultQuotaPerHour": 5
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
This is a local fixed-window simulation. It does not reproduce Firebase’s full quota accounting or abuse-prevention systems.
|
|
367
|
+
|
|
368
|
+
### Configure execution time
|
|
369
|
+
|
|
370
|
+
Set the emulator’s starting time with `daemon.clockStart`. Configure the clock, time zone, and other scheduling behavior in the `scheduler` section. This lets you test scheduled functions independently of the actual time.
|
|
371
|
+
|
|
372
|
+
See the [configuration schema](https://github.com/t-k/fireemu/blob/v0.10.0/spec/config/fireemu.schema.json) for available settings and values.
|
|
373
|
+
|
|
374
|
+
## Compatibility and limitations
|
|
375
|
+
|
|
376
|
+
### Differences from production Firebase
|
|
377
|
+
|
|
378
|
+
Fireemu aims to match production Firebase behavior, but a successful local operation does not guarantee the same result in production.
|
|
379
|
+
|
|
380
|
+
The local runtime does not reproduce real quota accounting, billing, IAM, organization policies, regional or network differences, or service rollouts. Local performance measurements also do not predict production latency or throughput.
|
|
381
|
+
|
|
382
|
+
Security Rules and API behavior are implemented using documentation and observations of Firebase’s actual behavior. Changes in Firebase or untested conditions may introduce differences that have not yet been recorded.
|
|
383
|
+
|
|
384
|
+
### Comparison with the official emulator
|
|
385
|
+
|
|
386
|
+
The official emulator comparison baseline is `firebase-tools 15.28.2`.
|
|
387
|
+
|
|
388
|
+
Fireemu is compatible with the listed Local Emulator Suite products as shipped by firebase-tools 15.28.2 -- Cloud Firestore, Firebase Authentication, Cloud Storage for Firebase, Cloud Functions, Cloud Pub/Sub and Eventarc, with Security Rules on the Firestore and Storage surfaces -- under the `emulator` compatibility profile and the evidence recorded in `spec/compatibility/contract.json`; it makes no complete-suite and no unqualified superset claim while Realtime Database, Firebase Hosting, App Hosting and Data Connect are deferred and Firebase Extensions is not planned.
|
|
389
|
+
|
|
390
|
+
The `strict` and `emulator` profiles differ in some behaviors to serve their respective purposes. Where the official emulator and production Firebase disagree, Fireemu also adopts production behavior in some cases and records the difference.
|
|
391
|
+
|
|
392
|
+
Check support for the specific APIs and conditions your application uses, rather than relying on product names alone. The [compatibility contract](https://github.com/t-k/fireemu/blob/v0.10.0/spec/compatibility/contract.json) records scope and known differences. The [compatibility documentation](https://github.com/t-k/fireemu/blob/v0.10.0/docs/compatibility-contract.md) explains the verification process and how to interpret its records.
|
|
393
|
+
|
|
394
|
+
### Changes between versions
|
|
395
|
+
|
|
396
|
+
Configuration and behavior may change between releases. See the [CHANGELOG](https://github.com/t-k/fireemu/blob/v0.10.0/CHANGELOG.md) for release changes.
|
|
397
|
+
|
|
398
|
+
## Performance
|
|
399
|
+
|
|
400
|
+
Fireemu is compared with the official Firestore emulator using the same SDK workloads. Both run sequentially on the same GitHub Actions Linux runner, with Fireemu using the `emulator` profile. The benchmark also validates operation results.
|
|
401
|
+
|
|
402
|
+
The following results come from one `standard` run at commit `f3b942c`. Ratios are calculated from five measured pairs; absolute values depend on the execution environment.
|
|
403
|
+
|
|
404
|
+
| Metric | Official emulator | Fireemu | Comparison |
|
|
405
|
+
|---|---:|---:|---:|
|
|
406
|
+
| Startup until the SDK can use Firestore | 3,043 ms | 140 ms | 21.6× faster |
|
|
407
|
+
| Idle memory with an empty database (PSS) | 390 MiB | 11 MiB | About 1/34 the memory |
|
|
408
|
+
| Peak memory during a trial (cgroup) | 849 MiB | 79 MiB | About 1/10.7 the memory |
|
|
409
|
+
| Firestore throughput across 22 workloads | — | — | 1.1× to 5.2× higher |
|
|
410
|
+
|
|
411
|
+
The 95% confidence interval for the startup-time ratio is `[21.4, 21.8]`. For the peak-memory ratio, calculated as official emulator divided by Fireemu, it is `[10.2, 11.1]`.
|
|
412
|
+
|
|
413
|
+
See [benchmark.yml](https://github.com/t-k/fireemu/blob/v0.10.0/.github/workflows/benchmark.yml) for the workflow and [`tools/bench/`](https://github.com/t-k/fireemu/tree/v0.10.0/tools/bench/) for the benchmark implementation.
|
|
98
414
|
|
|
99
|
-
##
|
|
415
|
+
## Reporting issues and contributing
|
|
100
416
|
|
|
101
|
-
|
|
102
|
-
own exact version, so `fireemu@1.2.3` can only resolve `@fireemu/linux-x64@1.2.3` -- an upgrade
|
|
103
|
-
moves the binary and the launcher together, never one without the other.
|
|
104
|
-
- **Uninstall**: `npm uninstall fireemu`. Nothing is installed outside `node_modules`: no cache
|
|
105
|
-
directory, no global binary, no downloaded component.
|
|
106
|
-
- **Offline**: `npm install --offline` works once the tarballs are in the npm cache, and so does
|
|
107
|
-
installing from a private registry that mirrors the `fireemu` and `@fireemu` packages. Warm a
|
|
108
|
-
cache with `npm install` on a machine of the same platform, or vendor the tarballs with
|
|
109
|
-
`npm pack`.
|
|
110
|
-
- **A vendored or self-built binary**: set `FIREEMU_BINARY_PATH` to it and the launcher runs that
|
|
111
|
-
instead of resolving a platform package.
|
|
112
|
-
- **If the binary is missing**: the launcher says which package it looked for and what is
|
|
113
|
-
published. The usual cause is an install that skipped optional dependencies
|
|
114
|
-
(`--omit=optional`, `--no-optional`, or a lockfile built on another platform).
|
|
417
|
+
When reporting an issue, include the Fireemu and Firebase SDK versions, the profile used, the Firebase product involved, and a minimal reproduction.
|
|
115
418
|
|
|
116
|
-
|
|
419
|
+
For compatibility issues, also state whether you are comparing against the actual Firebase service or the official emulator, along with the expected and actual results. Remove credentials and personal information before sharing configuration files or logs.
|
|
117
420
|
|
|
118
|
-
|
|
421
|
+
See the [development guide](https://github.com/t-k/fireemu/blob/v0.10.0/docs/development.md) for build and test instructions.
|
|
119
422
|
|
|
120
423
|
## License
|
|
121
424
|
|
|
122
|
-
Apache
|
|
425
|
+
Fireemu is licensed under the [Apache License 2.0](https://github.com/t-k/fireemu/blob/v0.10.0/LICENSE). Third-party notices are listed in [THIRD_PARTY_LICENSES.txt](https://github.com/t-k/fireemu/blob/v0.10.0/THIRD_PARTY_LICENSES.txt).
|
package/bin/fireemu.mjs
CHANGED
|
@@ -116,10 +116,11 @@ function main() {
|
|
|
116
116
|
ensureExecutable(binary.path);
|
|
117
117
|
// Keep terminal I/O and the foreground process group intact. PID-directed signals only
|
|
118
118
|
// reach this launcher, so forward them and wait for the daemon's own shutdown to finish.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
//
|
|
120
|
+
// The handlers are registered before the daemon is spawned: a signal that reached the launcher
|
|
121
|
+
// between spawn() and process.on() would kill it with the default action and orphan the daemon.
|
|
122
|
+
// Node runs a handler on the event loop, after main() has returned, so `child` exists by then.
|
|
123
|
+
let child;
|
|
123
124
|
for (const signal of ["SIGTERM", "SIGINT"]) {
|
|
124
125
|
process.on(signal, () => {
|
|
125
126
|
// Windows delivers console Ctrl-C to the child directly; child.kill would forcefully
|
|
@@ -129,6 +130,10 @@ function main() {
|
|
|
129
130
|
if (child.exitCode === null && child.signalCode === null) child.kill(signal);
|
|
130
131
|
});
|
|
131
132
|
}
|
|
133
|
+
child = spawn(binary.path, process.argv.slice(2), {
|
|
134
|
+
stdio: "inherit",
|
|
135
|
+
windowsHide: false,
|
|
136
|
+
});
|
|
132
137
|
child.on("error", (error) => {
|
|
133
138
|
if (child.pid) {
|
|
134
139
|
// A failed signal delivery must not orphan a daemon that is still running.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fireemu",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "A local runtime for testing Firebase SDK and Functions code, checked against production Firebase behavior",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"emulator",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
],
|
|
28
28
|
"type": "module",
|
|
29
29
|
"optionalDependencies": {
|
|
30
|
-
"@fireemu/darwin-arm64": "0.
|
|
31
|
-
"@fireemu/darwin-x64": "0.
|
|
32
|
-
"@fireemu/linux-x64": "0.
|
|
33
|
-
"@fireemu/linux-arm64": "0.
|
|
34
|
-
"@fireemu/win32-x64": "0.
|
|
30
|
+
"@fireemu/darwin-arm64": "0.10.0",
|
|
31
|
+
"@fireemu/darwin-x64": "0.10.0",
|
|
32
|
+
"@fireemu/linux-x64": "0.10.0",
|
|
33
|
+
"@fireemu/linux-arm64": "0.10.0",
|
|
34
|
+
"@fireemu/win32-x64": "0.10.0"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=20"
|