fireemu 0.10.0 → 0.11.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 +82 -14
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Fireemu is being developed to close these gaps. For example, it provides:
|
|
|
14
14
|
|
|
15
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.
|
|
16
16
|
|
|
17
|
-
See the [capability manifest](https://github.com/t-k/fireemu/blob/v0.
|
|
17
|
+
See the [capability manifest](https://github.com/t-k/fireemu/blob/v0.11.0/crates/fireemu/src/capabilities.json) and [compatibility documentation](https://github.com/t-k/fireemu/blob/v0.11.0/docs/compatibility-contract.md) for supported features, known differences, and the status of compatibility verification.
|
|
18
18
|
|
|
19
19
|
## Quick start
|
|
20
20
|
|
|
@@ -66,13 +66,13 @@ Fireemu supports Cloud Firestore, Firebase Authentication (Identity Platform), C
|
|
|
66
66
|
| Cloud Pub/Sub | Schemas, BigQuery and Cloud Storage subscription delivery, and some APIs such as `UpdateTopic` are not supported. |
|
|
67
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
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.
|
|
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.11.0/crates/fireemu/src/capabilities.json).
|
|
70
70
|
|
|
71
71
|
```sh
|
|
72
72
|
npx fireemu capabilities
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
See the [Functions support inventory](https://github.com/t-k/fireemu/blob/v0.
|
|
75
|
+
See the [Functions support inventory](https://github.com/t-k/fireemu/blob/v0.11.0/docs/functions-export-inventory.md) for support by trigger type.
|
|
76
76
|
|
|
77
77
|
### Unsupported products
|
|
78
78
|
|
|
@@ -143,6 +143,8 @@ On Windows, `emulators:export` and `--export-on-exit` are not currently availabl
|
|
|
143
143
|
|
|
144
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
145
|
|
|
146
|
+
On macOS, an ancestor directory with an ACL is refused when the ACL has an `allow` entry for anyone but the owner, root or the user running the export, whatever permissions the entry shows (the kernel grants rights that `ls -le` does not list). `deny` entries are accepted, so a standard home directory (which carries `group:everyone deny delete`) and the folders below it work. When an export is refused for an ACL, the message names the entry; remove it (`chmod -a`) or export to another directory, for example one under `$TMPDIR`. Check an ancestor with `/bin/ls -led <directory>`. A destination on a volume that ignores ownership (exFAT and FAT sticks and cards, or an external APFS volume with "Ignore ownership on this volume" turned on) is refused, because the owner and the mode of its directories do not show who can change them; export to a volume that enforces ownership. A volume without atomic directory rename (exFAT, FAT, some network filesystems) cannot publish an export either: use a directory on an APFS volume.
|
|
147
|
+
|
|
146
148
|
### Troubleshooting
|
|
147
149
|
|
|
148
150
|
For startup or installation problems, inspect the environment and bundled files with:
|
|
@@ -202,7 +204,7 @@ You can specify the configuration file with `--config`.
|
|
|
202
204
|
npx fireemu up --config ./fireemu.json
|
|
203
205
|
```
|
|
204
206
|
|
|
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.
|
|
207
|
+
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.11.0/spec/config/fireemu.schema.json) for all available settings.
|
|
206
208
|
|
|
207
209
|
### Firebase Authentication (Identity Platform) configuration
|
|
208
210
|
|
|
@@ -226,9 +228,9 @@ The `auth` section of `fireemu.json` lets you configure sign-in methods, passwor
|
|
|
226
228
|
| Public keys for verifying custom tokens and OIDC ID tokens | `auth.customTokenSigners`, `auth.idpSigners` |
|
|
227
229
|
| Sign-up quota configuration and local quota-exceeded simulation | `auth.quota`, `auth.quotaSimulation` |
|
|
228
230
|
|
|
229
|
-
See the [configuration schema](https://github.com/t-k/fireemu/blob/v0.
|
|
231
|
+
See the [configuration schema](https://github.com/t-k/fireemu/blob/v0.11.0/spec/config/fireemu.schema.json) for the format and accepted values of each setting.
|
|
230
232
|
|
|
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.
|
|
233
|
+
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.11.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
234
|
|
|
233
235
|
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
236
|
|
|
@@ -322,7 +324,7 @@ Under the `strict` profile, TOTP is enabled only through the project's MFA confi
|
|
|
322
324
|
|
|
323
325
|
#### Enable multi-tenancy
|
|
324
326
|
|
|
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.
|
|
327
|
+
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.11.0/docs/compatibility-contract.md) for the supported Admin API scope.
|
|
326
328
|
|
|
327
329
|
#### Start with tenants
|
|
328
330
|
|
|
@@ -367,9 +369,71 @@ This is a local fixed-window simulation. It does not reproduce Firebase’s full
|
|
|
367
369
|
|
|
368
370
|
### Configure execution time
|
|
369
371
|
|
|
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.
|
|
372
|
+
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. If the Functions event queue is full (4,096 active events or 64 MiB), a scheduled run that comes due stays due and runs once room frees, and a manual run answers `429 RESOURCE_EXHAUSTED` without being queued. The clock can also move backwards (`clock:set` with `"allowBackwards": true`, or **Allow moving backwards** on the Runtime page). In the `emulator` profile, ID tokens stay usable after a rewind, as with the official emulator, which does not check their issue time. In the `strict` profile, Authentication (`INVALID_ID_TOKEN`), Cloud Firestore and Cloud Storage refuse an ID token issued after the new time until the clock reaches its issue time again. In both profiles an expired token is still refused. A rewind to before an account was created, or before its tokens were revoked, makes even a new sign-in's token count as revoked; move the clock forward again or reset the session instead. Conversely, a revocation or password change made after a rewind does not revoke tokens issued at later times on the timeline: the `emulator` profile accepts them at once, and `strict` accepts them once the clock reaches their issue time. Move the clock forward past their issue time before revoking, or reset the session.
|
|
373
|
+
|
|
374
|
+
A schedule is driven by the virtual clock alone: real time passing runs nothing. Each clock move (`clock:advance`, `clock:advanceTo`, `clock:set` or the Runtime page) makes every occurrence in `(previous time, new time]` due, so an occurrence exactly at the new time is included and one exactly at the previous time is not. `scheduler.catchUp` decides what runs: `all` runs each one (at most `scheduler.maxCatchUpRuns` per job and clock move, the rest stays due and runs as room frees), `latest` runs the newest and `none` runs none, and both record one `skipped: catch-up` summary per job and clock move that drops runs. A rewind never replays: occurrences the schedule already passed are not run again when the clock moves forward over them, and the schedule resumes once the clock passes the last occurrence it ran or still owes (its cursor). After a rewind below that point, runs still owed from a backlog or held for room stay owed but do not come due again until the clock passes it. A session reset or a snapshot restore starts every schedule from the clock's current time instead, so after a rewind the occurrences between that time and a later one are due again. `scheduler.overlap` (`allow`, `skip`, `queue`, `reject`) applies to scheduler runs and manual runs alike. A function counts as busy while any of its runs is queued or running, including a run that is waiting to be retried, so under `skip` and `reject` a retry still pending can suppress the next occurrence; fireemu does not distinguish a retry attempt from an overlapping run here. With `catchUp: all`, one clock move over several occurrences of the same function overlaps itself, so `skip` keeps the oldest of them and `reject` counts the rest as rejections.
|
|
375
|
+
|
|
376
|
+
A manual run (`POST /v1/sessions/{session}/functions/{name}:run`) enqueues one run of a scheduled function stamped with the current virtual time. It does not consume the next occurrence, which still comes due and is subject to `scheduler.overlap` like any run. It answers `400 INVALID_ARGUMENT` for an unknown function, a function that is not scheduled, an overlap policy refusal, or a runtime that is shutting down, and `429 RESOURCE_EXHAUSTED` when the event queue is full. This is fireemu's own control, not a claim about production's run-now.
|
|
377
|
+
|
|
378
|
+
See the [configuration schema](https://github.com/t-k/fireemu/blob/v0.11.0/spec/config/fireemu.schema.json) for available settings and values.
|
|
379
|
+
|
|
380
|
+
### Firestore history limits
|
|
381
|
+
|
|
382
|
+
Like production, Fireemu keeps every version of a document written in the last hour, so a `read_time` read, a read-only transaction or a resumed listener can see it. A test that updates the same documents many times therefore holds many versions in memory. These limits are local; production has none of them:
|
|
383
|
+
|
|
384
|
+
- Each database retains at most 1 GiB of logical history bytes and 1,000,000 versions, each session 1 GiB and 1,000,000 versions, and the daemon 4 GiB and 4,000,000 versions. Logical bytes follow Firestore's storage size model and are not the process's memory, which can be several times larger.
|
|
385
|
+
- On a pinned clock (`daemon.clockStart`), time does not pass on its own, so a database keeps at most 1,024 versions of any one document. This limit works like `maxVersionsPerPath` below: once a document goes past it, older snapshots are released for the whole database.
|
|
386
|
+
- A commit that would cross a limit is refused whole with `RESOURCE_EXHAUSTED` and the message `Firestore retained history capacity is exhausted`.
|
|
387
|
+
|
|
388
|
+
Versions older than an hour are released by the next commit after the clock passes them. To use less memory, lower the limits in the `firestore.history` section:
|
|
389
|
+
|
|
390
|
+
```json
|
|
391
|
+
{
|
|
392
|
+
"schemaVersion": 1,
|
|
393
|
+
"firestore": {
|
|
394
|
+
"edition": "standard",
|
|
395
|
+
"apiMode": "native",
|
|
396
|
+
"history": {
|
|
397
|
+
"maxVersionsPerPath": 16,
|
|
398
|
+
"maxBytes": 268435456
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
```
|
|
371
403
|
|
|
372
|
-
|
|
404
|
+
- `maxVersionsPerPath` (1 to 1,000,000) sets the most versions of one document a database keeps, on either clock, in place of the defaults above.
|
|
405
|
+
- `maxBytes` (1 MiB to 1 GiB) lowers the logical history bytes one database retains. An import (`--import`) is not checked against it: a larger import starts with a `warning:` line naming the database, its bytes and the limit (a snapshot restore above it logs the same line), and every later write that would grow the history is refused with `RESOURCE_EXHAUSTED`.
|
|
406
|
+
|
|
407
|
+
Without these keys the defaults apply.
|
|
408
|
+
|
|
409
|
+
The version cap applies to each document separately, but its effect reaches the whole database. Snapshots stay exact for every document, so once any document has more versions than the cap, the database keeps no snapshot older than that document's oldest kept version. After that:
|
|
410
|
+
|
|
411
|
+
- A `read_time` read older than that point is refused with `FAILED_PRECONDITION` (`The requested 'read_time' is no longer retained by this database.`). So is a new read-only transaction at such a `read_time` (`read_time is no longer retained by this database`).
|
|
412
|
+
- A transaction already open on an older snapshot fails its next read or commit with `ABORTED` (`The referenced transaction has expired or is no longer valid.`), even if it only touches other documents.
|
|
413
|
+
- A listener resuming from an older point is reset and sent the full result again.
|
|
414
|
+
|
|
415
|
+
Client SDKs retry `ABORTED` transactions. One frequently updated document under a small cap can therefore keep aborting unrelated transactions. Avoid very small caps: choose a cap above the number of times any document is updated while your longest transaction is open.
|
|
416
|
+
|
|
417
|
+
To see how much history a running daemon holds, run `fireemu doctor --connect <control URL>`. Its `history.*` lines report the retained versions and logical bytes against the session and daemon limits, and how many bytes the next compaction would release.
|
|
418
|
+
|
|
419
|
+
### Storage stored-byte limit
|
|
420
|
+
|
|
421
|
+
The Storage emulator keeps every object in memory, and by default nothing bounds how much. To cap it, set `storage.maxStoredBytes` (bytes, at least 1). Production has no such limit; it is local to Fireemu:
|
|
422
|
+
|
|
423
|
+
```json
|
|
424
|
+
{
|
|
425
|
+
"schemaVersion": 1,
|
|
426
|
+
"storage": { "maxStoredBytes": 1073741824 }
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
- Each object counts its bytes once, and a copy counts again. Replacing an object counts only the difference in size.
|
|
431
|
+
- An upload, a resumable upload's final request or a copy that would grow the total past the limit is refused with HTTP 402 and the message `storage.maxStoredBytes limit exceeded` (in the JSON API, with the reason `storageCapacityExceeded`). There is no `Retry-After`. Delete objects to make room. The Firebase client SDKs report a 402 at once as `storage/quota-exceeded` without retrying; the Cloud Storage client libraries do not retry it either.
|
|
432
|
+
- A write that does not grow the total, such as an equal or smaller replacement, always passes, even while the store holds more than the limit (after an import, a restore or a lowered limit).
|
|
433
|
+
- A refused write changes nothing. A resumable upload stays open: its offset does not advance, so you can send the same final chunk again after making room, or cancel the upload.
|
|
434
|
+
- An import (`--import`) and a snapshot restore are not checked against the limit. An import above it starts with a `warning:` line naming the stored bytes and the limit, and a snapshot restore above it logs the same line.
|
|
435
|
+
|
|
436
|
+
`fireemu doctor --connect <control URL>` reports the stored bytes as `objects.bytes` against this limit.
|
|
373
437
|
|
|
374
438
|
## Compatibility and limitations
|
|
375
439
|
|
|
@@ -389,11 +453,15 @@ Fireemu is compatible with the listed Local Emulator Suite products as shipped b
|
|
|
389
453
|
|
|
390
454
|
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
455
|
|
|
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.
|
|
456
|
+
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.11.0/spec/compatibility/contract.json) records scope and known differences. The [compatibility documentation](https://github.com/t-k/fireemu/blob/v0.11.0/docs/compatibility-contract.md) explains the verification process and how to interpret its records.
|
|
457
|
+
|
|
458
|
+
### Network exposure of the Storage port
|
|
459
|
+
|
|
460
|
+
Like the official emulator, the Storage port reflects the requested object name in the HTML body of its 404 for a missing media read (`text/html`, as production answers). A web page opened on the developer's machine could therefore run script on that origin. Keep the emulator bound to localhost, which is the default, and do not expose the Storage port to other hosts or networks. The strict profile sends no `X-Content-Type-Options: nosniff` on the JSON API answers where production sends none, so it does not add that defence in depth; the emulator profile keeps the official emulator's header.
|
|
393
461
|
|
|
394
462
|
### Changes between versions
|
|
395
463
|
|
|
396
|
-
Configuration and behavior may change between releases. See the [CHANGELOG](https://github.com/t-k/fireemu/blob/v0.
|
|
464
|
+
Configuration and behavior may change between releases. See the [CHANGELOG](https://github.com/t-k/fireemu/blob/v0.11.0/CHANGELOG.md) for release changes.
|
|
397
465
|
|
|
398
466
|
## Performance
|
|
399
467
|
|
|
@@ -410,7 +478,7 @@ The following results come from one `standard` run at commit `f3b942c`. Ratios a
|
|
|
410
478
|
|
|
411
479
|
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
480
|
|
|
413
|
-
See [benchmark.yml](https://github.com/t-k/fireemu/blob/v0.
|
|
481
|
+
See [benchmark.yml](https://github.com/t-k/fireemu/blob/v0.11.0/.github/workflows/benchmark.yml) for the workflow and [`tools/bench/`](https://github.com/t-k/fireemu/tree/v0.11.0/tools/bench/) for the benchmark implementation.
|
|
414
482
|
|
|
415
483
|
## Reporting issues and contributing
|
|
416
484
|
|
|
@@ -418,8 +486,8 @@ When reporting an issue, include the Fireemu and Firebase SDK versions, the prof
|
|
|
418
486
|
|
|
419
487
|
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.
|
|
420
488
|
|
|
421
|
-
See the [development guide](https://github.com/t-k/fireemu/blob/v0.
|
|
489
|
+
See the [development guide](https://github.com/t-k/fireemu/blob/v0.11.0/docs/development.md) for build and test instructions.
|
|
422
490
|
|
|
423
491
|
## License
|
|
424
492
|
|
|
425
|
-
Fireemu is licensed under the [Apache License 2.0](https://github.com/t-k/fireemu/blob/v0.
|
|
493
|
+
Fireemu is licensed under the [Apache License 2.0](https://github.com/t-k/fireemu/blob/v0.11.0/LICENSE). Third-party notices are listed in [THIRD_PARTY_LICENSES.txt](https://github.com/t-k/fireemu/blob/v0.11.0/THIRD_PARTY_LICENSES.txt).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fireemu",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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.11.0",
|
|
31
|
+
"@fireemu/darwin-x64": "0.11.0",
|
|
32
|
+
"@fireemu/linux-x64": "0.11.0",
|
|
33
|
+
"@fireemu/linux-arm64": "0.11.0",
|
|
34
|
+
"@fireemu/win32-x64": "0.11.0"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=20"
|