@multiplatform.one/frappe 6.0.4 → 6.3.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 +38 -12
- package/dist/cjs/auth.cjs +1 -1
- package/dist/cjs/auth.native.js.map +1 -1
- package/dist/cjs/call.cjs +1 -1
- package/dist/cjs/call.native.js.map +1 -1
- package/dist/cjs/collection.cjs +18 -4
- package/dist/cjs/collection.native.js +18 -4
- package/dist/cjs/collection.native.js.map +1 -1
- package/dist/cjs/core/http.cjs +92 -9
- package/dist/cjs/core/http.native.js +96 -7
- package/dist/cjs/core/http.native.js.map +1 -1
- package/dist/cjs/db.cjs +7 -7
- package/dist/cjs/db.native.js +4 -4
- package/dist/cjs/db.native.js.map +1 -1
- package/dist/cjs/doctype.cjs +97 -39
- package/dist/cjs/doctype.native.js +116 -46
- package/dist/cjs/doctype.native.js.map +1 -1
- package/dist/cjs/file.cjs +1 -1
- package/dist/cjs/file.native.js.map +1 -1
- package/dist/cjs/fixtureDb.cjs +3 -2
- package/dist/cjs/fixtureDb.native.js +2 -1
- package/dist/cjs/fixtureDb.native.js.map +1 -1
- package/dist/cjs/frappeApp.cjs +15 -14
- package/dist/cjs/frappeApp.native.js +16 -14
- package/dist/cjs/frappeApp.native.js.map +1 -1
- package/dist/cjs/frappeReact.cjs +198 -18
- package/dist/cjs/frappeReact.native.js +241 -18
- package/dist/cjs/frappeReact.native.js.map +1 -1
- package/dist/cjs/index.cjs +9 -4
- package/dist/cjs/index.native.js +9 -4
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/pacer.cjs +2 -2
- package/dist/cjs/pacer.native.js +2 -2
- package/dist/cjs/pacer.native.js.map +1 -1
- package/dist/cjs/realtime.cjs +186 -46
- package/dist/cjs/realtime.native.js +268 -48
- package/dist/cjs/realtime.native.js.map +1 -1
- package/dist/cjs/sync/backfill.cjs +32 -27
- package/dist/cjs/sync/backfill.native.js +49 -43
- package/dist/cjs/sync/backfill.native.js.map +1 -1
- package/dist/cjs/sync/index.cjs +90 -24
- package/dist/cjs/sync/index.native.js +112 -10
- package/dist/cjs/sync/index.native.js.map +1 -1
- package/dist/cjs/sync/merge.cjs +0 -3
- package/dist/cjs/sync/merge.native.js +0 -3
- package/dist/cjs/sync/merge.native.js.map +1 -1
- package/dist/cjs/sync/mutationEngine.cjs +25 -19
- package/dist/cjs/sync/mutationEngine.native.js +16 -13
- package/dist/cjs/sync/mutationEngine.native.js.map +1 -1
- package/dist/cjs/sync/mutationJournal.cjs +9 -4
- package/dist/cjs/sync/mutationJournal.native.js +7 -4
- package/dist/cjs/sync/mutationJournal.native.js.map +1 -1
- package/dist/cjs/sync/normalizedCache.cjs +7 -3
- package/dist/cjs/sync/normalizedCache.native.js +7 -2
- package/dist/cjs/sync/normalizedCache.native.js.map +1 -1
- package/dist/cjs/sync/persistence.cjs +63 -31
- package/dist/cjs/sync/persistence.native.js +120 -63
- package/dist/cjs/sync/persistence.native.js.map +1 -1
- package/dist/cjs/sync/realtime.cjs +124 -13
- package/dist/cjs/sync/realtime.native.js +163 -20
- package/dist/cjs/sync/realtime.native.js.map +1 -1
- package/dist/cjs/sync/rehydration.cjs +16 -10
- package/dist/cjs/sync/rehydration.native.js +16 -14
- package/dist/cjs/sync/rehydration.native.js.map +1 -1
- package/dist/cjs/sync/storage.cjs +3 -3
- package/dist/cjs/sync/storage.native.js +1 -1
- package/dist/cjs/sync/storage.native.js.map +1 -1
- package/dist/cjs/sync/subscriptionManager.cjs +255 -65
- package/dist/cjs/sync/subscriptionManager.native.js +330 -93
- package/dist/cjs/sync/subscriptionManager.native.js.map +1 -1
- package/dist/cjs/sync/types.cjs +2 -0
- package/dist/cjs/sync/types.native.js +2 -0
- package/dist/cjs/sync/types.native.js.map +1 -1
- package/dist/cjs/sync/virtualPageManager.cjs +9 -9
- package/dist/cjs/sync/virtualPageManager.native.js +5 -9
- package/dist/cjs/sync/virtualPageManager.native.js.map +1 -1
- package/dist/cjs/useLiveQuery.cjs +52 -0
- package/dist/cjs/useLiveQuery.native.js +59 -0
- package/dist/cjs/useLiveQuery.native.js.map +1 -0
- package/dist/cjs/util.cjs +11 -2
- package/dist/cjs/util.native.js +16 -2
- package/dist/cjs/util.native.js.map +1 -1
- package/dist/esm/auth.mjs +1 -1
- package/dist/esm/auth.mjs.map +1 -1
- package/dist/esm/auth.native.js.map +1 -1
- package/dist/esm/call.mjs +1 -1
- package/dist/esm/call.mjs.map +1 -1
- package/dist/esm/call.native.js.map +1 -1
- package/dist/esm/collection.mjs +18 -4
- package/dist/esm/collection.mjs.map +1 -1
- package/dist/esm/collection.native.js +18 -4
- package/dist/esm/collection.native.js.map +1 -1
- package/dist/esm/core/http.mjs +93 -10
- package/dist/esm/core/http.mjs.map +1 -1
- package/dist/esm/core/http.native.js +97 -8
- package/dist/esm/core/http.native.js.map +1 -1
- package/dist/esm/db.mjs +7 -7
- package/dist/esm/db.mjs.map +1 -1
- package/dist/esm/db.native.js +4 -4
- package/dist/esm/db.native.js.map +1 -1
- package/dist/esm/doctype.mjs +96 -39
- package/dist/esm/doctype.mjs.map +1 -1
- package/dist/esm/doctype.native.js +115 -46
- package/dist/esm/doctype.native.js.map +1 -1
- package/dist/esm/file.mjs +1 -1
- package/dist/esm/file.mjs.map +1 -1
- package/dist/esm/file.native.js.map +1 -1
- package/dist/esm/fixtureDb.mjs +3 -2
- package/dist/esm/fixtureDb.mjs.map +1 -1
- package/dist/esm/fixtureDb.native.js +2 -1
- package/dist/esm/fixtureDb.native.js.map +1 -1
- package/dist/esm/frappeApp.mjs +15 -14
- package/dist/esm/frappeApp.mjs.map +1 -1
- package/dist/esm/frappeApp.native.js +16 -14
- package/dist/esm/frappeApp.native.js.map +1 -1
- package/dist/esm/frappeReact.mjs +197 -19
- package/dist/esm/frappeReact.mjs.map +1 -1
- package/dist/esm/frappeReact.native.js +240 -19
- package/dist/esm/frappeReact.native.js.map +1 -1
- package/dist/esm/index.mjs +5 -4
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +5 -4
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/pacer.mjs +1 -1
- package/dist/esm/pacer.native.js +1 -1
- package/dist/esm/realtime.mjs +187 -47
- package/dist/esm/realtime.mjs.map +1 -1
- package/dist/esm/realtime.native.js +269 -49
- package/dist/esm/realtime.native.js.map +1 -1
- package/dist/esm/sync/backfill.mjs +32 -27
- package/dist/esm/sync/backfill.mjs.map +1 -1
- package/dist/esm/sync/backfill.native.js +49 -43
- package/dist/esm/sync/backfill.native.js.map +1 -1
- package/dist/esm/sync/index.mjs +90 -24
- package/dist/esm/sync/index.mjs.map +1 -1
- package/dist/esm/sync/index.native.js +112 -10
- package/dist/esm/sync/index.native.js.map +1 -1
- package/dist/esm/sync/merge.mjs +1 -1
- package/dist/esm/sync/merge.mjs.map +1 -1
- package/dist/esm/sync/merge.native.js +1 -1
- package/dist/esm/sync/merge.native.js.map +1 -1
- package/dist/esm/sync/mutationEngine.mjs +25 -19
- package/dist/esm/sync/mutationEngine.mjs.map +1 -1
- package/dist/esm/sync/mutationEngine.native.js +16 -13
- package/dist/esm/sync/mutationEngine.native.js.map +1 -1
- package/dist/esm/sync/mutationJournal.mjs +9 -4
- package/dist/esm/sync/mutationJournal.mjs.map +1 -1
- package/dist/esm/sync/mutationJournal.native.js +7 -4
- package/dist/esm/sync/mutationJournal.native.js.map +1 -1
- package/dist/esm/sync/normalizedCache.mjs +7 -3
- package/dist/esm/sync/normalizedCache.mjs.map +1 -1
- package/dist/esm/sync/normalizedCache.native.js +7 -2
- package/dist/esm/sync/normalizedCache.native.js.map +1 -1
- package/dist/esm/sync/persistence.mjs +64 -32
- package/dist/esm/sync/persistence.mjs.map +1 -1
- package/dist/esm/sync/persistence.native.js +121 -64
- package/dist/esm/sync/persistence.native.js.map +1 -1
- package/dist/esm/sync/realtime.mjs +124 -13
- package/dist/esm/sync/realtime.mjs.map +1 -1
- package/dist/esm/sync/realtime.native.js +163 -20
- package/dist/esm/sync/realtime.native.js.map +1 -1
- package/dist/esm/sync/rehydration.mjs +16 -10
- package/dist/esm/sync/rehydration.mjs.map +1 -1
- package/dist/esm/sync/rehydration.native.js +16 -14
- package/dist/esm/sync/rehydration.native.js.map +1 -1
- package/dist/esm/sync/storage.mjs +3 -3
- package/dist/esm/sync/storage.mjs.map +1 -1
- package/dist/esm/sync/storage.native.js +1 -1
- package/dist/esm/sync/storage.native.js.map +1 -1
- package/dist/esm/sync/subscriptionManager.mjs +255 -65
- package/dist/esm/sync/subscriptionManager.mjs.map +1 -1
- package/dist/esm/sync/subscriptionManager.native.js +330 -93
- package/dist/esm/sync/subscriptionManager.native.js.map +1 -1
- package/dist/esm/sync/types.mjs +2 -0
- package/dist/esm/sync/types.mjs.map +1 -1
- package/dist/esm/sync/types.native.js +2 -0
- package/dist/esm/sync/types.native.js.map +1 -1
- package/dist/esm/sync/virtualPageManager.mjs +9 -9
- package/dist/esm/sync/virtualPageManager.mjs.map +1 -1
- package/dist/esm/sync/virtualPageManager.native.js +5 -9
- package/dist/esm/sync/virtualPageManager.native.js.map +1 -1
- package/dist/esm/useLiveQuery.mjs +26 -0
- package/dist/esm/useLiveQuery.mjs.map +1 -0
- package/dist/esm/useLiveQuery.native.js +30 -0
- package/dist/esm/useLiveQuery.native.js.map +1 -0
- package/dist/esm/util.mjs +11 -3
- package/dist/esm/util.mjs.map +1 -1
- package/dist/esm/util.native.js +16 -3
- package/dist/esm/util.native.js.map +1 -1
- package/dist/jsx/auth.mjs +1 -1
- package/dist/jsx/auth.mjs.map +1 -1
- package/dist/jsx/auth.native.js.map +1 -1
- package/dist/jsx/call.mjs +1 -1
- package/dist/jsx/call.mjs.map +1 -1
- package/dist/jsx/call.native.js.map +1 -1
- package/dist/jsx/collection.mjs +18 -4
- package/dist/jsx/collection.mjs.map +1 -1
- package/dist/jsx/collection.native.js +18 -4
- package/dist/jsx/collection.native.js.map +1 -1
- package/dist/jsx/core/http.mjs +93 -10
- package/dist/jsx/core/http.mjs.map +1 -1
- package/dist/jsx/core/http.native.js +96 -7
- package/dist/jsx/core/http.native.js.map +1 -1
- package/dist/jsx/db.mjs +7 -7
- package/dist/jsx/db.mjs.map +1 -1
- package/dist/jsx/db.native.js +4 -4
- package/dist/jsx/db.native.js.map +1 -1
- package/dist/jsx/doctype.mjs +96 -39
- package/dist/jsx/doctype.mjs.map +1 -1
- package/dist/jsx/doctype.native.js +116 -46
- package/dist/jsx/doctype.native.js.map +1 -1
- package/dist/jsx/file.mjs +1 -1
- package/dist/jsx/file.mjs.map +1 -1
- package/dist/jsx/file.native.js.map +1 -1
- package/dist/jsx/fixtureDb.mjs +3 -2
- package/dist/jsx/fixtureDb.mjs.map +1 -1
- package/dist/jsx/fixtureDb.native.js +2 -1
- package/dist/jsx/fixtureDb.native.js.map +1 -1
- package/dist/jsx/frappeApp.mjs +15 -14
- package/dist/jsx/frappeApp.mjs.map +1 -1
- package/dist/jsx/frappeApp.native.js +16 -14
- package/dist/jsx/frappeApp.native.js.map +1 -1
- package/dist/jsx/frappeReact.mjs +197 -19
- package/dist/jsx/frappeReact.mjs.map +1 -1
- package/dist/jsx/frappeReact.native.js +241 -18
- package/dist/jsx/frappeReact.native.js.map +1 -1
- package/dist/jsx/index.js +5 -4
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +5 -4
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +9 -4
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/pacer.mjs +1 -1
- package/dist/jsx/pacer.native.js +2 -2
- package/dist/jsx/pacer.native.js.map +1 -1
- package/dist/jsx/realtime.mjs +187 -47
- package/dist/jsx/realtime.mjs.map +1 -1
- package/dist/jsx/realtime.native.js +268 -48
- package/dist/jsx/realtime.native.js.map +1 -1
- package/dist/jsx/sync/backfill.mjs +32 -27
- package/dist/jsx/sync/backfill.mjs.map +1 -1
- package/dist/jsx/sync/backfill.native.js +49 -43
- package/dist/jsx/sync/backfill.native.js.map +1 -1
- package/dist/jsx/sync/index.mjs +90 -24
- package/dist/jsx/sync/index.mjs.map +1 -1
- package/dist/jsx/sync/index.native.js +112 -10
- package/dist/jsx/sync/index.native.js.map +1 -1
- package/dist/jsx/sync/merge.mjs +1 -1
- package/dist/jsx/sync/merge.mjs.map +1 -1
- package/dist/jsx/sync/merge.native.js +0 -3
- package/dist/jsx/sync/merge.native.js.map +1 -1
- package/dist/jsx/sync/mutationEngine.mjs +25 -19
- package/dist/jsx/sync/mutationEngine.mjs.map +1 -1
- package/dist/jsx/sync/mutationEngine.native.js +16 -13
- package/dist/jsx/sync/mutationEngine.native.js.map +1 -1
- package/dist/jsx/sync/mutationJournal.mjs +9 -4
- package/dist/jsx/sync/mutationJournal.mjs.map +1 -1
- package/dist/jsx/sync/mutationJournal.native.js +7 -4
- package/dist/jsx/sync/mutationJournal.native.js.map +1 -1
- package/dist/jsx/sync/normalizedCache.mjs +7 -3
- package/dist/jsx/sync/normalizedCache.mjs.map +1 -1
- package/dist/jsx/sync/normalizedCache.native.js +7 -2
- package/dist/jsx/sync/normalizedCache.native.js.map +1 -1
- package/dist/jsx/sync/persistence.mjs +64 -32
- package/dist/jsx/sync/persistence.mjs.map +1 -1
- package/dist/jsx/sync/persistence.native.js +120 -63
- package/dist/jsx/sync/persistence.native.js.map +1 -1
- package/dist/jsx/sync/realtime.mjs +124 -13
- package/dist/jsx/sync/realtime.mjs.map +1 -1
- package/dist/jsx/sync/realtime.native.js +163 -20
- package/dist/jsx/sync/realtime.native.js.map +1 -1
- package/dist/jsx/sync/rehydration.mjs +16 -10
- package/dist/jsx/sync/rehydration.mjs.map +1 -1
- package/dist/jsx/sync/rehydration.native.js +16 -14
- package/dist/jsx/sync/rehydration.native.js.map +1 -1
- package/dist/jsx/sync/storage.mjs +3 -3
- package/dist/jsx/sync/storage.mjs.map +1 -1
- package/dist/jsx/sync/storage.native.js +1 -1
- package/dist/jsx/sync/storage.native.js.map +1 -1
- package/dist/jsx/sync/subscriptionManager.mjs +255 -65
- package/dist/jsx/sync/subscriptionManager.mjs.map +1 -1
- package/dist/jsx/sync/subscriptionManager.native.js +330 -93
- package/dist/jsx/sync/subscriptionManager.native.js.map +1 -1
- package/dist/jsx/sync/types.mjs +2 -0
- package/dist/jsx/sync/types.mjs.map +1 -1
- package/dist/jsx/sync/types.native.js +2 -0
- package/dist/jsx/sync/types.native.js.map +1 -1
- package/dist/jsx/sync/virtualPageManager.mjs +9 -9
- package/dist/jsx/sync/virtualPageManager.mjs.map +1 -1
- package/dist/jsx/sync/virtualPageManager.native.js +5 -9
- package/dist/jsx/sync/virtualPageManager.native.js.map +1 -1
- package/dist/jsx/useLiveQuery.mjs +26 -0
- package/dist/jsx/useLiveQuery.mjs.map +1 -0
- package/dist/jsx/useLiveQuery.native.js +59 -0
- package/dist/jsx/useLiveQuery.native.js.map +1 -0
- package/dist/jsx/util.mjs +11 -3
- package/dist/jsx/util.mjs.map +1 -1
- package/dist/jsx/util.native.js +16 -2
- package/dist/jsx/util.native.js.map +1 -1
- package/package.json +20 -17
- package/src/auth.ts +5 -1
- package/src/call.ts +5 -1
- package/src/collection.spec.ts +55 -0
- package/src/collection.ts +33 -4
- package/src/core/http.spec.ts +66 -0
- package/src/core/http.ts +115 -9
- package/src/core/httpNative.spec.ts +234 -0
- package/src/core/types.ts +2 -0
- package/src/db.spec.ts +91 -51
- package/src/db.ts +27 -8
- package/src/doctype.spec.ts +247 -39
- package/src/doctype.ts +203 -53
- package/src/file.ts +5 -1
- package/src/fixtureDb.ts +13 -2
- package/src/frappeApp.ts +18 -19
- package/src/frappeReact.spec.ts +565 -1
- package/src/frappeReact.ts +446 -38
- package/src/frappeReactLiveQueryGc.spec.ts +320 -0
- package/src/frappeReactNative.spec.ts +65 -0
- package/src/index.ts +10 -9
- package/src/pacer.ts +2 -2
- package/src/realtime.spec.ts +464 -20
- package/src/realtime.ts +284 -46
- package/src/sync/backfill.spec.ts +43 -0
- package/src/sync/backfill.ts +59 -39
- package/src/sync/debug.spec.ts +36 -0
- package/src/sync/filterValidation.spec.ts +197 -0
- package/src/sync/index.ts +98 -7
- package/src/sync/merge.ts +3 -3
- package/src/sync/mutationEngine.spec.ts +36 -4
- package/src/sync/mutationEngine.ts +30 -11
- package/src/sync/mutationJournal.ts +18 -4
- package/src/sync/normalizedCache.spec.ts +102 -0
- package/src/sync/normalizedCache.ts +19 -3
- package/src/sync/offlineRestore.spec.ts +423 -0
- package/src/sync/persistence.spec.ts +39 -7
- package/src/sync/persistence.ts +90 -18
- package/src/sync/persistenceGjs.spec.ts +143 -0
- package/src/sync/persistenceNative.spec.ts +139 -0
- package/src/sync/realtime.spec.ts +18 -1
- package/src/sync/realtime.ts +161 -13
- package/src/sync/rehydration.ts +23 -5
- package/src/sync/storage.ts +5 -4
- package/src/sync/subscriptionManager.spec.ts +94 -0
- package/src/sync/subscriptionManager.ts +304 -82
- package/src/sync/syncModule.spec.ts +137 -0
- package/src/sync/types.ts +39 -0
- package/src/sync/virtualPageManager.ts +8 -4
- package/src/useLiveQuery.ts +58 -0
- package/src/util.spec.ts +35 -4
- package/src/util.ts +37 -2
- package/types/auth.d.ts +13 -0
- package/types/auth.d.ts.map +1 -0
- package/types/call.d.ts +10 -0
- package/types/call.d.ts.map +1 -0
- package/types/collection.d.ts +127 -0
- package/types/collection.d.ts.map +1 -0
- package/types/common/types.d.ts +35 -0
- package/types/common/types.d.ts.map +1 -0
- package/types/core/http.d.ts +86 -0
- package/types/core/http.d.ts.map +1 -0
- package/types/core/types.d.ts +74 -0
- package/types/core/types.d.ts.map +1 -0
- package/types/core/wire.d.ts +405 -0
- package/types/core/wire.d.ts.map +1 -0
- package/types/db.d.ts +244 -0
- package/types/db.d.ts.map +1 -0
- package/types/devtools/FrappeDevtoolsPanel.d.ts +7 -0
- package/types/devtools/FrappeDevtoolsPanel.d.ts.map +1 -0
- package/types/devtools/index.d.ts +4 -0
- package/types/devtools/index.d.ts.map +1 -0
- package/types/devtools/plugin.d.ts +9 -0
- package/types/devtools/plugin.d.ts.map +1 -0
- package/types/devtools/theme.d.ts +15 -0
- package/types/devtools/theme.d.ts.map +1 -0
- package/types/doctype.d.ts +256 -0
- package/types/doctype.d.ts.map +1 -0
- package/types/file.d.ts +15 -0
- package/types/file.d.ts.map +1 -0
- package/types/fixtureDb.d.ts +76 -0
- package/types/fixtureDb.d.ts.map +1 -0
- package/types/fixtures.d.ts +55 -0
- package/types/fixtures.d.ts.map +1 -0
- package/types/frappeApp.d.ts +45 -0
- package/types/frappeApp.d.ts.map +1 -0
- package/types/frappeReact.d.ts +270 -0
- package/types/frappeReact.d.ts.map +1 -0
- package/types/index.d.ts +44 -0
- package/types/index.d.ts.map +1 -0
- package/types/optimistic.d.ts +38 -0
- package/types/optimistic.d.ts.map +1 -0
- package/types/pacer.d.ts +193 -0
- package/types/pacer.d.ts.map +1 -0
- package/types/plugin/index.d.ts +11 -0
- package/types/plugin/index.d.ts.map +1 -0
- package/types/realtime.d.ts +121 -0
- package/types/realtime.d.ts.map +1 -0
- package/types/sync/backfill.d.ts +60 -0
- package/types/sync/backfill.d.ts.map +1 -0
- package/types/sync/filters.d.ts +101 -0
- package/types/sync/filters.d.ts.map +1 -0
- package/types/sync/index.d.ts +181 -0
- package/types/sync/index.d.ts.map +1 -0
- package/types/sync/merge.d.ts +59 -0
- package/types/sync/merge.d.ts.map +1 -0
- package/types/sync/mutationEngine.d.ts +117 -0
- package/types/sync/mutationEngine.d.ts.map +1 -0
- package/types/sync/mutationJournal.d.ts +60 -0
- package/types/sync/mutationJournal.d.ts.map +1 -0
- package/types/sync/normalizedCache.d.ts +59 -0
- package/types/sync/normalizedCache.d.ts.map +1 -0
- package/types/sync/persistence.d.ts +185 -0
- package/types/sync/persistence.d.ts.map +1 -0
- package/types/sync/realtime.d.ts +121 -0
- package/types/sync/realtime.d.ts.map +1 -0
- package/types/sync/rehydration.d.ts +109 -0
- package/types/sync/rehydration.d.ts.map +1 -0
- package/types/sync/storage.d.ts +65 -0
- package/types/sync/storage.d.ts.map +1 -0
- package/types/sync/subscriptionManager.d.ts +161 -0
- package/types/sync/subscriptionManager.d.ts.map +1 -0
- package/types/sync/types.d.ts +435 -0
- package/types/sync/types.d.ts.map +1 -0
- package/types/sync/virtualPageManager.d.ts +190 -0
- package/types/sync/virtualPageManager.d.ts.map +1 -0
- package/types/useLiveQuery.d.ts +16 -0
- package/types/useLiveQuery.d.ts.map +1 -0
- package/types/util.d.ts +24 -0
- package/types/util.d.ts.map +1 -0
- package/dist/cjs/auth.spec.cjs +0 -322
- package/dist/cjs/auth.spec.native.js +0 -329
- package/dist/cjs/auth.spec.native.js.map +0 -1
- package/dist/cjs/call.spec.cjs +0 -427
- package/dist/cjs/call.spec.native.js +0 -430
- package/dist/cjs/call.spec.native.js.map +0 -1
- package/dist/cjs/collection.spec.cjs +0 -186
- package/dist/cjs/collection.spec.native.js +0 -216
- package/dist/cjs/collection.spec.native.js.map +0 -1
- package/dist/cjs/common/types.spec.cjs +0 -266
- package/dist/cjs/common/types.spec.native.js +0 -271
- package/dist/cjs/common/types.spec.native.js.map +0 -1
- package/dist/cjs/core/http.spec.cjs +0 -1259
- package/dist/cjs/core/http.spec.native.js +0 -1401
- package/dist/cjs/core/http.spec.native.js.map +0 -1
- package/dist/cjs/core/wire.spec.cjs +0 -478
- package/dist/cjs/core/wire.spec.native.js +0 -482
- package/dist/cjs/core/wire.spec.native.js.map +0 -1
- package/dist/cjs/db.spec.cjs +0 -862
- package/dist/cjs/db.spec.native.js +0 -865
- package/dist/cjs/db.spec.native.js.map +0 -1
- package/dist/cjs/doctype.spec.cjs +0 -460
- package/dist/cjs/doctype.spec.native.js +0 -538
- package/dist/cjs/doctype.spec.native.js.map +0 -1
- package/dist/cjs/file.spec.cjs +0 -315
- package/dist/cjs/file.spec.native.js +0 -342
- package/dist/cjs/file.spec.native.js.map +0 -1
- package/dist/cjs/frappeApp.spec.cjs +0 -306
- package/dist/cjs/frappeApp.spec.native.js +0 -308
- package/dist/cjs/frappeApp.spec.native.js.map +0 -1
- package/dist/cjs/frappeReact.spec.cjs +0 -531
- package/dist/cjs/frappeReact.spec.native.js +0 -670
- package/dist/cjs/frappeReact.spec.native.js.map +0 -1
- package/dist/cjs/optimistic.spec.cjs +0 -11
- package/dist/cjs/optimistic.spec.native.js +0 -19
- package/dist/cjs/optimistic.spec.native.js.map +0 -1
- package/dist/cjs/pacer.spec.cjs +0 -470
- package/dist/cjs/pacer.spec.native.js +0 -537
- package/dist/cjs/pacer.spec.native.js.map +0 -1
- package/dist/cjs/realtime.spec.cjs +0 -326
- package/dist/cjs/realtime.spec.native.js +0 -392
- package/dist/cjs/realtime.spec.native.js.map +0 -1
- package/dist/cjs/sync/backfill.spec.cjs +0 -586
- package/dist/cjs/sync/backfill.spec.native.js +0 -712
- package/dist/cjs/sync/backfill.spec.native.js.map +0 -1
- package/dist/cjs/sync/debug.spec.cjs +0 -125
- package/dist/cjs/sync/debug.spec.native.js +0 -133
- package/dist/cjs/sync/debug.spec.native.js.map +0 -1
- package/dist/cjs/sync/filters.spec.cjs +0 -168
- package/dist/cjs/sync/filters.spec.native.js +0 -173
- package/dist/cjs/sync/filters.spec.native.js.map +0 -1
- package/dist/cjs/sync/merge.spec.cjs +0 -908
- package/dist/cjs/sync/merge.spec.native.js +0 -937
- package/dist/cjs/sync/merge.spec.native.js.map +0 -1
- package/dist/cjs/sync/multiOrderBy.spec.cjs +0 -165
- package/dist/cjs/sync/multiOrderBy.spec.native.js +0 -229
- package/dist/cjs/sync/multiOrderBy.spec.native.js.map +0 -1
- package/dist/cjs/sync/mutationEngine.spec.cjs +0 -1158
- package/dist/cjs/sync/mutationEngine.spec.native.js +0 -1173
- package/dist/cjs/sync/mutationEngine.spec.native.js.map +0 -1
- package/dist/cjs/sync/mutationJournal.spec.cjs +0 -330
- package/dist/cjs/sync/mutationJournal.spec.native.js +0 -333
- package/dist/cjs/sync/mutationJournal.spec.native.js.map +0 -1
- package/dist/cjs/sync/mutations.spec.cjs +0 -327
- package/dist/cjs/sync/mutations.spec.native.js +0 -330
- package/dist/cjs/sync/mutations.spec.native.js.map +0 -1
- package/dist/cjs/sync/normalizedCache.spec.cjs +0 -302
- package/dist/cjs/sync/normalizedCache.spec.native.js +0 -311
- package/dist/cjs/sync/normalizedCache.spec.native.js.map +0 -1
- package/dist/cjs/sync/persistence.spec.cjs +0 -562
- package/dist/cjs/sync/persistence.spec.native.js +0 -572
- package/dist/cjs/sync/persistence.spec.native.js.map +0 -1
- package/dist/cjs/sync/realtime.spec.cjs +0 -499
- package/dist/cjs/sync/realtime.spec.native.js +0 -512
- package/dist/cjs/sync/realtime.spec.native.js.map +0 -1
- package/dist/cjs/sync/rehydration.spec.cjs +0 -731
- package/dist/cjs/sync/rehydration.spec.native.js +0 -736
- package/dist/cjs/sync/rehydration.spec.native.js.map +0 -1
- package/dist/cjs/sync/storage.spec.cjs +0 -446
- package/dist/cjs/sync/storage.spec.native.js +0 -470
- package/dist/cjs/sync/storage.spec.native.js.map +0 -1
- package/dist/cjs/sync/subscriptionManager.spec.cjs +0 -1102
- package/dist/cjs/sync/subscriptionManager.spec.native.js +0 -1136
- package/dist/cjs/sync/subscriptionManager.spec.native.js.map +0 -1
- package/dist/cjs/sync/subscriptions.spec.cjs +0 -937
- package/dist/cjs/sync/subscriptions.spec.native.js +0 -969
- package/dist/cjs/sync/subscriptions.spec.native.js.map +0 -1
- package/dist/cjs/sync/syncModule.spec.cjs +0 -206
- package/dist/cjs/sync/syncModule.spec.native.js +0 -222
- package/dist/cjs/sync/syncModule.spec.native.js.map +0 -1
- package/dist/cjs/sync/types.spec.cjs +0 -246
- package/dist/cjs/sync/types.spec.native.js +0 -256
- package/dist/cjs/sync/types.spec.native.js.map +0 -1
- package/dist/cjs/sync/virtualPageManager.spec.cjs +0 -801
- package/dist/cjs/sync/virtualPageManager.spec.native.js +0 -873
- package/dist/cjs/sync/virtualPageManager.spec.native.js.map +0 -1
- package/dist/cjs/util.spec.cjs +0 -43
- package/dist/cjs/util.spec.native.js +0 -48
- package/dist/cjs/util.spec.native.js.map +0 -1
- package/dist/esm/auth.spec.mjs +0 -323
- package/dist/esm/auth.spec.mjs.map +0 -1
- package/dist/esm/auth.spec.native.js +0 -327
- package/dist/esm/auth.spec.native.js.map +0 -1
- package/dist/esm/call.spec.mjs +0 -428
- package/dist/esm/call.spec.mjs.map +0 -1
- package/dist/esm/call.spec.native.js +0 -428
- package/dist/esm/call.spec.native.js.map +0 -1
- package/dist/esm/collection.spec.mjs +0 -187
- package/dist/esm/collection.spec.mjs.map +0 -1
- package/dist/esm/collection.spec.native.js +0 -214
- package/dist/esm/collection.spec.native.js.map +0 -1
- package/dist/esm/common/types.spec.mjs +0 -267
- package/dist/esm/common/types.spec.mjs.map +0 -1
- package/dist/esm/common/types.spec.native.js +0 -269
- package/dist/esm/common/types.spec.native.js.map +0 -1
- package/dist/esm/core/http.spec.mjs +0 -1260
- package/dist/esm/core/http.spec.mjs.map +0 -1
- package/dist/esm/core/http.spec.native.js +0 -1399
- package/dist/esm/core/http.spec.native.js.map +0 -1
- package/dist/esm/core/wire.spec.mjs +0 -479
- package/dist/esm/core/wire.spec.mjs.map +0 -1
- package/dist/esm/core/wire.spec.native.js +0 -480
- package/dist/esm/core/wire.spec.native.js.map +0 -1
- package/dist/esm/db.spec.mjs +0 -863
- package/dist/esm/db.spec.mjs.map +0 -1
- package/dist/esm/db.spec.native.js +0 -863
- package/dist/esm/db.spec.native.js.map +0 -1
- package/dist/esm/doctype.spec.mjs +0 -461
- package/dist/esm/doctype.spec.mjs.map +0 -1
- package/dist/esm/doctype.spec.native.js +0 -536
- package/dist/esm/doctype.spec.native.js.map +0 -1
- package/dist/esm/file.spec.mjs +0 -316
- package/dist/esm/file.spec.mjs.map +0 -1
- package/dist/esm/file.spec.native.js +0 -340
- package/dist/esm/file.spec.native.js.map +0 -1
- package/dist/esm/frappeApp.spec.mjs +0 -307
- package/dist/esm/frappeApp.spec.mjs.map +0 -1
- package/dist/esm/frappeApp.spec.native.js +0 -306
- package/dist/esm/frappeApp.spec.native.js.map +0 -1
- package/dist/esm/frappeReact.spec.mjs +0 -532
- package/dist/esm/frappeReact.spec.mjs.map +0 -1
- package/dist/esm/frappeReact.spec.native.js +0 -668
- package/dist/esm/frappeReact.spec.native.js.map +0 -1
- package/dist/esm/optimistic.spec.mjs +0 -12
- package/dist/esm/optimistic.spec.mjs.map +0 -1
- package/dist/esm/optimistic.spec.native.js +0 -17
- package/dist/esm/optimistic.spec.native.js.map +0 -1
- package/dist/esm/pacer.spec.mjs +0 -447
- package/dist/esm/pacer.spec.mjs.map +0 -1
- package/dist/esm/pacer.spec.native.js +0 -511
- package/dist/esm/pacer.spec.native.js.map +0 -1
- package/dist/esm/realtime.spec.mjs +0 -327
- package/dist/esm/realtime.spec.mjs.map +0 -1
- package/dist/esm/realtime.spec.native.js +0 -390
- package/dist/esm/realtime.spec.native.js.map +0 -1
- package/dist/esm/sync/backfill.spec.mjs +0 -563
- package/dist/esm/sync/backfill.spec.mjs.map +0 -1
- package/dist/esm/sync/backfill.spec.native.js +0 -686
- package/dist/esm/sync/backfill.spec.native.js.map +0 -1
- package/dist/esm/sync/debug.spec.mjs +0 -102
- package/dist/esm/sync/debug.spec.mjs.map +0 -1
- package/dist/esm/sync/debug.spec.native.js +0 -107
- package/dist/esm/sync/debug.spec.native.js.map +0 -1
- package/dist/esm/sync/filters.spec.mjs +0 -169
- package/dist/esm/sync/filters.spec.mjs.map +0 -1
- package/dist/esm/sync/filters.spec.native.js +0 -171
- package/dist/esm/sync/filters.spec.native.js.map +0 -1
- package/dist/esm/sync/merge.spec.mjs +0 -909
- package/dist/esm/sync/merge.spec.mjs.map +0 -1
- package/dist/esm/sync/merge.spec.native.js +0 -935
- package/dist/esm/sync/merge.spec.native.js.map +0 -1
- package/dist/esm/sync/multiOrderBy.spec.mjs +0 -166
- package/dist/esm/sync/multiOrderBy.spec.mjs.map +0 -1
- package/dist/esm/sync/multiOrderBy.spec.native.js +0 -227
- package/dist/esm/sync/multiOrderBy.spec.native.js.map +0 -1
- package/dist/esm/sync/mutationEngine.spec.mjs +0 -1159
- package/dist/esm/sync/mutationEngine.spec.mjs.map +0 -1
- package/dist/esm/sync/mutationEngine.spec.native.js +0 -1171
- package/dist/esm/sync/mutationEngine.spec.native.js.map +0 -1
- package/dist/esm/sync/mutationJournal.spec.mjs +0 -331
- package/dist/esm/sync/mutationJournal.spec.mjs.map +0 -1
- package/dist/esm/sync/mutationJournal.spec.native.js +0 -331
- package/dist/esm/sync/mutationJournal.spec.native.js.map +0 -1
- package/dist/esm/sync/mutations.spec.mjs +0 -328
- package/dist/esm/sync/mutations.spec.mjs.map +0 -1
- package/dist/esm/sync/mutations.spec.native.js +0 -328
- package/dist/esm/sync/mutations.spec.native.js.map +0 -1
- package/dist/esm/sync/normalizedCache.spec.mjs +0 -303
- package/dist/esm/sync/normalizedCache.spec.mjs.map +0 -1
- package/dist/esm/sync/normalizedCache.spec.native.js +0 -309
- package/dist/esm/sync/normalizedCache.spec.native.js.map +0 -1
- package/dist/esm/sync/persistence.spec.mjs +0 -563
- package/dist/esm/sync/persistence.spec.mjs.map +0 -1
- package/dist/esm/sync/persistence.spec.native.js +0 -570
- package/dist/esm/sync/persistence.spec.native.js.map +0 -1
- package/dist/esm/sync/realtime.spec.mjs +0 -500
- package/dist/esm/sync/realtime.spec.mjs.map +0 -1
- package/dist/esm/sync/realtime.spec.native.js +0 -510
- package/dist/esm/sync/realtime.spec.native.js.map +0 -1
- package/dist/esm/sync/rehydration.spec.mjs +0 -732
- package/dist/esm/sync/rehydration.spec.mjs.map +0 -1
- package/dist/esm/sync/rehydration.spec.native.js +0 -734
- package/dist/esm/sync/rehydration.spec.native.js.map +0 -1
- package/dist/esm/sync/storage.spec.mjs +0 -423
- package/dist/esm/sync/storage.spec.mjs.map +0 -1
- package/dist/esm/sync/storage.spec.native.js +0 -444
- package/dist/esm/sync/storage.spec.native.js.map +0 -1
- package/dist/esm/sync/subscriptionManager.spec.mjs +0 -1079
- package/dist/esm/sync/subscriptionManager.spec.mjs.map +0 -1
- package/dist/esm/sync/subscriptionManager.spec.native.js +0 -1110
- package/dist/esm/sync/subscriptionManager.spec.native.js.map +0 -1
- package/dist/esm/sync/subscriptions.spec.mjs +0 -914
- package/dist/esm/sync/subscriptions.spec.mjs.map +0 -1
- package/dist/esm/sync/subscriptions.spec.native.js +0 -943
- package/dist/esm/sync/subscriptions.spec.native.js.map +0 -1
- package/dist/esm/sync/syncModule.spec.mjs +0 -207
- package/dist/esm/sync/syncModule.spec.mjs.map +0 -1
- package/dist/esm/sync/syncModule.spec.native.js +0 -220
- package/dist/esm/sync/syncModule.spec.native.js.map +0 -1
- package/dist/esm/sync/types.spec.mjs +0 -247
- package/dist/esm/sync/types.spec.mjs.map +0 -1
- package/dist/esm/sync/types.spec.native.js +0 -254
- package/dist/esm/sync/types.spec.native.js.map +0 -1
- package/dist/esm/sync/virtualPageManager.spec.mjs +0 -802
- package/dist/esm/sync/virtualPageManager.spec.mjs.map +0 -1
- package/dist/esm/sync/virtualPageManager.spec.native.js +0 -871
- package/dist/esm/sync/virtualPageManager.spec.native.js.map +0 -1
- package/dist/esm/util.spec.mjs +0 -20
- package/dist/esm/util.spec.mjs.map +0 -1
- package/dist/esm/util.spec.native.js +0 -22
- package/dist/esm/util.spec.native.js.map +0 -1
- package/dist/jsx/auth.spec.mjs +0 -323
- package/dist/jsx/auth.spec.mjs.map +0 -1
- package/dist/jsx/auth.spec.native.js +0 -329
- package/dist/jsx/auth.spec.native.js.map +0 -1
- package/dist/jsx/call.spec.mjs +0 -428
- package/dist/jsx/call.spec.mjs.map +0 -1
- package/dist/jsx/call.spec.native.js +0 -430
- package/dist/jsx/call.spec.native.js.map +0 -1
- package/dist/jsx/collection.spec.mjs +0 -187
- package/dist/jsx/collection.spec.mjs.map +0 -1
- package/dist/jsx/collection.spec.native.js +0 -216
- package/dist/jsx/collection.spec.native.js.map +0 -1
- package/dist/jsx/common/types.spec.mjs +0 -267
- package/dist/jsx/common/types.spec.mjs.map +0 -1
- package/dist/jsx/common/types.spec.native.js +0 -271
- package/dist/jsx/common/types.spec.native.js.map +0 -1
- package/dist/jsx/core/http.spec.mjs +0 -1260
- package/dist/jsx/core/http.spec.mjs.map +0 -1
- package/dist/jsx/core/http.spec.native.js +0 -1401
- package/dist/jsx/core/http.spec.native.js.map +0 -1
- package/dist/jsx/core/wire.spec.mjs +0 -479
- package/dist/jsx/core/wire.spec.mjs.map +0 -1
- package/dist/jsx/core/wire.spec.native.js +0 -482
- package/dist/jsx/core/wire.spec.native.js.map +0 -1
- package/dist/jsx/db.spec.mjs +0 -863
- package/dist/jsx/db.spec.mjs.map +0 -1
- package/dist/jsx/db.spec.native.js +0 -865
- package/dist/jsx/db.spec.native.js.map +0 -1
- package/dist/jsx/doctype.spec.mjs +0 -461
- package/dist/jsx/doctype.spec.mjs.map +0 -1
- package/dist/jsx/doctype.spec.native.js +0 -538
- package/dist/jsx/doctype.spec.native.js.map +0 -1
- package/dist/jsx/file.spec.mjs +0 -316
- package/dist/jsx/file.spec.mjs.map +0 -1
- package/dist/jsx/file.spec.native.js +0 -342
- package/dist/jsx/file.spec.native.js.map +0 -1
- package/dist/jsx/frappeApp.spec.mjs +0 -307
- package/dist/jsx/frappeApp.spec.mjs.map +0 -1
- package/dist/jsx/frappeApp.spec.native.js +0 -308
- package/dist/jsx/frappeApp.spec.native.js.map +0 -1
- package/dist/jsx/frappeReact.spec.mjs +0 -532
- package/dist/jsx/frappeReact.spec.mjs.map +0 -1
- package/dist/jsx/frappeReact.spec.native.js +0 -670
- package/dist/jsx/frappeReact.spec.native.js.map +0 -1
- package/dist/jsx/optimistic.spec.mjs +0 -12
- package/dist/jsx/optimistic.spec.mjs.map +0 -1
- package/dist/jsx/optimistic.spec.native.js +0 -19
- package/dist/jsx/optimistic.spec.native.js.map +0 -1
- package/dist/jsx/pacer.spec.mjs +0 -447
- package/dist/jsx/pacer.spec.mjs.map +0 -1
- package/dist/jsx/pacer.spec.native.js +0 -537
- package/dist/jsx/pacer.spec.native.js.map +0 -1
- package/dist/jsx/realtime.spec.mjs +0 -327
- package/dist/jsx/realtime.spec.mjs.map +0 -1
- package/dist/jsx/realtime.spec.native.js +0 -392
- package/dist/jsx/realtime.spec.native.js.map +0 -1
- package/dist/jsx/sync/backfill.spec.mjs +0 -563
- package/dist/jsx/sync/backfill.spec.mjs.map +0 -1
- package/dist/jsx/sync/backfill.spec.native.js +0 -712
- package/dist/jsx/sync/backfill.spec.native.js.map +0 -1
- package/dist/jsx/sync/debug.spec.mjs +0 -102
- package/dist/jsx/sync/debug.spec.mjs.map +0 -1
- package/dist/jsx/sync/debug.spec.native.js +0 -133
- package/dist/jsx/sync/debug.spec.native.js.map +0 -1
- package/dist/jsx/sync/filters.spec.mjs +0 -169
- package/dist/jsx/sync/filters.spec.mjs.map +0 -1
- package/dist/jsx/sync/filters.spec.native.js +0 -173
- package/dist/jsx/sync/filters.spec.native.js.map +0 -1
- package/dist/jsx/sync/merge.spec.mjs +0 -909
- package/dist/jsx/sync/merge.spec.mjs.map +0 -1
- package/dist/jsx/sync/merge.spec.native.js +0 -937
- package/dist/jsx/sync/merge.spec.native.js.map +0 -1
- package/dist/jsx/sync/multiOrderBy.spec.mjs +0 -166
- package/dist/jsx/sync/multiOrderBy.spec.mjs.map +0 -1
- package/dist/jsx/sync/multiOrderBy.spec.native.js +0 -229
- package/dist/jsx/sync/multiOrderBy.spec.native.js.map +0 -1
- package/dist/jsx/sync/mutationEngine.spec.mjs +0 -1159
- package/dist/jsx/sync/mutationEngine.spec.mjs.map +0 -1
- package/dist/jsx/sync/mutationEngine.spec.native.js +0 -1173
- package/dist/jsx/sync/mutationEngine.spec.native.js.map +0 -1
- package/dist/jsx/sync/mutationJournal.spec.mjs +0 -331
- package/dist/jsx/sync/mutationJournal.spec.mjs.map +0 -1
- package/dist/jsx/sync/mutationJournal.spec.native.js +0 -333
- package/dist/jsx/sync/mutationJournal.spec.native.js.map +0 -1
- package/dist/jsx/sync/mutations.spec.mjs +0 -328
- package/dist/jsx/sync/mutations.spec.mjs.map +0 -1
- package/dist/jsx/sync/mutations.spec.native.js +0 -330
- package/dist/jsx/sync/mutations.spec.native.js.map +0 -1
- package/dist/jsx/sync/normalizedCache.spec.mjs +0 -303
- package/dist/jsx/sync/normalizedCache.spec.mjs.map +0 -1
- package/dist/jsx/sync/normalizedCache.spec.native.js +0 -311
- package/dist/jsx/sync/normalizedCache.spec.native.js.map +0 -1
- package/dist/jsx/sync/persistence.spec.mjs +0 -563
- package/dist/jsx/sync/persistence.spec.mjs.map +0 -1
- package/dist/jsx/sync/persistence.spec.native.js +0 -572
- package/dist/jsx/sync/persistence.spec.native.js.map +0 -1
- package/dist/jsx/sync/realtime.spec.mjs +0 -500
- package/dist/jsx/sync/realtime.spec.mjs.map +0 -1
- package/dist/jsx/sync/realtime.spec.native.js +0 -512
- package/dist/jsx/sync/realtime.spec.native.js.map +0 -1
- package/dist/jsx/sync/rehydration.spec.mjs +0 -732
- package/dist/jsx/sync/rehydration.spec.mjs.map +0 -1
- package/dist/jsx/sync/rehydration.spec.native.js +0 -736
- package/dist/jsx/sync/rehydration.spec.native.js.map +0 -1
- package/dist/jsx/sync/storage.spec.mjs +0 -423
- package/dist/jsx/sync/storage.spec.mjs.map +0 -1
- package/dist/jsx/sync/storage.spec.native.js +0 -470
- package/dist/jsx/sync/storage.spec.native.js.map +0 -1
- package/dist/jsx/sync/subscriptionManager.spec.mjs +0 -1079
- package/dist/jsx/sync/subscriptionManager.spec.mjs.map +0 -1
- package/dist/jsx/sync/subscriptionManager.spec.native.js +0 -1136
- package/dist/jsx/sync/subscriptionManager.spec.native.js.map +0 -1
- package/dist/jsx/sync/subscriptions.spec.mjs +0 -914
- package/dist/jsx/sync/subscriptions.spec.mjs.map +0 -1
- package/dist/jsx/sync/subscriptions.spec.native.js +0 -969
- package/dist/jsx/sync/subscriptions.spec.native.js.map +0 -1
- package/dist/jsx/sync/syncModule.spec.mjs +0 -207
- package/dist/jsx/sync/syncModule.spec.mjs.map +0 -1
- package/dist/jsx/sync/syncModule.spec.native.js +0 -222
- package/dist/jsx/sync/syncModule.spec.native.js.map +0 -1
- package/dist/jsx/sync/types.spec.mjs +0 -247
- package/dist/jsx/sync/types.spec.mjs.map +0 -1
- package/dist/jsx/sync/types.spec.native.js +0 -256
- package/dist/jsx/sync/types.spec.native.js.map +0 -1
- package/dist/jsx/sync/virtualPageManager.spec.mjs +0 -802
- package/dist/jsx/sync/virtualPageManager.spec.mjs.map +0 -1
- package/dist/jsx/sync/virtualPageManager.spec.native.js +0 -873
- package/dist/jsx/sync/virtualPageManager.spec.native.js.map +0 -1
- package/dist/jsx/util.spec.mjs +0 -20
- package/dist/jsx/util.spec.mjs.map +0 -1
- package/dist/jsx/util.spec.native.js +0 -48
- package/dist/jsx/util.spec.native.js.map +0 -1
|
@@ -67,6 +67,108 @@ describe("NormalizedCache", () => {
|
|
|
67
67
|
expect(Object.keys(cache.state.Task.byId)).toHaveLength(0);
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
+
it("should preserve unprojected fields on narrow-projection upsert", () => {
|
|
71
|
+
const fullDoc = {
|
|
72
|
+
name: "TASK-001",
|
|
73
|
+
doctype: "Task",
|
|
74
|
+
title: "Test Task",
|
|
75
|
+
status: "Open",
|
|
76
|
+
description: "Long description",
|
|
77
|
+
owner: "user@example.com",
|
|
78
|
+
};
|
|
79
|
+
const narrowDoc = {
|
|
80
|
+
name: "TASK-001",
|
|
81
|
+
doctype: "Task",
|
|
82
|
+
title: "Renamed Task",
|
|
83
|
+
};
|
|
84
|
+
cache.upsert(fullDoc);
|
|
85
|
+
cache.upsert(narrowDoc);
|
|
86
|
+
const retrieved = cache.get({ doctype: "Task", name: "TASK-001" });
|
|
87
|
+
expect(retrieved).toEqual({
|
|
88
|
+
name: "TASK-001",
|
|
89
|
+
doctype: "Task",
|
|
90
|
+
title: "Renamed Task",
|
|
91
|
+
status: "Open",
|
|
92
|
+
description: "Long description",
|
|
93
|
+
owner: "user@example.com",
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should overwrite a field present with null (cleared server-side)", () => {
|
|
98
|
+
const fullDoc = {
|
|
99
|
+
name: "TASK-001",
|
|
100
|
+
doctype: "Task",
|
|
101
|
+
title: "Test Task",
|
|
102
|
+
status: "Open",
|
|
103
|
+
description: "Long description",
|
|
104
|
+
};
|
|
105
|
+
const clearedDoc = {
|
|
106
|
+
name: "TASK-001",
|
|
107
|
+
doctype: "Task",
|
|
108
|
+
description: null,
|
|
109
|
+
} as any;
|
|
110
|
+
cache.upsert(fullDoc);
|
|
111
|
+
cache.upsert(clearedDoc);
|
|
112
|
+
const retrieved = cache.get({ doctype: "Task", name: "TASK-001" });
|
|
113
|
+
expect(retrieved?.description).toBeNull();
|
|
114
|
+
expect(retrieved?.title).toBe("Test Task");
|
|
115
|
+
expect(retrieved?.status).toBe("Open");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("should replace values present on a full-doc upsert", () => {
|
|
119
|
+
const originalDoc = {
|
|
120
|
+
name: "TASK-001",
|
|
121
|
+
doctype: "Task",
|
|
122
|
+
title: "Original Task",
|
|
123
|
+
status: "Open",
|
|
124
|
+
description: "Original description",
|
|
125
|
+
};
|
|
126
|
+
const fullUpdate = {
|
|
127
|
+
name: "TASK-001",
|
|
128
|
+
doctype: "Task",
|
|
129
|
+
title: "Updated Task",
|
|
130
|
+
status: "Closed",
|
|
131
|
+
description: "",
|
|
132
|
+
};
|
|
133
|
+
cache.upsert(originalDoc);
|
|
134
|
+
cache.upsert(fullUpdate);
|
|
135
|
+
const retrieved = cache.get({ doctype: "Task", name: "TASK-001" });
|
|
136
|
+
expect(retrieved).toEqual(fullUpdate);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should drop fields absent from the incoming doc when replace is true", () => {
|
|
140
|
+
const optimisticDoc = {
|
|
141
|
+
name: "TASK-001",
|
|
142
|
+
doctype: "Task",
|
|
143
|
+
title: "Optimistic Task",
|
|
144
|
+
status: "Open",
|
|
145
|
+
extraField: "added optimistically",
|
|
146
|
+
};
|
|
147
|
+
const snapshot = {
|
|
148
|
+
name: "TASK-001",
|
|
149
|
+
doctype: "Task",
|
|
150
|
+
title: "Snapshot Task",
|
|
151
|
+
status: "Open",
|
|
152
|
+
};
|
|
153
|
+
cache.upsert(optimisticDoc);
|
|
154
|
+
cache.upsert(snapshot, { replace: true });
|
|
155
|
+
const retrieved = cache.get({ doctype: "Task", name: "TASK-001" });
|
|
156
|
+
expect(retrieved).toEqual(snapshot);
|
|
157
|
+
expect(retrieved).not.toHaveProperty("extraField");
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("should not mutate the previously cached object when merging", () => {
|
|
161
|
+
const originalDoc = {
|
|
162
|
+
name: "TASK-001",
|
|
163
|
+
doctype: "Task",
|
|
164
|
+
title: "Original Task",
|
|
165
|
+
status: "Open",
|
|
166
|
+
};
|
|
167
|
+
cache.upsert(originalDoc);
|
|
168
|
+
cache.upsert({ name: "TASK-001", doctype: "Task", title: "Updated" });
|
|
169
|
+
expect(originalDoc.title).toBe("Original Task");
|
|
170
|
+
});
|
|
171
|
+
|
|
70
172
|
it("should handle multiple doctypes", () => {
|
|
71
173
|
const task = {
|
|
72
174
|
name: "TASK-001",
|
|
@@ -12,6 +12,15 @@ export interface NormalizedCacheOptions {
|
|
|
12
12
|
onEvict?: (doctype: string, name: string) => void;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export interface UpsertOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Replace the cached document wholesale instead of merging fields.
|
|
18
|
+
* Use when the incoming doc is authoritative for its entire shape
|
|
19
|
+
* (e.g. restoring a rollback snapshot).
|
|
20
|
+
*/
|
|
21
|
+
replace?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
15
24
|
/**
|
|
16
25
|
* Normalized cache with optional LRU eviction.
|
|
17
26
|
*
|
|
@@ -43,7 +52,7 @@ export class NormalizedCache {
|
|
|
43
52
|
};
|
|
44
53
|
}
|
|
45
54
|
|
|
46
|
-
upsert<Data extends FrappeDocData>(doc: FrappeDoc<Data
|
|
55
|
+
upsert<Data extends FrappeDocData>(doc: FrappeDoc<Data>, options: UpsertOptions = {}) {
|
|
47
56
|
let bucket = this.state[doc.doctype];
|
|
48
57
|
if (!bucket) {
|
|
49
58
|
bucket = { byId: {}, allIds: [] };
|
|
@@ -52,11 +61,18 @@ export class NormalizedCache {
|
|
|
52
61
|
const id = doc?.name;
|
|
53
62
|
if (!id) return;
|
|
54
63
|
|
|
55
|
-
const
|
|
64
|
+
const existing = bucket.byId[id];
|
|
65
|
+
const isNew = !existing;
|
|
56
66
|
if (isNew) {
|
|
57
67
|
bucket.allIds.push(id);
|
|
58
68
|
}
|
|
59
|
-
|
|
69
|
+
// Shallow field merge: only keys PRESENT on the incoming doc overwrite the
|
|
70
|
+
// cached entry, so a narrow-fields fetch (projection) cannot strip fields
|
|
71
|
+
// other live views depend on. A key present with null/"" (genuinely
|
|
72
|
+
// cleared server-side) still overwrites; a key absent from the projection
|
|
73
|
+
// is preserved. Pass `replace: true` for wholesale replacement.
|
|
74
|
+
bucket.byId[id] =
|
|
75
|
+
existing && !options.replace ? ({ ...existing, ...doc } as FrappeDoc<FrappeDocData>) : doc;
|
|
60
76
|
|
|
61
77
|
// Update access time
|
|
62
78
|
const key = this.makeKey(doc.doctype, id);
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cold-offline restore behavior: persisted snapshots must serve reads after a
|
|
3
|
+
* reload with no network (cache-first subscribe with re-adoption), restored
|
|
4
|
+
* subscriptions must not accumulate across reloads (adoption + TTL GC), and
|
|
5
|
+
* queued mutations must replay on app focus.
|
|
6
|
+
*
|
|
7
|
+
* These specs simulate "reloads" by creating successive SyncModule instances
|
|
8
|
+
* that share one in-memory KVStorage (standing in for IndexedDB/MMKV).
|
|
9
|
+
*/
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
11
|
+
import { SyncModule } from "./index";
|
|
12
|
+
import { BackfillScope, Operation } from "./types";
|
|
13
|
+
import type { KVStorage, SubscriptionQuery } from "./types";
|
|
14
|
+
|
|
15
|
+
/** In-memory KVStorage that survives across simulated reloads. */
|
|
16
|
+
class MemoryKV implements KVStorage {
|
|
17
|
+
store = new Map<string, string>();
|
|
18
|
+
async getItem(key: string) {
|
|
19
|
+
return this.store.get(key) ?? null;
|
|
20
|
+
}
|
|
21
|
+
async setItem(key: string, value: string) {
|
|
22
|
+
this.store.set(key, value);
|
|
23
|
+
}
|
|
24
|
+
async removeItem(key: string) {
|
|
25
|
+
this.store.delete(key);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const PERSIST_KEY = "offline-restore-test";
|
|
30
|
+
|
|
31
|
+
const seedDocs = [
|
|
32
|
+
{ name: "t1", doctype: "ToDo", modified: "2024-01-01T10:00:00", description: "one" },
|
|
33
|
+
{ name: "t2", doctype: "ToDo", modified: "2024-01-01T11:00:00", description: "two" },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
// Keep the literal shape/key-order identical everywhere: query-key matching
|
|
37
|
+
// (re-adoption) relies on stable JSON serialization of the query object.
|
|
38
|
+
const todoQuery: SubscriptionQuery = { doctype: "ToDo", fields: ["description"] };
|
|
39
|
+
|
|
40
|
+
function createMockDb() {
|
|
41
|
+
return {
|
|
42
|
+
getDoc: vi.fn().mockResolvedValue(seedDocs[0]),
|
|
43
|
+
getDocList: vi.fn().mockResolvedValue(seedDocs),
|
|
44
|
+
createDoc: vi.fn().mockResolvedValue(seedDocs[0]),
|
|
45
|
+
updateDoc: vi.fn().mockResolvedValue(seedDocs[0]),
|
|
46
|
+
deleteDoc: vi.fn().mockResolvedValue({}),
|
|
47
|
+
backfill: vi.fn().mockResolvedValue({ rows: [], checkpoint: "2024-01-02T00:00:00" }),
|
|
48
|
+
} as any;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function snapshotFromStorage(kv: MemoryKV) {
|
|
52
|
+
const raw = kv.store.get(PERSIST_KEY);
|
|
53
|
+
return raw ? JSON.parse(raw) : undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
describe("offline restore (persistKey)", () => {
|
|
57
|
+
let modules: SyncModule[];
|
|
58
|
+
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
vi.useFakeTimers();
|
|
61
|
+
modules = [];
|
|
62
|
+
localStorage.clear();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
afterEach(async () => {
|
|
66
|
+
for (const sync of modules) await sync.dispose();
|
|
67
|
+
vi.useRealTimers();
|
|
68
|
+
vi.restoreAllMocks();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
function createSync(db: any, options: Record<string, unknown> = {}) {
|
|
72
|
+
const sync = new SyncModule(db, undefined, options);
|
|
73
|
+
modules.push(sync);
|
|
74
|
+
return sync;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Flushes the 50ms debounced persistence save. */
|
|
78
|
+
async function flushSave() {
|
|
79
|
+
await vi.advanceTimersByTimeAsync(60);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Session 1: subscribe online and persist a snapshot into `kv`. */
|
|
83
|
+
async function seedSnapshot(kv: MemoryKV) {
|
|
84
|
+
const db = createMockDb();
|
|
85
|
+
const sync = createSync(db, { persistKey: PERSIST_KEY, storage: kv });
|
|
86
|
+
const result = await sync.subscribe(todoQuery);
|
|
87
|
+
await flushSave();
|
|
88
|
+
await sync.dispose();
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
describe("cold-offline reads (cache-first subscribe)", () => {
|
|
93
|
+
it("serves restored cache when the reload is offline, keeps checkpoint, and marks the sub stale", async () => {
|
|
94
|
+
const kv = new MemoryKV();
|
|
95
|
+
const first = await seedSnapshot(kv);
|
|
96
|
+
expect(snapshotFromStorage(kv).subs).toHaveLength(1);
|
|
97
|
+
|
|
98
|
+
// Cold reload with no network: every fetch fails
|
|
99
|
+
const offlineDb = createMockDb();
|
|
100
|
+
offlineDb.getDocList.mockRejectedValue(new Error("network down"));
|
|
101
|
+
const sync = createSync(offlineDb, { persistKey: PERSIST_KEY, storage: kv });
|
|
102
|
+
|
|
103
|
+
const result = await sync.subscribe(todoQuery);
|
|
104
|
+
|
|
105
|
+
// The restored subscription was adopted, not replaced
|
|
106
|
+
expect(result.subscriptionId).toBe(first.subscriptionId);
|
|
107
|
+
expect(result.checkpoint).toBe(first.checkpoint);
|
|
108
|
+
// Cached rows render immediately
|
|
109
|
+
expect(result.rows.map((row) => row.name)).toEqual(["t1", "t2"]);
|
|
110
|
+
expect((result.rows[0] as any).description).toBe("one");
|
|
111
|
+
|
|
112
|
+
// The background refresh fails without rejecting and flags staleness
|
|
113
|
+
const refresh = await result.refresh!;
|
|
114
|
+
expect(refresh.ok).toBe(false);
|
|
115
|
+
// The cached membership keeps serving after the failed refresh
|
|
116
|
+
expect(sync.getDocsForSubscription(result.subscriptionId).map((row) => row.name)).toEqual([
|
|
117
|
+
"t1",
|
|
118
|
+
"t2",
|
|
119
|
+
]);
|
|
120
|
+
const sub = sync.getSubscription(result.subscriptionId);
|
|
121
|
+
expect(sub?.stale).toBe(true);
|
|
122
|
+
// Restored CDC checkpoint is preserved for the next backfill drain
|
|
123
|
+
expect(sub?.checkpoint).toBe(first.checkpoint);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("catches up from the restored checkpoint on the next backfill trigger and clears stale", async () => {
|
|
127
|
+
const kv = new MemoryKV();
|
|
128
|
+
const first = await seedSnapshot(kv);
|
|
129
|
+
|
|
130
|
+
const offlineDb = createMockDb();
|
|
131
|
+
offlineDb.getDocList.mockRejectedValue(new Error("network down"));
|
|
132
|
+
const sync = createSync(offlineDb, { persistKey: PERSIST_KEY, storage: kv });
|
|
133
|
+
const result = await sync.subscribe(todoQuery);
|
|
134
|
+
await result.refresh!;
|
|
135
|
+
expect(sync.getSubscription(result.subscriptionId)?.stale).toBe(true);
|
|
136
|
+
|
|
137
|
+
// Network returns: the CDC drain resumes from the restored checkpoint
|
|
138
|
+
offlineDb.backfill.mockResolvedValue({
|
|
139
|
+
rows: [
|
|
140
|
+
{ name: "t3", doctype: "ToDo", modified: "2024-01-01T12:00:00", description: "three" },
|
|
141
|
+
],
|
|
142
|
+
deleted: [],
|
|
143
|
+
checkpoint: "2024-01-01T12:00:00|t3",
|
|
144
|
+
has_more: false,
|
|
145
|
+
});
|
|
146
|
+
await sync.backfill({ scope: BackfillScope.All });
|
|
147
|
+
|
|
148
|
+
expect(offlineDb.backfill).toHaveBeenCalledWith(
|
|
149
|
+
expect.objectContaining({ doctype: "ToDo", modifiedAfter: first.checkpoint }),
|
|
150
|
+
);
|
|
151
|
+
const sub = sync.getSubscription(result.subscriptionId);
|
|
152
|
+
expect(sub?.stale).toBe(false);
|
|
153
|
+
expect(sub?.checkpoint).toBe("2024-01-01T12:00:00|t3");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("refreshes an adopted subscription from the network when the reload is online", async () => {
|
|
157
|
+
const kv = new MemoryKV();
|
|
158
|
+
const first = await seedSnapshot(kv);
|
|
159
|
+
|
|
160
|
+
const freshDocs = [
|
|
161
|
+
{ name: "t2", doctype: "ToDo", modified: "2024-01-01T11:00:00", description: "two" },
|
|
162
|
+
{ name: "t9", doctype: "ToDo", modified: "2024-01-03T09:00:00", description: "nine" },
|
|
163
|
+
];
|
|
164
|
+
const onlineDb = createMockDb();
|
|
165
|
+
onlineDb.getDocList.mockResolvedValue(freshDocs);
|
|
166
|
+
const sync = createSync(onlineDb, { persistKey: PERSIST_KEY, storage: kv });
|
|
167
|
+
|
|
168
|
+
const listener = vi.fn();
|
|
169
|
+
sync.subscribeStore(listener);
|
|
170
|
+
const result = await sync.subscribe(todoQuery);
|
|
171
|
+
|
|
172
|
+
// Immediate render still comes from the cache (stale-while-revalidate)
|
|
173
|
+
expect(result.subscriptionId).toBe(first.subscriptionId);
|
|
174
|
+
expect(result.rows.map((row) => row.name)).toEqual(["t1", "t2"]);
|
|
175
|
+
|
|
176
|
+
listener.mockClear();
|
|
177
|
+
const refresh = await result.refresh!;
|
|
178
|
+
expect(refresh.ok).toBe(true);
|
|
179
|
+
// Store listeners were notified so collections re-read the fresh rows
|
|
180
|
+
expect(listener).toHaveBeenCalled();
|
|
181
|
+
|
|
182
|
+
const sub = sync.getSubscription(result.subscriptionId);
|
|
183
|
+
expect(sub?.stale).toBe(false);
|
|
184
|
+
// Membership replaced by the authoritative fetch, checkpoint recomputed
|
|
185
|
+
expect(sync.getDocsForSubscription(result.subscriptionId).map((row) => row.name)).toEqual([
|
|
186
|
+
"t2",
|
|
187
|
+
"t9",
|
|
188
|
+
]);
|
|
189
|
+
expect(sub?.checkpoint).toBe("2024-01-03T09:00:00");
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("still rejects for queries with no restored subscription (honest error surfacing)", async () => {
|
|
193
|
+
const kv = new MemoryKV();
|
|
194
|
+
await seedSnapshot(kv);
|
|
195
|
+
|
|
196
|
+
const offlineDb = createMockDb();
|
|
197
|
+
offlineDb.getDocList.mockRejectedValue(new Error("network down"));
|
|
198
|
+
const sync = createSync(offlineDb, { persistKey: PERSIST_KEY, storage: kv });
|
|
199
|
+
|
|
200
|
+
await expect(sync.subscribe({ doctype: "Note" })).rejects.toThrow("network down");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("adopts even when subscribe() is called before the async snapshot load finishes", async () => {
|
|
204
|
+
const kv = new MemoryKV();
|
|
205
|
+
const first = await seedSnapshot(kv);
|
|
206
|
+
const raw = kv.store.get(PERSIST_KEY)!;
|
|
207
|
+
|
|
208
|
+
// Storage with a slow (100ms) read, like a busy IndexedDB
|
|
209
|
+
const slowKv: KVStorage = {
|
|
210
|
+
getItem: () => new Promise((resolve) => setTimeout(() => resolve(raw), 100)),
|
|
211
|
+
setItem: async () => {},
|
|
212
|
+
removeItem: async () => {},
|
|
213
|
+
};
|
|
214
|
+
const offlineDb = createMockDb();
|
|
215
|
+
offlineDb.getDocList.mockRejectedValue(new Error("network down"));
|
|
216
|
+
const sync = createSync(offlineDb, { persistKey: PERSIST_KEY, storage: slowKv });
|
|
217
|
+
|
|
218
|
+
const pending = sync.subscribe(todoQuery);
|
|
219
|
+
await vi.advanceTimersByTimeAsync(150);
|
|
220
|
+
const result = await pending;
|
|
221
|
+
|
|
222
|
+
expect(result.subscriptionId).toBe(first.subscriptionId);
|
|
223
|
+
expect(result.rows.map((row) => row.name)).toEqual(["t1", "t2"]);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
describe("re-adoption and GC (no orphan growth)", () => {
|
|
228
|
+
it("keeps exactly one subscription per query across repeated reload cycles", async () => {
|
|
229
|
+
const kv = new MemoryKV();
|
|
230
|
+
let subscriptionId: string | undefined;
|
|
231
|
+
|
|
232
|
+
for (let cycle = 0; cycle < 3; cycle++) {
|
|
233
|
+
const db = createMockDb();
|
|
234
|
+
const sync = createSync(db, { persistKey: PERSIST_KEY, storage: kv });
|
|
235
|
+
const result = await sync.subscribe(todoQuery);
|
|
236
|
+
if (subscriptionId) expect(result.subscriptionId).toBe(subscriptionId);
|
|
237
|
+
subscriptionId = result.subscriptionId;
|
|
238
|
+
if (result.refresh) await result.refresh;
|
|
239
|
+
await flushSave();
|
|
240
|
+
|
|
241
|
+
// One subscription in memory, one in the snapshot — every cycle
|
|
242
|
+
expect(sync.__debug().subscriptions).toHaveLength(1);
|
|
243
|
+
expect(snapshotFromStorage(kv).subs).toHaveLength(1);
|
|
244
|
+
|
|
245
|
+
await sync.dispose();
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("collapses duplicate snapshot entries from pre-fix versions (last wins)", async () => {
|
|
250
|
+
const kv = new MemoryKV();
|
|
251
|
+
// Simulate a legacy snapshot polluted by orphan accumulation
|
|
252
|
+
kv.store.set(
|
|
253
|
+
PERSIST_KEY,
|
|
254
|
+
JSON.stringify({
|
|
255
|
+
subs: [
|
|
256
|
+
{ id: "legacy-1", query: todoQuery, checkpoint: "2024-01-01T08:00:00", docIds: ["t1"] },
|
|
257
|
+
{ id: "legacy-2", query: todoQuery, checkpoint: "2024-01-01T09:00:00", docIds: ["t1"] },
|
|
258
|
+
{
|
|
259
|
+
id: "legacy-3",
|
|
260
|
+
query: todoQuery,
|
|
261
|
+
checkpoint: "2024-01-01T10:00:00",
|
|
262
|
+
docIds: ["t1", "t2"],
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
cache: {
|
|
266
|
+
ToDo: {
|
|
267
|
+
byId: { t1: seedDocs[0], t2: seedDocs[1] },
|
|
268
|
+
allIds: ["t1", "t2"],
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
journal: [],
|
|
272
|
+
temp: [],
|
|
273
|
+
}),
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
const offlineDb = createMockDb();
|
|
277
|
+
offlineDb.getDocList.mockRejectedValue(new Error("network down"));
|
|
278
|
+
const sync = createSync(offlineDb, { persistKey: PERSIST_KEY, storage: kv });
|
|
279
|
+
|
|
280
|
+
const result = await sync.subscribe(todoQuery);
|
|
281
|
+
// Last snapshot entry (most recent session) won the dedupe
|
|
282
|
+
expect(result.subscriptionId).toBe("legacy-3");
|
|
283
|
+
expect(result.checkpoint).toBe("2024-01-01T10:00:00");
|
|
284
|
+
expect(sync.__debug().subscriptions).toHaveLength(1);
|
|
285
|
+
|
|
286
|
+
await flushSave();
|
|
287
|
+
expect(snapshotFromStorage(kv).subs).toHaveLength(1);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("keeps unadopted restored subscriptions within the TTL and GCs them after it", async () => {
|
|
291
|
+
const kv = new MemoryKV();
|
|
292
|
+
await seedSnapshot(kv);
|
|
293
|
+
|
|
294
|
+
const db = createMockDb();
|
|
295
|
+
const sync = createSync(db, {
|
|
296
|
+
persistKey: PERSIST_KEY,
|
|
297
|
+
storage: kv,
|
|
298
|
+
restoredSubscriptionTTL: 1000,
|
|
299
|
+
});
|
|
300
|
+
// Subscribe a DIFFERENT query; the restored ToDo sub stays unadopted
|
|
301
|
+
await sync.subscribe({ doctype: "Note" });
|
|
302
|
+
await flushSave();
|
|
303
|
+
|
|
304
|
+
// Within the TTL the restored sub is retained (and persisted) so a
|
|
305
|
+
// later offline navigation can still adopt it
|
|
306
|
+
let snapshot = snapshotFromStorage(kv);
|
|
307
|
+
expect(snapshot.subs).toHaveLength(2);
|
|
308
|
+
expect(sync.__debug().subscriptions.filter((sub) => sub.restored)).toHaveLength(1);
|
|
309
|
+
|
|
310
|
+
// After the TTL, the next snapshot write GCs it
|
|
311
|
+
await vi.advanceTimersByTimeAsync(1100);
|
|
312
|
+
await sync.subscribe({ doctype: "Comment" });
|
|
313
|
+
await flushSave();
|
|
314
|
+
|
|
315
|
+
snapshot = snapshotFromStorage(kv);
|
|
316
|
+
expect(snapshot.subs).toHaveLength(2); // Note + Comment
|
|
317
|
+
expect(snapshot.subs.map((sub: any) => sub.query.doctype).sort()).toEqual([
|
|
318
|
+
"Comment",
|
|
319
|
+
"Note",
|
|
320
|
+
]);
|
|
321
|
+
expect(sync.__debug().subscriptions.filter((sub) => sub.restored)).toHaveLength(0);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it("excludes unadopted restored subscriptions from backfill fan-out", async () => {
|
|
325
|
+
const kv = new MemoryKV();
|
|
326
|
+
await seedSnapshot(kv);
|
|
327
|
+
|
|
328
|
+
const db = createMockDb();
|
|
329
|
+
const sync = createSync(db, { persistKey: PERSIST_KEY, storage: kv });
|
|
330
|
+
await sync.subscribe({ doctype: "Note" });
|
|
331
|
+
|
|
332
|
+
db.backfill.mockClear();
|
|
333
|
+
await sync.backfill({ scope: BackfillScope.All });
|
|
334
|
+
|
|
335
|
+
// Only the live Note subscription drained; the restored ToDo sub did not
|
|
336
|
+
expect(db.backfill).toHaveBeenCalledTimes(1);
|
|
337
|
+
expect(db.backfill).toHaveBeenCalledWith(expect.objectContaining({ doctype: "Note" }));
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
describe("detach on unsubscribe (persistKey only)", () => {
|
|
342
|
+
it("retains a released subscription for cache-first re-adoption", async () => {
|
|
343
|
+
const kv = new MemoryKV();
|
|
344
|
+
const db = createMockDb();
|
|
345
|
+
const sync = createSync(db, { persistKey: PERSIST_KEY, storage: kv });
|
|
346
|
+
|
|
347
|
+
const first = await sync.subscribe(todoQuery);
|
|
348
|
+
sync.unsubscribe(first.subscriptionId);
|
|
349
|
+
|
|
350
|
+
// Still in memory as a dormant restored subscription
|
|
351
|
+
const debugSubs = sync.__debug().subscriptions;
|
|
352
|
+
expect(debugSubs).toHaveLength(1);
|
|
353
|
+
expect(debugSubs[0].restored).toBe(true);
|
|
354
|
+
|
|
355
|
+
// Excluded from backfill while detached
|
|
356
|
+
db.backfill.mockClear();
|
|
357
|
+
await sync.backfill({ scope: BackfillScope.All });
|
|
358
|
+
expect(db.backfill).not.toHaveBeenCalled();
|
|
359
|
+
|
|
360
|
+
// Remount re-adopts: same id, cached rows immediately
|
|
361
|
+
db.getDocList.mockClear();
|
|
362
|
+
const second = await sync.subscribe(todoQuery);
|
|
363
|
+
expect(second.subscriptionId).toBe(first.subscriptionId);
|
|
364
|
+
expect(second.rows.map((row) => row.name)).toEqual(["t1", "t2"]);
|
|
365
|
+
expect(second.refresh).toBeDefined();
|
|
366
|
+
await second.refresh!;
|
|
367
|
+
expect(db.getDocList).toHaveBeenCalledTimes(1);
|
|
368
|
+
expect(sync.__debug().subscriptions[0].restored).toBe(false);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it("without persistKey, unsubscribe deletes the subscription (unchanged behavior)", async () => {
|
|
372
|
+
const db = createMockDb();
|
|
373
|
+
const sync = createSync(db, {});
|
|
374
|
+
|
|
375
|
+
const result = await sync.subscribe(todoQuery);
|
|
376
|
+
expect(result.refresh).toBeUndefined();
|
|
377
|
+
sync.unsubscribe(result.subscriptionId);
|
|
378
|
+
|
|
379
|
+
expect(sync.__debug().subscriptions).toHaveLength(0);
|
|
380
|
+
expect(sync.getSubscription(result.subscriptionId)).toBeUndefined();
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
describe("journal replay on app focus", () => {
|
|
385
|
+
it("replays queued mutations when the app regains focus", async () => {
|
|
386
|
+
const db = createMockDb();
|
|
387
|
+
const sync = createSync(db, {});
|
|
388
|
+
await sync.subscribe(todoQuery);
|
|
389
|
+
|
|
390
|
+
// Mutation fails (server unreachable) and stays queued in the journal
|
|
391
|
+
db.updateDoc.mockRejectedValueOnce(new Error("fetch failed"));
|
|
392
|
+
await expect(
|
|
393
|
+
sync.mutate({
|
|
394
|
+
mutationId: "m-focus-1",
|
|
395
|
+
operation: Operation.Update,
|
|
396
|
+
doc: { doctype: "ToDo", name: "t1", description: "edited" } as any,
|
|
397
|
+
}),
|
|
398
|
+
).rejects.toThrow();
|
|
399
|
+
expect(db.updateDoc).toHaveBeenCalledTimes(1);
|
|
400
|
+
|
|
401
|
+
// Foreground transition (web focus / RN AppState active) triggers replay
|
|
402
|
+
window.dispatchEvent(new Event("focus"));
|
|
403
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
404
|
+
|
|
405
|
+
expect(db.updateDoc).toHaveBeenCalledTimes(2);
|
|
406
|
+
expect(db.updateDoc.mock.calls[1][0]).toEqual(
|
|
407
|
+
expect.objectContaining({ doctype: "ToDo", name: "t1", client_mutation_id: "m-focus-1" }),
|
|
408
|
+
);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it("does not start a replay cycle on focus when the journal is empty", async () => {
|
|
412
|
+
const db = createMockDb();
|
|
413
|
+
const onReplayStart = vi.fn();
|
|
414
|
+
const sync = createSync(db, { onReplayStart });
|
|
415
|
+
await sync.subscribe(todoQuery);
|
|
416
|
+
|
|
417
|
+
window.dispatchEvent(new Event("focus"));
|
|
418
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
419
|
+
|
|
420
|
+
expect(onReplayStart).not.toHaveBeenCalled();
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
});
|
|
@@ -99,6 +99,8 @@ describe("PersistenceManager", () => {
|
|
|
99
99
|
// Mock dependencies
|
|
100
100
|
mockNormalizedCache = {
|
|
101
101
|
state: { docs: {}, pages: {} },
|
|
102
|
+
get: vi.fn().mockReturnValue(undefined),
|
|
103
|
+
upsert: vi.fn(),
|
|
102
104
|
} as any;
|
|
103
105
|
|
|
104
106
|
mockMutationJournal = {
|
|
@@ -108,6 +110,8 @@ describe("PersistenceManager", () => {
|
|
|
108
110
|
|
|
109
111
|
mockSubscriptionManager = {
|
|
110
112
|
getAllSubscriptions: vi.fn().mockReturnValue(new Map()),
|
|
113
|
+
restoreSubscription: vi.fn(),
|
|
114
|
+
gcRestoredSubscriptions: vi.fn(),
|
|
111
115
|
} as any;
|
|
112
116
|
|
|
113
117
|
mockMutationEngine = {
|
|
@@ -422,6 +426,7 @@ describe("PersistenceManager", () => {
|
|
|
422
426
|
|
|
423
427
|
describe("load", () => {
|
|
424
428
|
it("should load and restore persisted state", async () => {
|
|
429
|
+
const cachedUser = { doctype: "User", name: "user1", full_name: "User 1" };
|
|
425
430
|
const persistedState = {
|
|
426
431
|
subs: [
|
|
427
432
|
{
|
|
@@ -431,16 +436,14 @@ describe("PersistenceManager", () => {
|
|
|
431
436
|
docIds: ["user1", "user2"],
|
|
432
437
|
},
|
|
433
438
|
],
|
|
434
|
-
cache: {
|
|
439
|
+
cache: { User: { byId: { user1: cachedUser }, allIds: ["user1"] } },
|
|
435
440
|
journal: [{ id: "entry1", entry: { type: "create" } }],
|
|
436
441
|
temp: [["temp1", "real1"]],
|
|
437
442
|
};
|
|
438
443
|
|
|
439
444
|
mockStorage.getItem.mockResolvedValue(JSON.stringify(persistedState));
|
|
440
445
|
|
|
441
|
-
const subscriptionsMap = new Map();
|
|
442
446
|
const tempMap = new Map();
|
|
443
|
-
mockSubscriptionManager.getAllSubscriptions.mockReturnValue(subscriptionsMap);
|
|
444
447
|
mockMutationEngine.getTemporaryIdToRealNameMap.mockReturnValue(tempMap);
|
|
445
448
|
|
|
446
449
|
// Create new instance to trigger load
|
|
@@ -454,11 +457,13 @@ describe("PersistenceManager", () => {
|
|
|
454
457
|
|
|
455
458
|
await vi.advanceTimersByTimeAsync(100);
|
|
456
459
|
|
|
457
|
-
// Verify
|
|
458
|
-
expect(mockNormalizedCache.
|
|
460
|
+
// Verify cached docs were merged in per-doc (not wholesale replace)
|
|
461
|
+
expect(mockNormalizedCache.upsert).toHaveBeenCalledWith(cachedUser, { replace: true });
|
|
459
462
|
|
|
460
|
-
// Verify subscriptions were restored
|
|
461
|
-
expect(
|
|
463
|
+
// Verify subscriptions were restored as dormant restored entries
|
|
464
|
+
expect(mockSubscriptionManager.restoreSubscription).toHaveBeenCalledWith(
|
|
465
|
+
persistedState.subs[0],
|
|
466
|
+
);
|
|
462
467
|
|
|
463
468
|
// Verify journal was restored
|
|
464
469
|
expect(mockMutationJournal.add).toHaveBeenCalledWith("entry1", {
|
|
@@ -469,6 +474,33 @@ describe("PersistenceManager", () => {
|
|
|
469
474
|
expect(tempMap.get("temp1")).toBe("real1");
|
|
470
475
|
});
|
|
471
476
|
|
|
477
|
+
it("should not clobber docs already in memory when merging the snapshot cache", async () => {
|
|
478
|
+
const snapshotDoc = { doctype: "User", name: "user1", full_name: "Old Name" };
|
|
479
|
+
mockStorage.getItem.mockResolvedValue(
|
|
480
|
+
JSON.stringify({
|
|
481
|
+
cache: { User: { byId: { user1: snapshotDoc }, allIds: ["user1"] } },
|
|
482
|
+
}),
|
|
483
|
+
);
|
|
484
|
+
// Doc already exists in memory (e.g. optimistic write raced the load)
|
|
485
|
+
mockNormalizedCache.get.mockReturnValue({
|
|
486
|
+
doctype: "User",
|
|
487
|
+
name: "user1",
|
|
488
|
+
full_name: "Newer Name",
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
new PersistenceManager(
|
|
492
|
+
mockNormalizedCache,
|
|
493
|
+
mockMutationJournal,
|
|
494
|
+
mockSubscriptionManager,
|
|
495
|
+
mockMutationEngine,
|
|
496
|
+
{ persistKey: "test-key", storage: mockStorage },
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
await vi.advanceTimersByTimeAsync(100);
|
|
500
|
+
|
|
501
|
+
expect(mockNormalizedCache.upsert).not.toHaveBeenCalled();
|
|
502
|
+
});
|
|
503
|
+
|
|
472
504
|
it("should handle missing persisted state", async () => {
|
|
473
505
|
mockStorage.getItem.mockResolvedValue(null);
|
|
474
506
|
|