fireemu 0.10.0 → 0.12.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.
Files changed (2) hide show
  1. package/README.md +82 -14
  2. 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.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.
17
+ See the [capability manifest](https://github.com/t-k/fireemu/blob/v0.12.0/crates/fireemu/src/capabilities.json) and [compatibility documentation](https://github.com/t-k/fireemu/blob/v0.12.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.10.0/crates/fireemu/src/capabilities.json).
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.12.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.10.0/docs/functions-export-inventory.md) for support by trigger type.
75
+ See the [Functions support inventory](https://github.com/t-k/fireemu/blob/v0.12.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.10.0/spec/config/fireemu.schema.json) for all available settings.
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.12.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.10.0/spec/config/fireemu.schema.json) for the format and accepted values of each setting.
231
+ See the [configuration schema](https://github.com/t-k/fireemu/blob/v0.12.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.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.
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.12.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.10.0/docs/compatibility-contract.md) for the supported Admin API scope.
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.12.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`, `skip-in-flight`) applies to scheduler runs and manual runs alike, except `skip-in-flight`, which never refuses a manual run. Unset, the strict profile uses `skip-in-flight`: an occurrence is dropped (recorded as `skipped: in flight`) while a handler of the function that started before the clock move is still executing, as production's Cloud Scheduler did, and the occurrences of one clock move do not count against each other; the emulator profile uses `allow`. 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.12.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
- See the [configuration schema](https://github.com/t-k/fireemu/blob/v0.10.0/spec/config/fireemu.schema.json) for available settings and values.
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.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.
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.12.0/spec/compatibility/contract.json) records scope and known differences. The [compatibility documentation](https://github.com/t-k/fireemu/blob/v0.12.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.10.0/CHANGELOG.md) for release changes.
464
+ Configuration and behavior may change between releases. See the [CHANGELOG](https://github.com/t-k/fireemu/blob/v0.12.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.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.
481
+ See [benchmark.yml](https://github.com/t-k/fireemu/blob/v0.12.0/.github/workflows/benchmark.yml) for the workflow and [`tools/bench/`](https://github.com/t-k/fireemu/tree/v0.12.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.10.0/docs/development.md) for build and test instructions.
489
+ See the [development guide](https://github.com/t-k/fireemu/blob/v0.12.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.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).
493
+ Fireemu is licensed under the [Apache License 2.0](https://github.com/t-k/fireemu/blob/v0.12.0/LICENSE). Third-party notices are listed in [THIRD_PARTY_LICENSES.txt](https://github.com/t-k/fireemu/blob/v0.12.0/THIRD_PARTY_LICENSES.txt).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fireemu",
3
- "version": "0.10.0",
3
+ "version": "0.12.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.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"
30
+ "@fireemu/darwin-arm64": "0.12.0",
31
+ "@fireemu/darwin-x64": "0.12.0",
32
+ "@fireemu/linux-x64": "0.12.0",
33
+ "@fireemu/linux-arm64": "0.12.0",
34
+ "@fireemu/win32-x64": "0.12.0"
35
35
  },
36
36
  "engines": {
37
37
  "node": ">=20"