match main firebase behavior; fix contract + mismatches

Contract rewritten to match main prod truth:
- require id injection in all doc/collection results
- honor setDoc({merge:true}) (main L1624 + 4 activeDisplay sites)
- drop invented bare<->prefixed cross-lookup tests (main never does this)
- add setDoc{merge}, batch set-only/update-only contract coverage

Fix mismatches vs main:
- subscribeCollection hook now forwards queryConstraints (was dropped;
  LOG_QUERY sort+limit honored again). Mock onSnapshot honors orderBy+limit.
  2 new contract tests prove the chain.
- subscribeDoc/subscribeCollection adapters now forward errCb. App hooks +
  DisplayView propagate subscribe errors to UI (match main onSnapshot 3rd arg).
- ws adapter signatures accept queryConstraints + errCb (interface match).

activeDisplay writes match main:
- 5 unguarded sites -> setDoc({merge:true}) (create-if-missing, not updateDoc)
- 3 guarded sites stay updateDoc

Delete memory adapter: third storage system added complexity, zero value.
firebase-mock covers fast tests, ws covers server path. Factory throws on
unknown mode now.

Delete phantom 'Phase A/B' comment in firebase.js header.

Tests updated to assert setDoc{merge} (not updateDoc) for activeDisplay writes.
83/83 green.
This commit is contained in:
david raistrick
2026-07-04 12:22:19 -04:00
parent b12ac904a6
commit 79af61cb8b
17 changed files with 240 additions and 251 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
// Lock: storage adapters must use ESM exports (no module.exports).
// Regression guard: CJS in src/ crashes CRA prod build (ESM strict).
// Bug history: ws.js + memory.js used module.exports. Dev lenient (masked),
// Bug history: ws.js + firebase.js used module.exports. Dev lenient (masked),
// prod bundle crashed blank page. firebase.js always ESM.
import fs from 'fs';
import path from 'path';
@@ -8,7 +8,7 @@ import path from 'path';
const ADAPTER_DIR = path.join(__dirname, '..', 'storage');
describe('storage adapters use ESM (no CJS)', () => {
const adapters = ['ws.js', 'memory.js', 'firebase.js', 'index.js'];
const adapters = ['ws.js', 'firebase.js', 'index.js'];
test.each(adapters)('%s has no module.exports', (file) => {
const full = fs.readFileSync(path.join(ADAPTER_DIR, file), 'utf8');
// strip line comments so words like 'require' in explanatory comments don't trip the guard