@multiplatform.one/frappe 6.1.0 → 6.4.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 +10 -2
- package/dist/esm/util.mjs.map +1 -1
- package/dist/esm/util.native.js +15 -2
- 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 +10 -2
- 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 +445 -37
- package/src/frappeReactLiveQueryGc.spec.ts +320 -0
- package/src/frappeReactNative.spec.ts +65 -0
- package/src/index.ts +10 -9
- package/src/pacer.ts +1 -1
- 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 +34 -7
- 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
package/src/sync/debug.spec.ts
CHANGED
|
@@ -93,6 +93,42 @@ describe("SyncModule.__debug()", () => {
|
|
|
93
93
|
expect(typeof debug.connection.socketConnected).toBe("boolean");
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
+
it("treats missing navigator.onLine as online (React Native)", () => {
|
|
97
|
+
// RN has a navigator object but no onLine property — the old ternary
|
|
98
|
+
// surfaced `undefined`, rendering as "offline" in devtools.
|
|
99
|
+
const originalNavigator = globalThis.navigator;
|
|
100
|
+
Object.defineProperty(globalThis, "navigator", {
|
|
101
|
+
value: { product: "ReactNative" },
|
|
102
|
+
writable: true,
|
|
103
|
+
configurable: true,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(syncModule.__debug().connection.isOnline).toBe(true);
|
|
107
|
+
|
|
108
|
+
Object.defineProperty(globalThis, "navigator", {
|
|
109
|
+
value: originalNavigator,
|
|
110
|
+
writable: true,
|
|
111
|
+
configurable: true,
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("still reports offline when navigator.onLine is explicitly false (web)", () => {
|
|
116
|
+
const originalNavigator = globalThis.navigator;
|
|
117
|
+
Object.defineProperty(globalThis, "navigator", {
|
|
118
|
+
value: { onLine: false },
|
|
119
|
+
writable: true,
|
|
120
|
+
configurable: true,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(syncModule.__debug().connection.isOnline).toBe(false);
|
|
124
|
+
|
|
125
|
+
Object.defineProperty(globalThis, "navigator", {
|
|
126
|
+
value: originalNavigator,
|
|
127
|
+
writable: true,
|
|
128
|
+
configurable: true,
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
96
132
|
it("mutation journal has correct structure", async () => {
|
|
97
133
|
await syncModule.subscribe({
|
|
98
134
|
doctype: "ToDo",
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter toolkit contracts beyond matchesFilters (covered in filters.spec):
|
|
3
|
+
* schema validation (validateFilters strict/lenient), normalization of
|
|
4
|
+
* object filters to tuples, filter-field extraction, display formatting,
|
|
5
|
+
* getDoc fast-path extraction (extractSingleName), and the tree-operator
|
|
6
|
+
* client/server evaluation gate the sync engine keys off.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, expect, it } from "vitest";
|
|
10
|
+
import {
|
|
11
|
+
canEvaluateClientSide,
|
|
12
|
+
extractFilterFields,
|
|
13
|
+
extractSingleName,
|
|
14
|
+
FilterOperator,
|
|
15
|
+
formatFilter,
|
|
16
|
+
getClientEvaluationBlockers,
|
|
17
|
+
hasServerOnlyOperators,
|
|
18
|
+
isTreeOperator,
|
|
19
|
+
normalizeFilters,
|
|
20
|
+
validateFilters,
|
|
21
|
+
type FilterTuple,
|
|
22
|
+
} from "./filters";
|
|
23
|
+
|
|
24
|
+
const schema = [
|
|
25
|
+
{ fieldname: "title", fieldtype: "Data" },
|
|
26
|
+
{ fieldname: "amount", fieldtype: "Currency" },
|
|
27
|
+
{ fieldname: "status", fieldtype: "Select" },
|
|
28
|
+
{ fieldname: "attachment", fieldtype: "Attach" },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
describe("validateFilters", () => {
|
|
32
|
+
it("passes valid filters against the schema", () => {
|
|
33
|
+
const result = validateFilters(
|
|
34
|
+
[
|
|
35
|
+
["title", "like", "%report%"],
|
|
36
|
+
["amount", ">", 100],
|
|
37
|
+
["status", "in", ["Open", "Closed"]],
|
|
38
|
+
],
|
|
39
|
+
schema,
|
|
40
|
+
);
|
|
41
|
+
expect(result.valid).toBe(true);
|
|
42
|
+
expect(result.errors).toEqual([]);
|
|
43
|
+
expect(result.warnings).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("treats empty filters as valid", () => {
|
|
47
|
+
expect(validateFilters(null, schema).valid).toBe(true);
|
|
48
|
+
expect(validateFilters(undefined, schema).valid).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("accepts standard fields that are not in the schema", () => {
|
|
52
|
+
const result = validateFilters([["modified", ">", "2024-01-01"]], schema);
|
|
53
|
+
expect(result.valid).toBe(true);
|
|
54
|
+
expect(result.warnings).toEqual([]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("warns about unknown fields by default but errors in strict mode", () => {
|
|
58
|
+
const lenient = validateFilters([["custom_field", "=", 1]], schema);
|
|
59
|
+
expect(lenient.valid).toBe(true);
|
|
60
|
+
expect(lenient.warnings[0]).toContain("custom_field");
|
|
61
|
+
|
|
62
|
+
const strict = validateFilters([["custom_field", "=", 1]], schema, { strict: true });
|
|
63
|
+
expect(strict.valid).toBe(false);
|
|
64
|
+
expect(strict.errors[0]).toMatchObject({ field: "custom_field", code: "unknown_field" });
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("rejects invalid operators", () => {
|
|
68
|
+
const result = validateFilters([["title", "resembles", "x"]], schema);
|
|
69
|
+
expect(result.valid).toBe(false);
|
|
70
|
+
expect(result.errors[0]).toMatchObject({ field: "title", code: "invalid_operator" });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("warns when LIKE is used on non-text fields", () => {
|
|
74
|
+
const result = validateFilters([["amount", "like", "%5%"]], schema);
|
|
75
|
+
expect(result.valid).toBe(true);
|
|
76
|
+
expect(result.warnings[0]).toContain("LIKE operator on non-text field");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("warns when comparisons hit non-comparable fields", () => {
|
|
80
|
+
const result = validateFilters([["attachment", ">", 3]], schema);
|
|
81
|
+
expect(result.valid).toBe(true);
|
|
82
|
+
expect(result.warnings[0]).toContain("Comparison operator on non-numeric/date field");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("requires arrays for IN and exactly two values for BETWEEN", () => {
|
|
86
|
+
const inResult = validateFilters([["status", "in", "Open"]], schema);
|
|
87
|
+
expect(inResult.valid).toBe(false);
|
|
88
|
+
expect(inResult.errors[0].code).toBe("invalid_value");
|
|
89
|
+
|
|
90
|
+
const betweenResult = validateFilters([["amount", "between", [1]]], schema);
|
|
91
|
+
expect(betweenResult.valid).toBe(false);
|
|
92
|
+
expect(betweenResult.errors[0].code).toBe("invalid_value");
|
|
93
|
+
|
|
94
|
+
const ok = validateFilters([["amount", "between", [1, 10]]], schema);
|
|
95
|
+
expect(ok.valid).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("validates object-format filters for unknown fields", () => {
|
|
99
|
+
const lenient = validateFilters({ ghost: 1, title: "x" }, schema);
|
|
100
|
+
expect(lenient.valid).toBe(true);
|
|
101
|
+
expect(lenient.warnings).toHaveLength(1);
|
|
102
|
+
|
|
103
|
+
const strict = validateFilters({ ghost: 1 }, schema, { strict: true });
|
|
104
|
+
expect(strict.valid).toBe(false);
|
|
105
|
+
expect(strict.errors[0].field).toBe("ghost");
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe("normalizeFilters / extractFilterFields", () => {
|
|
110
|
+
it("passes tuple filters through and converts object filters to equality tuples", () => {
|
|
111
|
+
const tuples: FilterTuple[] = [["title", "like", "%x%"]];
|
|
112
|
+
expect(normalizeFilters(tuples)).toBe(tuples);
|
|
113
|
+
expect(normalizeFilters({ status: "Open", amount: 5 })).toEqual([
|
|
114
|
+
["status", FilterOperator.Equals, "Open"],
|
|
115
|
+
["amount", FilterOperator.Equals, 5],
|
|
116
|
+
]);
|
|
117
|
+
expect(normalizeFilters(null)).toEqual([]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("extracts unique filter field names", () => {
|
|
121
|
+
expect(
|
|
122
|
+
extractFilterFields([
|
|
123
|
+
["title", "like", "%a%"],
|
|
124
|
+
["title", "!=", "b"],
|
|
125
|
+
["amount", ">", 1],
|
|
126
|
+
]),
|
|
127
|
+
).toEqual(["title", "amount"]);
|
|
128
|
+
expect(extractFilterFields(null)).toEqual([]);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe("formatFilter", () => {
|
|
133
|
+
it("formats scalar, string, array, and null values", () => {
|
|
134
|
+
expect(formatFilter(["amount", ">", 5])).toBe("amount > 5");
|
|
135
|
+
expect(formatFilter(["title", "like", "%x%"])).toBe('title like "%x%"');
|
|
136
|
+
expect(formatFilter(["status", "in", ["a", "b"]])).toBe('status in ["a", "b"]');
|
|
137
|
+
expect(formatFilter(["parent", "is", null])).toBe("parent is null");
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe("extractSingleName (getDoc fast path)", () => {
|
|
142
|
+
it("extracts the name from a single name-equality tuple", () => {
|
|
143
|
+
expect(extractSingleName([["name", "=", "DOC-001"]])).toBe("DOC-001");
|
|
144
|
+
expect(extractSingleName([["name", "==", "DOC-002"]])).toBe("DOC-002");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("extracts the name from an object filter", () => {
|
|
148
|
+
expect(extractSingleName({ name: "DOC-003" })).toBe("DOC-003");
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("refuses multi-filter, non-name, non-equality, and non-string cases", () => {
|
|
152
|
+
expect(
|
|
153
|
+
extractSingleName([
|
|
154
|
+
["name", "=", "DOC-001"],
|
|
155
|
+
["status", "=", "Open"],
|
|
156
|
+
]),
|
|
157
|
+
).toBeUndefined();
|
|
158
|
+
expect(extractSingleName([["title", "=", "DOC-001"]])).toBeUndefined();
|
|
159
|
+
expect(extractSingleName([["name", "like", "DOC-%"]])).toBeUndefined();
|
|
160
|
+
expect(extractSingleName([["name", "=", 42]])).toBeUndefined();
|
|
161
|
+
expect(extractSingleName(null)).toBeUndefined();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe("tree-operator evaluation gate", () => {
|
|
166
|
+
it("classifies tree operators as server-only", () => {
|
|
167
|
+
expect(isTreeOperator("ancestors of")).toBe(true);
|
|
168
|
+
expect(isTreeOperator("DESCENDANTS OF")).toBe(true);
|
|
169
|
+
expect(isTreeOperator("not ancestors of")).toBe(true);
|
|
170
|
+
expect(isTreeOperator("not descendants of")).toBe(true);
|
|
171
|
+
expect(isTreeOperator("=")).toBe(false);
|
|
172
|
+
expect(isTreeOperator("like")).toBe(false);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("detects server-only operators inside filters", () => {
|
|
176
|
+
expect(hasServerOnlyOperators([["parent", "ancestors of", "Root"]])).toBe(true);
|
|
177
|
+
expect(hasServerOnlyOperators([["title", "like", "%x%"]])).toBe(false);
|
|
178
|
+
expect(hasServerOnlyOperators(null)).toBe(false);
|
|
179
|
+
expect(hasServerOnlyOperators({ status: "Open" })).toBe(false);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("canEvaluateClientSide is the inverse gate", () => {
|
|
183
|
+
expect(canEvaluateClientSide([["parent", "descendants of", "Root"]])).toBe(false);
|
|
184
|
+
expect(canEvaluateClientSide([["status", "=", "Open"]])).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("explains exactly which fields block client evaluation", () => {
|
|
188
|
+
const blockers = getClientEvaluationBlockers([
|
|
189
|
+
["parent", "ancestors of", "Root"],
|
|
190
|
+
["status", "=", "Open"],
|
|
191
|
+
]);
|
|
192
|
+
expect(blockers).toHaveLength(1);
|
|
193
|
+
expect(blockers[0]).toContain('"parent"');
|
|
194
|
+
expect(blockers[0]).toContain("ancestors of");
|
|
195
|
+
expect(getClientEvaluationBlockers(null)).toEqual([]);
|
|
196
|
+
});
|
|
197
|
+
});
|
package/src/sync/index.ts
CHANGED
|
@@ -17,9 +17,16 @@ import type {
|
|
|
17
17
|
SyncOptions,
|
|
18
18
|
FrappeDebugState,
|
|
19
19
|
Mutation,
|
|
20
|
+
RealtimeEventType,
|
|
20
21
|
SubscriptionQuery,
|
|
21
22
|
} from "./types";
|
|
22
23
|
|
|
24
|
+
/** Realtime event forwarded to `subscribeRealtimeEvents` listeners. */
|
|
25
|
+
export interface SyncRealtimeEvent {
|
|
26
|
+
type: RealtimeEventType;
|
|
27
|
+
payload?: unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
/**
|
|
24
31
|
* Synchronization engine that provides Zero-style UX on top of Frappe's REST API.
|
|
25
32
|
*
|
|
@@ -70,6 +77,8 @@ export class SyncModule {
|
|
|
70
77
|
private normalizedCache: NormalizedCache;
|
|
71
78
|
private mutationJournal: MutationJournal;
|
|
72
79
|
private storeListeners = new Set<() => void>();
|
|
80
|
+
/** Listeners registered via `subscribeRealtimeEvents`. */
|
|
81
|
+
private realtimeEventListeners = new Set<(event: SyncRealtimeEvent) => void>();
|
|
73
82
|
private subscriptionManager: SubscriptionManager;
|
|
74
83
|
/** Mutation engine for optimistic updates and conflict resolution. */
|
|
75
84
|
private mutationEngine: MutationEngine;
|
|
@@ -81,16 +90,19 @@ export class SyncModule {
|
|
|
81
90
|
private rehydrationManager: RehydrationManager;
|
|
82
91
|
/** Cleanup functions returned by lifecycle subscriptions. */
|
|
83
92
|
private cleanupFocus?: () => void;
|
|
93
|
+
private cleanupFocusReplay?: () => void;
|
|
84
94
|
private cleanupOnlineBackfill?: () => void;
|
|
85
95
|
private cleanupOnlineReplay?: () => void;
|
|
86
96
|
/** Timer handle for periodic CDC polling. */
|
|
87
97
|
private cdcIntervalHandle?: ReturnType<typeof setInterval>;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
private readonly db: DbModule;
|
|
99
|
+
private readonly realtime?: RealtimeModule;
|
|
100
|
+
private readonly options: SyncOptions;
|
|
101
|
+
|
|
102
|
+
constructor(db: DbModule, realtime?: RealtimeModule, options: SyncOptions = {}) {
|
|
103
|
+
this.db = db;
|
|
104
|
+
this.realtime = realtime;
|
|
105
|
+
this.options = options;
|
|
94
106
|
// Initialize normalized cache with LRU eviction if maxCacheSize is set
|
|
95
107
|
this.normalizedCache = new NormalizedCache({
|
|
96
108
|
maxSize: this.options.maxCacheSize,
|
|
@@ -108,6 +120,7 @@ export class SyncModule {
|
|
|
108
120
|
this.normalizedCache,
|
|
109
121
|
this.subscriptionManager,
|
|
110
122
|
this.mutationJournal,
|
|
123
|
+
() => this.emit(),
|
|
111
124
|
);
|
|
112
125
|
|
|
113
126
|
this.mutationEngine = new MutationEngine(
|
|
@@ -125,6 +138,13 @@ export class SyncModule {
|
|
|
125
138
|
...this.options,
|
|
126
139
|
onResetCache: () => this.resetCache(),
|
|
127
140
|
onBackfillAll: () => this.backfill({ scope: BackfillScope.All }),
|
|
141
|
+
// Realtime reconciliation mutates cache/membership outside the public
|
|
142
|
+
// mutate/backfill entry points — bridge those changes to store listeners.
|
|
143
|
+
onStoreChange: () => this.emit(),
|
|
144
|
+
onRealtimeEvent: (event) => {
|
|
145
|
+
this.options.onRealtimeEvent?.(event);
|
|
146
|
+
for (const listener of this.realtimeEventListeners) listener(event);
|
|
147
|
+
},
|
|
128
148
|
};
|
|
129
149
|
|
|
130
150
|
this.realtimeHandler = new RealtimeHandler(
|
|
@@ -153,6 +173,13 @@ export class SyncModule {
|
|
|
153
173
|
*/
|
|
154
174
|
private setupWindowEvents() {
|
|
155
175
|
this.cleanupFocus = onAppFocus(() => this.backfill({ scope: BackfillScope.All }));
|
|
176
|
+
// Journal replay on foreground: React Native never fires `online`
|
|
177
|
+
// (AppState is its only lifecycle signal), and on web this recovers
|
|
178
|
+
// server-restart cases where connectivity never flipped. Guarded so it
|
|
179
|
+
// is a strict no-op unless mutations are actually queued.
|
|
180
|
+
this.cleanupFocusReplay = onAppFocus(() => {
|
|
181
|
+
if (this.mutationJournal.listPending().length > 0) void this.replayPending();
|
|
182
|
+
});
|
|
156
183
|
this.cleanupOnlineBackfill = onOnline(() => this.backfill({ scope: BackfillScope.All }));
|
|
157
184
|
this.cleanupOnlineReplay = onOnline(() => this.replayPending());
|
|
158
185
|
|
|
@@ -166,10 +193,25 @@ export class SyncModule {
|
|
|
166
193
|
|
|
167
194
|
/**
|
|
168
195
|
* Creates a subscription, seeds cache with initial rows, and stores a backfill checkpoint.
|
|
196
|
+
*
|
|
197
|
+
* With persistence enabled, a query matching a subscription restored from
|
|
198
|
+
* the snapshot is re-adopted cache-first: the returned rows come from the
|
|
199
|
+
* restored cache and a background network refresh follows (`result.refresh`).
|
|
200
|
+
* If that refresh fails (offline), the cached membership keeps serving and
|
|
201
|
+
* the subscription is marked stale until the next successful backfill.
|
|
169
202
|
*/
|
|
170
203
|
async subscribe<Data extends FrappeDocData>(query: SubscriptionQuery) {
|
|
204
|
+
// Wait for any persisted snapshot restore so a matching restored
|
|
205
|
+
// subscription can be adopted instead of racing the async load.
|
|
206
|
+
await this.persistenceManager.whenReady();
|
|
171
207
|
const result = await this.subscriptionManager.subscribe<Data>(query);
|
|
208
|
+
// Join the doctype's realtime room so doc_update/list_update hints arrive
|
|
209
|
+
// for this subscription (refcounted; survives reconnects).
|
|
210
|
+
this.realtimeHandler.watchDoctype(query.doctype);
|
|
172
211
|
this.emit();
|
|
212
|
+
// Adopted subscriptions refresh in the background; notify store listeners
|
|
213
|
+
// when the refresh lands (or marks the subscription stale). Never rejects.
|
|
214
|
+
if (result.refresh) void result.refresh.then(() => this.emit());
|
|
173
215
|
return result;
|
|
174
216
|
}
|
|
175
217
|
|
|
@@ -177,7 +219,9 @@ export class SyncModule {
|
|
|
177
219
|
* Removes a subscription by id.
|
|
178
220
|
*/
|
|
179
221
|
unsubscribe(subscriptionId: string) {
|
|
222
|
+
const subscription = this.subscriptionManager.getSubscription(subscriptionId);
|
|
180
223
|
this.subscriptionManager.unsubscribe(subscriptionId);
|
|
224
|
+
if (subscription) this.realtimeHandler.unwatchDoctype(subscription.query.doctype);
|
|
181
225
|
this.emit();
|
|
182
226
|
}
|
|
183
227
|
|
|
@@ -279,6 +323,44 @@ export class SyncModule {
|
|
|
279
323
|
};
|
|
280
324
|
}
|
|
281
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Registers a listener for raw realtime events (doc_update, list_update,
|
|
328
|
+
* doc_deleted, connected, …). Useful for consumers that manage their own
|
|
329
|
+
* fetching (e.g. server-side paginated tables) but still want live
|
|
330
|
+
* invalidation hints. Returns an unsubscribe function.
|
|
331
|
+
*/
|
|
332
|
+
subscribeRealtimeEvents(listener: (event: SyncRealtimeEvent) => void): () => void {
|
|
333
|
+
this.realtimeEventListeners.add(listener);
|
|
334
|
+
return () => {
|
|
335
|
+
this.realtimeEventListeners.delete(listener);
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Joins the realtime doctype room without creating a data subscription
|
|
341
|
+
* (refcounted). Pair with `unwatchDoctype` on cleanup. Used by consumers
|
|
342
|
+
* that fetch their own data but need the doctype's realtime hints.
|
|
343
|
+
*/
|
|
344
|
+
watchDoctype(doctype: string): void {
|
|
345
|
+
this.realtimeHandler.watchDoctype(doctype);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** Releases one `watchDoctype` reference. */
|
|
349
|
+
unwatchDoctype(doctype: string): void {
|
|
350
|
+
this.realtimeHandler.unwatchDoctype(doctype);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Live socket connection snapshot. `connected` is the state right now;
|
|
355
|
+
* `everConnected` distinguishes "reconnecting" from "realtime never up"
|
|
356
|
+
* (fixture mode, SSR, or no realtime module). Store listeners are
|
|
357
|
+
* notified on every flip, so read this inside a `subscribeStore` callback
|
|
358
|
+
* for a reactive indicator.
|
|
359
|
+
*/
|
|
360
|
+
getConnectionState(): { connected: boolean; everConnected: boolean } {
|
|
361
|
+
return this.realtimeHandler.getConnectionState();
|
|
362
|
+
}
|
|
363
|
+
|
|
282
364
|
/** Notifies listeners, schedules persistence, and broadcasts cross-tab changes. */
|
|
283
365
|
private emit() {
|
|
284
366
|
// Fan out local state changes to all subscribers
|
|
@@ -291,6 +373,8 @@ export class SyncModule {
|
|
|
291
373
|
|
|
292
374
|
/** Clears subscriptions, cache, journal, and temp id mappings. */
|
|
293
375
|
resetCache() {
|
|
376
|
+
// Leave all realtime doctype rooms alongside dropping the subscriptions
|
|
377
|
+
this.realtimeHandler.unwatchAll();
|
|
294
378
|
// Drop all live subs, in-memory cache, journal, and temp mappings
|
|
295
379
|
this.subscriptionManager.clear();
|
|
296
380
|
this.normalizedCache.clear();
|
|
@@ -304,6 +388,7 @@ export class SyncModule {
|
|
|
304
388
|
async dispose() {
|
|
305
389
|
// Clear all listeners
|
|
306
390
|
this.storeListeners.clear();
|
|
391
|
+
this.realtimeEventListeners.clear();
|
|
307
392
|
|
|
308
393
|
// Clear subscriptions and cache
|
|
309
394
|
this.resetCache();
|
|
@@ -317,9 +402,11 @@ export class SyncModule {
|
|
|
317
402
|
|
|
318
403
|
// Remove lifecycle event listeners
|
|
319
404
|
this.cleanupFocus?.();
|
|
405
|
+
this.cleanupFocusReplay?.();
|
|
320
406
|
this.cleanupOnlineBackfill?.();
|
|
321
407
|
this.cleanupOnlineReplay?.();
|
|
322
408
|
this.cleanupFocus = undefined;
|
|
409
|
+
this.cleanupFocusReplay = undefined;
|
|
323
410
|
this.cleanupOnlineBackfill = undefined;
|
|
324
411
|
this.cleanupOnlineReplay = undefined;
|
|
325
412
|
|
|
@@ -350,6 +437,8 @@ export class SyncModule {
|
|
|
350
437
|
tombstoneCount: sub.tombstones?.size ?? 0,
|
|
351
438
|
checkpoint: sub.checkpoint,
|
|
352
439
|
cursor: sub.cursor,
|
|
440
|
+
stale: sub.stale,
|
|
441
|
+
restored: this.subscriptionManager.isRestoredSubscription(sub.id),
|
|
353
442
|
pageInfo,
|
|
354
443
|
};
|
|
355
444
|
|
|
@@ -398,7 +487,9 @@ export class SyncModule {
|
|
|
398
487
|
connection: {
|
|
399
488
|
socketConnected: this.realtimeHandler.getIsConnected(),
|
|
400
489
|
isLeader: this.persistenceManager.getIsLeader(),
|
|
401
|
-
|
|
490
|
+
// React Native has navigator but no onLine (undefined) — treat
|
|
491
|
+
// anything other than an explicit false as online.
|
|
492
|
+
isOnline: typeof navigator === "undefined" || navigator.onLine !== false,
|
|
402
493
|
},
|
|
403
494
|
};
|
|
404
495
|
}
|
package/src/sync/merge.ts
CHANGED
|
@@ -32,7 +32,7 @@ export function isObject(value: FrappeDocValue): value is Record<string, FrappeD
|
|
|
32
32
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
function isFrappeDoc(value: unknown): value is FrappeDoc<FrappeDocData> {
|
|
36
36
|
return (
|
|
37
37
|
typeof value === "object" &&
|
|
38
38
|
value !== null &&
|
|
@@ -290,7 +290,7 @@ export function merge<Data extends FrappeDocData = FrappeDocData>(
|
|
|
290
290
|
};
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
-
|
|
293
|
+
function mergeObject(
|
|
294
294
|
base: Record<string, FrappeDocValue>,
|
|
295
295
|
client: Record<string, FrappeDocValue>,
|
|
296
296
|
server: Record<string, FrappeDocValue>,
|
|
@@ -416,7 +416,7 @@ export function mergeChildTable(
|
|
|
416
416
|
return sortChildTableByIdx(result);
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
-
|
|
419
|
+
function sortChildTableByIdx(value: FrappeDocValue[]): FrappeDocValue[] {
|
|
420
420
|
const hasIndexField = value.some(
|
|
421
421
|
(row) => isChildTableRow(row) && row.idx !== null && typeof row.idx === "number",
|
|
422
422
|
);
|
|
@@ -603,6 +603,38 @@ describe("MutationEngine", () => {
|
|
|
603
603
|
// Should not fetch the document after successful mutation
|
|
604
604
|
expect(mockDb.getDoc).not.toHaveBeenCalled();
|
|
605
605
|
});
|
|
606
|
+
|
|
607
|
+
it("should not refetch the deleted doc itself on delete when realtime is unhealthy", async () => {
|
|
608
|
+
// Regression: the post-mutation refetch used to include the DELETED
|
|
609
|
+
// doc — the server 404s, routing a confirmed delete into the
|
|
610
|
+
// error/rollback path (surfaced by FrappeTreeView's live delete spec
|
|
611
|
+
// running against a realtime-less fixture sync module).
|
|
612
|
+
mockRealtime.isHealthy.mockReturnValue(false);
|
|
613
|
+
mockDb.getDoc.mockClear();
|
|
614
|
+
mockDb.getDoc.mockImplementation(async (doctype: string, name: string) => {
|
|
615
|
+
if (doctype === "TestDoc" && name === "test-doc") {
|
|
616
|
+
throw new Error(`Document ${doctype}/${name} not found`);
|
|
617
|
+
}
|
|
618
|
+
return { ...mockDoc, doctype, name };
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
const mutation: DeleteMutation<FrappeDocData> = {
|
|
622
|
+
mutationId: "mut-del-refetch",
|
|
623
|
+
operation: Operation.Delete,
|
|
624
|
+
doc: { doctype: "TestDoc", name: "test-doc" },
|
|
625
|
+
version: undefined,
|
|
626
|
+
affected: [{ doctype: "RelatedDoc", name: "related-doc" }],
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
await mutationEngine.mutate(mutation);
|
|
630
|
+
|
|
631
|
+
// The tombstoned doc is never refetched…
|
|
632
|
+
expect(mockDb.getDoc).not.toHaveBeenCalledWith("TestDoc", "test-doc");
|
|
633
|
+
// …while related docs still refresh.
|
|
634
|
+
expect(mockDb.getDoc).toHaveBeenCalledWith("RelatedDoc", "related-doc");
|
|
635
|
+
expect(mockMutationJournal.confirm).toHaveBeenCalledWith("mut-del-refetch");
|
|
636
|
+
expect(mockMutationJournal.fail).not.toHaveBeenCalled();
|
|
637
|
+
});
|
|
606
638
|
});
|
|
607
639
|
});
|
|
608
640
|
|
|
@@ -680,8 +712,8 @@ describe("MutationEngine", () => {
|
|
|
680
712
|
|
|
681
713
|
await expect(mutationEngine.mutate(mutation)).rejects.toThrow("Update failed");
|
|
682
714
|
|
|
683
|
-
// Should restore snapshot
|
|
684
|
-
expect(mockNormalizedCache.upsert).toHaveBeenCalledWith(mockDoc);
|
|
715
|
+
// Should restore snapshot wholesale (replace, not merge)
|
|
716
|
+
expect(mockNormalizedCache.upsert).toHaveBeenCalledWith(mockDoc, { replace: true });
|
|
685
717
|
});
|
|
686
718
|
|
|
687
719
|
it("should not rollback when offline", async () => {
|
|
@@ -1022,8 +1054,8 @@ describe("MutationEngine", () => {
|
|
|
1022
1054
|
|
|
1023
1055
|
// Should still attempt snapshot rollback (upsert is called twice: once for optimistic update, once for rollback)
|
|
1024
1056
|
expect(mockNormalizedCache.upsert).toHaveBeenCalledTimes(2);
|
|
1025
|
-
// Last call should be the rollback with original snapshot
|
|
1026
|
-
expect(mockNormalizedCache.upsert).toHaveBeenLastCalledWith(mockDoc);
|
|
1057
|
+
// Last call should be the rollback with original snapshot (wholesale replace)
|
|
1058
|
+
expect(mockNormalizedCache.upsert).toHaveBeenLastCalledWith(mockDoc, { replace: true });
|
|
1027
1059
|
});
|
|
1028
1060
|
|
|
1029
1061
|
it("should handle custom version fields", async () => {
|
|
@@ -47,16 +47,30 @@ export class MutationEngine {
|
|
|
47
47
|
private pendingBatch: PendingBatchMutation<FrappeDocData>[] = [];
|
|
48
48
|
/** Debouncer for batch processing */
|
|
49
49
|
private batchDebouncer: Debouncer<() => Promise<void>>;
|
|
50
|
+
private readonly db: DbModule;
|
|
51
|
+
private readonly realtime: RealtimeModule | undefined;
|
|
52
|
+
private readonly normalizedCache: NormalizedCache;
|
|
53
|
+
private readonly mutationJournal: MutationJournal;
|
|
54
|
+
private readonly subscriptionManager: SubscriptionManager;
|
|
55
|
+
private readonly rehydrationManager: RehydrationManager;
|
|
56
|
+
private readonly options: SyncOptions;
|
|
50
57
|
|
|
51
58
|
constructor(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
db: DbModule,
|
|
60
|
+
realtime: RealtimeModule | undefined,
|
|
61
|
+
normalizedCache: NormalizedCache,
|
|
62
|
+
mutationJournal: MutationJournal,
|
|
63
|
+
subscriptionManager: SubscriptionManager,
|
|
64
|
+
rehydrationManager: RehydrationManager,
|
|
65
|
+
options: SyncOptions = {},
|
|
59
66
|
) {
|
|
67
|
+
this.db = db;
|
|
68
|
+
this.realtime = realtime;
|
|
69
|
+
this.normalizedCache = normalizedCache;
|
|
70
|
+
this.mutationJournal = mutationJournal;
|
|
71
|
+
this.subscriptionManager = subscriptionManager;
|
|
72
|
+
this.rehydrationManager = rehydrationManager;
|
|
73
|
+
this.options = options;
|
|
60
74
|
// Initialize batch debouncer
|
|
61
75
|
const batchDelay = options.batchDelay ?? 100;
|
|
62
76
|
this.batchDebouncer = new Debouncer(() => this.flushBatch(), { wait: batchDelay });
|
|
@@ -434,7 +448,11 @@ export class MutationEngine {
|
|
|
434
448
|
const docname = mutation.doc.name;
|
|
435
449
|
const doctype = mutation.doc.doctype;
|
|
436
450
|
const realName = (docname && this.temporaryIdToRealNameMap.get(docname)) || docname;
|
|
437
|
-
|
|
451
|
+
// A deleted doc no longer exists server-side — refetching it would 404
|
|
452
|
+
// and route a server-confirmed delete into the error/rollback path.
|
|
453
|
+
if (realName && mutation.operation !== Operation.Delete) {
|
|
454
|
+
targets.push({ doctype, name: realName });
|
|
455
|
+
}
|
|
438
456
|
if (mutation.affected?.length) targets.push(...mutation.affected);
|
|
439
457
|
// Fetch each target with user context to respect permissions and hidden fields
|
|
440
458
|
for (const target of targets) {
|
|
@@ -493,9 +511,10 @@ export class MutationEngine {
|
|
|
493
511
|
break;
|
|
494
512
|
|
|
495
513
|
case Operation.Update:
|
|
496
|
-
// Restore the original document from snapshot
|
|
514
|
+
// Restore the original document from snapshot (wholesale: an
|
|
515
|
+
// optimistic update may have added keys the snapshot never had)
|
|
497
516
|
if (entry?.snapshot && docname) {
|
|
498
|
-
this.normalizedCache.upsert(entry.snapshot);
|
|
517
|
+
this.normalizedCache.upsert(entry.snapshot, { replace: true });
|
|
499
518
|
// Also update subscription memberships in case filters changed
|
|
500
519
|
this.subscriptionManager.updateSubscriptionMembership(
|
|
501
520
|
entry.snapshot as FrappeDoc<FrappeDocData>,
|
|
@@ -506,7 +525,7 @@ export class MutationEngine {
|
|
|
506
525
|
case Operation.Delete:
|
|
507
526
|
// Restore the deleted document from snapshot
|
|
508
527
|
if (entry?.snapshot && docname) {
|
|
509
|
-
this.normalizedCache.upsert(entry.snapshot);
|
|
528
|
+
this.normalizedCache.upsert(entry.snapshot, { replace: true });
|
|
510
529
|
// Re-add to subscription memberships
|
|
511
530
|
const restoredDoc = entry.snapshot as FrappeDoc<FrappeDocData>;
|
|
512
531
|
for (const subscription of this.subscriptionManager.getAllSubscriptions().values()) {
|
|
@@ -27,6 +27,7 @@ export interface MutationJournalOptions {
|
|
|
27
27
|
|
|
28
28
|
export class MutationJournal {
|
|
29
29
|
private cleanupTimer?: ReturnType<typeof setInterval>;
|
|
30
|
+
private autoCleanupEnabled: boolean;
|
|
30
31
|
private ttl = 24 * 60 * 60 * 1000;
|
|
31
32
|
private pending = new Map<string, Pending>();
|
|
32
33
|
private sequenceNumber = 0;
|
|
@@ -40,9 +41,12 @@ export class MutationJournal {
|
|
|
40
41
|
this.storage = options.storage;
|
|
41
42
|
this.loadSequenceNumber();
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
// Auto-cleanup is armed lazily on the first add() rather than at
|
|
45
|
+
// construction: an empty journal has nothing to expire, and an
|
|
46
|
+
// unconditional interval was a leaked handle for every SyncModule that
|
|
47
|
+
// never mutated (one per fixture set in tests/stories — the pending
|
|
48
|
+
// hour-long timers helped wedge vitest forks-worker teardown).
|
|
49
|
+
this.autoCleanupEnabled = options?.enableAutoCleanup !== false;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
add(id: string, entry: Pending) {
|
|
@@ -51,6 +55,7 @@ export class MutationJournal {
|
|
|
51
55
|
if (entry.ttl === undefined) entry.ttl = this.ttl;
|
|
52
56
|
if (entry.retryCount === undefined) entry.retryCount = 0;
|
|
53
57
|
this.pending.set(id, entry);
|
|
58
|
+
if (this.autoCleanupEnabled) this.startAutoCleanup();
|
|
54
59
|
this.persistSequenceNumber();
|
|
55
60
|
}
|
|
56
61
|
|
|
@@ -124,6 +129,7 @@ export class MutationJournal {
|
|
|
124
129
|
|
|
125
130
|
clear() {
|
|
126
131
|
this.pending.clear();
|
|
132
|
+
this.stopAutoCleanup();
|
|
127
133
|
}
|
|
128
134
|
|
|
129
135
|
dispose() {
|
|
@@ -141,7 +147,15 @@ export class MutationJournal {
|
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
private startAutoCleanup() {
|
|
144
|
-
|
|
150
|
+
if (this.cleanupTimer) return;
|
|
151
|
+
this.cleanupTimer = setInterval(
|
|
152
|
+
() => {
|
|
153
|
+
this.cleanupExpired();
|
|
154
|
+
// Disarm once drained; the next add() re-arms.
|
|
155
|
+
if (this.pending.size === 0) this.stopAutoCleanup();
|
|
156
|
+
},
|
|
157
|
+
60 * 60 * 1000,
|
|
158
|
+
);
|
|
145
159
|
}
|
|
146
160
|
|
|
147
161
|
private loadSequenceNumber() {
|