Pyric
Navigate

pyric/app compatibility matrix

81.3% of the public API supported

13 of 16 public API

Status legend

Conforming — the mirror matches prod, locked by a passing replay Diverged (documented) — intentional difference with a written reason Not implemented yet — deliberately or deferred Unverified — claim from docs not yet observed prod-side

initializeApp(config, name?) — the app registry

initializeApp(config)Registers the default app under the name '[DEFAULT]'; getApps() has length 1 and getApp() (no arg) resolves the same instance
initializeApp(config, 'secondary')Registers a named app alongside the default; getApp('secondary') resolves it and getApps() has length 2 (default + named)
initializeApp(config)A same-name re-initialization with a DIFFERENT config throws FirebaseError code app/duplicate-app, with the app name embedded in the message
initializeApp(config)A same-name re-initialization with EQUAL config is idempotent — no throw, returns the existing instance, and getApps() stays length 1
getApp()getApp() with no name resolves the default app instance; its name is '[DEFAULT]'
oracle: app-registry-getapp-default (firebase 12.13.0) + replay: oracle-conformance.test.ts
getApp('secondary')getApp('secondary') resolves the named app instance; its name is 'secondary'
oracle: app-registry-getapp-named (firebase 12.13.0) + replay: oracle-conformance.test.ts
getApp(name)getApp(name) for a name that was never initialized throws FirebaseError code app/no-app, directing the caller to initializeApp()
getApps()getApps() returns an array containing every registered app by identity (the exact instances, not copies)
oracle: app-registry-getapps-contents (firebase 12.13.0) + replay: oracle-conformance.test.ts
deleteApp(app)deleteApp(app) returns a Promise, deregisters the app (so getApps() shrinks), a later getApp(name) throws app/no-app, and the name can be re-initialized afterwards
oracle: app-registry-deleteapp (firebase 12.13.0) + replay: oracle-conformance.test.ts
deleteApp(app)deleteApp on an already-deleted app throws FirebaseError code app/app-deleted
oracle: app-registry-deleteapp-double (firebase 12.13.0) + replay: oracle-conformance.test.ts
SDK_VERSIONSDK_VERSION is the Firebase client SDK semver string whose behavior pyric currently mirrors, pinned to the oracle version (12.13.0)
oracle: app-registry-sdk-version (firebase 12.13.0) + replay: oracle-conformance.test.ts
FirebaseErrorFirebaseError is an app-owned Error subclass: instanceof Error, constructor.name is 'FirebaseError', and it preserves .code and .message without loading firebase/app
onLog / setLogLevelonLog(cb) / setLogLevel(level) are a functioning app-owned diagnostic-logger seam: registering a handler returns undefined, raising the threshold takes effect, and a malformed registerVersion emits a warn entry (type @firebase/app) to the handler
oracle: app-registry-onlog-setloglevel (firebase 12.13.0) + replay: oracle-conformance.test.ts
registerVersionregisterVersion(library, version) accepts a well-formed registration and returns undefined without throwing; malformed values emit the observed warning through the app-owned logger
oracle: app-registry-registerversion (firebase 12.13.0) + replay: oracle-conformance.test.ts
initializeServerAppNot implemented; disposition app.server-app owns the reviewed availability and rationale
disposition:app.server-app
initializeApp(options, settings)initializeApp snapshots options, accepts a settings object, initializes automaticDataCollectionEnabled, and leaves that app property mutable
initializeApp(equalOptions, 'secondary')Equal-config named apps are distinct app containers with equal option values and independent name-keyed registry identity
getAuth/getFirestore/getDatabase/getStorage(app)Equal-config named apps own distinct app-associated service handles while resolving the same configured RTDB and Storage backend locators
initializeApp(differentOptions, 'secondary')Production permits a differently configured named app; Pyric rejects it because one runtime currently owns exactly one sandbox backend
oracle: app-registry-initializeapp-named-different-config (firebase 12.13.0) + replay pins app/multiple-configs-not-supported; packages/cli/test/e2e/app-multi-app.pw.ts proves the same lock is enforced by the authoritative SharedWorker across same-origin tabs, not only by one page registry (Structured evidence: oracle-conformance.test.ts)
deleteApp(app); initializeApp(differentOptions)Production permits a different configuration after deletion; Pyric retains the runtime backend lock and rejects the reinitialization
oracle: app-registry-delete-reinitialize-different-config (firebase 12.13.0) + replay pins app/multiple-configs-not-supported (Structured evidence: oracle-conformance.test.ts)
initializeApp()Without Hosting-provided defaults, omitting options throws FirebaseError code app/no-options with the production message
getAuth/getFirestore/getDatabase/getStorage()With a registered default app, each no-argument service factory resolves a service associated with that exact default app
initializeApp(equalOptions, name)Equal-config app instances connect to one logical backend: data written through one app is readable through another, while their active Auth sessions remain independent
oracle: app-production-multi-app-topology (firebase 12.13.0, real Chromium against production) + twin replay: production-multi-app-oracle.test.ts; served SharedWorker replay: app-multi-app.pw.ts
deleteApp(app); app.name / app.options / app.automaticDataCollectionEnabledAfter deletion resolves, every public FirebaseApp property accessor throws FirebaseError code app/app-deleted
deleteApp(app); getAuth/getFirestore/getDatabase/getStorage/getAI(app)After deletion, fresh Auth/Firestore/RTDB/Storage factories reject; cached factories return retained handles; retained Auth sign-out resolves but a new anonymous sign-in rejects app/app-deleted; Firestore reads report termination, RTDB refuses new refs, Storage refs remain constructible, and getAI(deletedApp) returns an app-associated handle
deleteApp(app)Deleting one app terminates its Firestore listener through the error callback with code aborted, silently stops its RTDB listener, and leaves equal-config sibling listeners and the shared backend usable
oracle: app-production-multi-app-topology (firebase 12.13.0, real Chromium against production) + twin replay: production-multi-app-oracle.test.ts; focused family tests: multi-app-listener-auth.test.ts and served app-multi-app.pw.ts
getAI(app, customEngine); deleteApp(app); retainedModel operationServed worker mode rejects page-local custom AnswerEngine objects; a model retained from a deleted app rejects, while an equal-config sibling model remains usable through its own app-scoped worker port
packages/cli/test/e2e/app-deletion.pw.ts observes AI code unsupported for a custom engine, then exercises retained and sibling models through canonical served imports after deleting one app; packages/pyric/src/ai/sandbox-plane.ts guards every model operation. A credentialed production AI lifecycle capture is still needed

Current gaps

Documented divergences

Known differences between Pyric and production Firebase. Each remains tracked as a non-conforming row.

initializeApp(differentOptions, 'secondary')Production permits a differently configured named app; Pyric rejects it because one runtime currently owns exactly one sandbox backend
oracle: app-registry-initializeapp-named-different-config (firebase 12.13.0) + replay pins app/multiple-configs-not-supported; packages/cli/test/e2e/app-multi-app.pw.ts proves the same lock is enforced by the authoritative SharedWorker across same-origin tabs, not only by one page registry (Structured evidence: oracle-conformance.test.ts)
deleteApp(app); initializeApp(differentOptions)Production permits a different configuration after deletion; Pyric retains the runtime backend lock and rejects the reinitialization
oracle: app-registry-delete-reinitialize-different-config (firebase 12.13.0) + replay pins app/multiple-configs-not-supported (Structured evidence: oracle-conformance.test.ts)

Not implemented yet

Tracked behavior that is not implemented in the current contract.

initializeServerAppNot implemented; disposition app.server-app owns the reviewed availability and rationale
disposition:app.server-app

Unverified

Tracked behavior whose available evidence does not yet establish the production result.

getAI(app, customEngine); deleteApp(app); retainedModel operationServed worker mode rejects page-local custom AnswerEngine objects; a model retained from a deleted app rejects, while an equal-config sibling model remains usable through its own app-scoped worker port
packages/cli/test/e2e/app-deletion.pw.ts observes AI code unsupported for a custom engine, then exercises retained and sibling models through canonical served imports after deleting one app; packages/pyric/src/ai/sandbox-plane.ts guards every model operation. A credentialed production AI lifecycle capture is still needed

Reviewed public-runtime gaps

app.server-appServer-app (SSR) initialization: a FirebaseServerApp carries per-request auth/heartbeat state with no decided sandbox mirror pattern yet. Deferred, not out of scope — tracked as an unsupported registry row (registry/app.ts app#15).
initializeServerApp
registry:app#15