@multiplatform.one/frappe 6.0.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/LICENSE +201 -0
- package/README.md +241 -0
- package/dist/cjs/auth.cjs +50 -0
- package/dist/cjs/auth.native.js +100 -0
- package/dist/cjs/auth.native.js.map +1 -0
- package/dist/cjs/auth.spec.cjs +322 -0
- package/dist/cjs/auth.spec.native.js +329 -0
- package/dist/cjs/auth.spec.native.js.map +1 -0
- package/dist/cjs/call.cjs +45 -0
- package/dist/cjs/call.native.js +93 -0
- package/dist/cjs/call.native.js.map +1 -0
- package/dist/cjs/call.spec.cjs +427 -0
- package/dist/cjs/call.spec.native.js +430 -0
- package/dist/cjs/call.spec.native.js.map +1 -0
- package/dist/cjs/collection.cjs +278 -0
- package/dist/cjs/collection.native.js +494 -0
- package/dist/cjs/collection.native.js.map +1 -0
- package/dist/cjs/collection.spec.cjs +186 -0
- package/dist/cjs/collection.spec.native.js +216 -0
- package/dist/cjs/collection.spec.native.js.map +1 -0
- package/dist/cjs/common/types.cjs +18 -0
- package/dist/cjs/common/types.native.js +21 -0
- package/dist/cjs/common/types.native.js.map +1 -0
- package/dist/cjs/common/types.spec.cjs +266 -0
- package/dist/cjs/common/types.spec.native.js +271 -0
- package/dist/cjs/common/types.spec.native.js.map +1 -0
- package/dist/cjs/core/http.cjs +289 -0
- package/dist/cjs/core/http.native.js +484 -0
- package/dist/cjs/core/http.native.js.map +1 -0
- package/dist/cjs/core/http.spec.cjs +1259 -0
- package/dist/cjs/core/http.spec.native.js +1401 -0
- package/dist/cjs/core/http.spec.native.js.map +1 -0
- package/dist/cjs/core/types.cjs +53 -0
- package/dist/cjs/core/types.native.js +178 -0
- package/dist/cjs/core/types.native.js.map +1 -0
- package/dist/cjs/core/wire.cjs +53 -0
- package/dist/cjs/core/wire.native.js +56 -0
- package/dist/cjs/core/wire.native.js.map +1 -0
- package/dist/cjs/core/wire.spec.cjs +478 -0
- package/dist/cjs/core/wire.spec.native.js +482 -0
- package/dist/cjs/core/wire.spec.native.js.map +1 -0
- package/dist/cjs/db.cjs +355 -0
- package/dist/cjs/db.native.js +469 -0
- package/dist/cjs/db.native.js.map +1 -0
- package/dist/cjs/db.spec.cjs +862 -0
- package/dist/cjs/db.spec.native.js +865 -0
- package/dist/cjs/db.spec.native.js.map +1 -0
- package/dist/cjs/devtools/FrappeDevtoolsPanel.cjs +838 -0
- package/dist/cjs/devtools/FrappeDevtoolsPanel.native.js +919 -0
- package/dist/cjs/devtools/FrappeDevtoolsPanel.native.js.map +1 -0
- package/dist/cjs/devtools/index.cjs +30 -0
- package/dist/cjs/devtools/index.native.js +33 -0
- package/dist/cjs/devtools/index.native.js.map +1 -0
- package/dist/cjs/devtools/plugin.cjs +39 -0
- package/dist/cjs/devtools/plugin.native.js +56 -0
- package/dist/cjs/devtools/plugin.native.js.map +1 -0
- package/dist/cjs/devtools/theme.cjs +55 -0
- package/dist/cjs/devtools/theme.native.js +58 -0
- package/dist/cjs/devtools/theme.native.js.map +1 -0
- package/dist/cjs/doctype.cjs +410 -0
- package/dist/cjs/doctype.native.js +521 -0
- package/dist/cjs/doctype.native.js.map +1 -0
- package/dist/cjs/doctype.spec.cjs +460 -0
- package/dist/cjs/doctype.spec.native.js +538 -0
- package/dist/cjs/doctype.spec.native.js.map +1 -0
- package/dist/cjs/file.cjs +41 -0
- package/dist/cjs/file.native.js +84 -0
- package/dist/cjs/file.native.js.map +1 -0
- package/dist/cjs/file.spec.cjs +315 -0
- package/dist/cjs/file.spec.native.js +342 -0
- package/dist/cjs/file.spec.native.js.map +1 -0
- package/dist/cjs/fixtureDb.cjs +212 -0
- package/dist/cjs/fixtureDb.native.js +313 -0
- package/dist/cjs/fixtureDb.native.js.map +1 -0
- package/dist/cjs/fixtures.cjs +199 -0
- package/dist/cjs/fixtures.native.js +400 -0
- package/dist/cjs/fixtures.native.js.map +1 -0
- package/dist/cjs/frappeApp.cjs +117 -0
- package/dist/cjs/frappeApp.native.js +179 -0
- package/dist/cjs/frappeApp.native.js.map +1 -0
- package/dist/cjs/frappeApp.spec.cjs +306 -0
- package/dist/cjs/frappeApp.spec.native.js +308 -0
- package/dist/cjs/frappeApp.spec.native.js.map +1 -0
- package/dist/cjs/frappeReact.cjs +314 -0
- package/dist/cjs/frappeReact.native.js +351 -0
- package/dist/cjs/frappeReact.native.js.map +1 -0
- package/dist/cjs/frappeReact.spec.cjs +531 -0
- package/dist/cjs/frappeReact.spec.native.js +670 -0
- package/dist/cjs/frappeReact.spec.native.js.map +1 -0
- package/dist/cjs/index.cjs +149 -0
- package/dist/cjs/index.native.js +152 -0
- package/dist/cjs/index.native.js.map +1 -0
- package/dist/cjs/optimistic.cjs +28 -0
- package/dist/cjs/optimistic.native.js +31 -0
- package/dist/cjs/optimistic.native.js.map +1 -0
- package/dist/cjs/optimistic.spec.cjs +11 -0
- package/dist/cjs/optimistic.spec.native.js +19 -0
- package/dist/cjs/optimistic.spec.native.js.map +1 -0
- package/dist/cjs/pacer.cjs +200 -0
- package/dist/cjs/pacer.native.js +274 -0
- package/dist/cjs/pacer.native.js.map +1 -0
- package/dist/cjs/pacer.spec.cjs +470 -0
- package/dist/cjs/pacer.spec.native.js +537 -0
- package/dist/cjs/pacer.spec.native.js.map +1 -0
- package/dist/cjs/plugin/index.cjs +124 -0
- package/dist/cjs/plugin/index.native.js +193 -0
- package/dist/cjs/plugin/index.native.js.map +1 -0
- package/dist/cjs/realtime.cjs +265 -0
- package/dist/cjs/realtime.native.js +387 -0
- package/dist/cjs/realtime.native.js.map +1 -0
- package/dist/cjs/realtime.spec.cjs +326 -0
- package/dist/cjs/realtime.spec.native.js +392 -0
- package/dist/cjs/realtime.spec.native.js.map +1 -0
- package/dist/cjs/sync/backfill.cjs +314 -0
- package/dist/cjs/sync/backfill.native.js +487 -0
- package/dist/cjs/sync/backfill.native.js.map +1 -0
- package/dist/cjs/sync/backfill.spec.cjs +586 -0
- package/dist/cjs/sync/backfill.spec.native.js +712 -0
- package/dist/cjs/sync/backfill.spec.native.js.map +1 -0
- package/dist/cjs/sync/debug.spec.cjs +125 -0
- package/dist/cjs/sync/debug.spec.native.js +133 -0
- package/dist/cjs/sync/debug.spec.native.js.map +1 -0
- package/dist/cjs/sync/filters.cjs +311 -0
- package/dist/cjs/sync/filters.native.js +446 -0
- package/dist/cjs/sync/filters.native.js.map +1 -0
- package/dist/cjs/sync/filters.spec.cjs +168 -0
- package/dist/cjs/sync/filters.spec.native.js +173 -0
- package/dist/cjs/sync/filters.spec.native.js.map +1 -0
- package/dist/cjs/sync/index.cjs +303 -0
- package/dist/cjs/sync/index.native.js +462 -0
- package/dist/cjs/sync/index.native.js.map +1 -0
- package/dist/cjs/sync/merge.cjs +435 -0
- package/dist/cjs/sync/merge.native.js +717 -0
- package/dist/cjs/sync/merge.native.js.map +1 -0
- package/dist/cjs/sync/merge.spec.cjs +908 -0
- package/dist/cjs/sync/merge.spec.native.js +937 -0
- package/dist/cjs/sync/merge.spec.native.js.map +1 -0
- package/dist/cjs/sync/multiOrderBy.spec.cjs +165 -0
- package/dist/cjs/sync/multiOrderBy.spec.native.js +229 -0
- package/dist/cjs/sync/multiOrderBy.spec.native.js.map +1 -0
- package/dist/cjs/sync/mutationEngine.cjs +781 -0
- package/dist/cjs/sync/mutationEngine.native.js +1159 -0
- package/dist/cjs/sync/mutationEngine.native.js.map +1 -0
- package/dist/cjs/sync/mutationEngine.spec.cjs +1158 -0
- package/dist/cjs/sync/mutationEngine.spec.native.js +1173 -0
- package/dist/cjs/sync/mutationEngine.spec.native.js.map +1 -0
- package/dist/cjs/sync/mutationJournal.cjs +150 -0
- package/dist/cjs/sync/mutationJournal.native.js +282 -0
- package/dist/cjs/sync/mutationJournal.native.js.map +1 -0
- package/dist/cjs/sync/mutationJournal.spec.cjs +330 -0
- package/dist/cjs/sync/mutationJournal.spec.native.js +333 -0
- package/dist/cjs/sync/mutationJournal.spec.native.js.map +1 -0
- package/dist/cjs/sync/mutations.spec.cjs +327 -0
- package/dist/cjs/sync/mutations.spec.native.js +330 -0
- package/dist/cjs/sync/mutations.spec.native.js.map +1 -0
- package/dist/cjs/sync/normalizedCache.cjs +140 -0
- package/dist/cjs/sync/normalizedCache.native.js +229 -0
- package/dist/cjs/sync/normalizedCache.native.js.map +1 -0
- package/dist/cjs/sync/normalizedCache.spec.cjs +302 -0
- package/dist/cjs/sync/normalizedCache.spec.native.js +311 -0
- package/dist/cjs/sync/normalizedCache.spec.native.js.map +1 -0
- package/dist/cjs/sync/persistence.cjs +627 -0
- package/dist/cjs/sync/persistence.native.js +911 -0
- package/dist/cjs/sync/persistence.native.js.map +1 -0
- package/dist/cjs/sync/persistence.spec.cjs +562 -0
- package/dist/cjs/sync/persistence.spec.native.js +572 -0
- package/dist/cjs/sync/persistence.spec.native.js.map +1 -0
- package/dist/cjs/sync/realtime.cjs +214 -0
- package/dist/cjs/sync/realtime.native.js +340 -0
- package/dist/cjs/sync/realtime.native.js.map +1 -0
- package/dist/cjs/sync/realtime.spec.cjs +499 -0
- package/dist/cjs/sync/realtime.spec.native.js +512 -0
- package/dist/cjs/sync/realtime.spec.native.js.map +1 -0
- package/dist/cjs/sync/rehydration.cjs +323 -0
- package/dist/cjs/sync/rehydration.native.js +531 -0
- package/dist/cjs/sync/rehydration.native.js.map +1 -0
- package/dist/cjs/sync/rehydration.spec.cjs +731 -0
- package/dist/cjs/sync/rehydration.spec.native.js +736 -0
- package/dist/cjs/sync/rehydration.spec.native.js.map +1 -0
- package/dist/cjs/sync/storage.cjs +142 -0
- package/dist/cjs/sync/storage.native.js +209 -0
- package/dist/cjs/sync/storage.native.js.map +1 -0
- package/dist/cjs/sync/storage.spec.cjs +446 -0
- package/dist/cjs/sync/storage.spec.native.js +470 -0
- package/dist/cjs/sync/storage.spec.native.js.map +1 -0
- package/dist/cjs/sync/subscriptionManager.cjs +487 -0
- package/dist/cjs/sync/subscriptionManager.native.js +948 -0
- package/dist/cjs/sync/subscriptionManager.native.js.map +1 -0
- package/dist/cjs/sync/subscriptionManager.spec.cjs +1102 -0
- package/dist/cjs/sync/subscriptionManager.spec.native.js +1136 -0
- package/dist/cjs/sync/subscriptionManager.spec.native.js.map +1 -0
- package/dist/cjs/sync/subscriptions.spec.cjs +937 -0
- package/dist/cjs/sync/subscriptions.spec.native.js +969 -0
- package/dist/cjs/sync/subscriptions.spec.native.js.map +1 -0
- package/dist/cjs/sync/syncModule.spec.cjs +206 -0
- package/dist/cjs/sync/syncModule.spec.native.js +222 -0
- package/dist/cjs/sync/syncModule.spec.native.js.map +1 -0
- package/dist/cjs/sync/types.cjs +99 -0
- package/dist/cjs/sync/types.native.js +102 -0
- package/dist/cjs/sync/types.native.js.map +1 -0
- package/dist/cjs/sync/types.spec.cjs +246 -0
- package/dist/cjs/sync/types.spec.native.js +256 -0
- package/dist/cjs/sync/types.spec.native.js.map +1 -0
- package/dist/cjs/sync/virtualPageManager.cjs +821 -0
- package/dist/cjs/sync/virtualPageManager.native.js +1125 -0
- package/dist/cjs/sync/virtualPageManager.native.js.map +1 -0
- package/dist/cjs/sync/virtualPageManager.spec.cjs +801 -0
- package/dist/cjs/sync/virtualPageManager.spec.native.js +873 -0
- package/dist/cjs/sync/virtualPageManager.spec.native.js.map +1 -0
- package/dist/cjs/util.cjs +31 -0
- package/dist/cjs/util.native.js +34 -0
- package/dist/cjs/util.native.js.map +1 -0
- package/dist/cjs/util.spec.cjs +43 -0
- package/dist/cjs/util.spec.native.js +48 -0
- package/dist/cjs/util.spec.native.js.map +1 -0
- package/dist/esm/auth.mjs +25 -0
- package/dist/esm/auth.mjs.map +1 -0
- package/dist/esm/auth.native.js +72 -0
- package/dist/esm/auth.native.js.map +1 -0
- package/dist/esm/auth.spec.mjs +323 -0
- package/dist/esm/auth.spec.mjs.map +1 -0
- package/dist/esm/auth.spec.native.js +327 -0
- package/dist/esm/auth.spec.native.js.map +1 -0
- package/dist/esm/call.mjs +20 -0
- package/dist/esm/call.mjs.map +1 -0
- package/dist/esm/call.native.js +65 -0
- package/dist/esm/call.native.js.map +1 -0
- package/dist/esm/call.spec.mjs +428 -0
- package/dist/esm/call.spec.mjs.map +1 -0
- package/dist/esm/call.spec.native.js +428 -0
- package/dist/esm/call.spec.native.js.map +1 -0
- package/dist/esm/collection.mjs +250 -0
- package/dist/esm/collection.mjs.map +1 -0
- package/dist/esm/collection.native.js +463 -0
- package/dist/esm/collection.native.js.map +1 -0
- package/dist/esm/collection.spec.mjs +187 -0
- package/dist/esm/collection.spec.mjs.map +1 -0
- package/dist/esm/collection.spec.native.js +214 -0
- package/dist/esm/collection.spec.native.js.map +1 -0
- package/dist/esm/common/types.mjs +2 -0
- package/dist/esm/common/types.mjs.map +1 -0
- package/dist/esm/common/types.native.js +2 -0
- package/dist/esm/common/types.native.js.map +1 -0
- package/dist/esm/common/types.spec.mjs +267 -0
- package/dist/esm/common/types.spec.mjs.map +1 -0
- package/dist/esm/common/types.spec.native.js +269 -0
- package/dist/esm/common/types.spec.native.js.map +1 -0
- package/dist/esm/core/http.mjs +258 -0
- package/dist/esm/core/http.mjs.map +1 -0
- package/dist/esm/core/http.native.js +450 -0
- package/dist/esm/core/http.native.js.map +1 -0
- package/dist/esm/core/http.spec.mjs +1260 -0
- package/dist/esm/core/http.spec.mjs.map +1 -0
- package/dist/esm/core/http.spec.native.js +1399 -0
- package/dist/esm/core/http.spec.native.js.map +1 -0
- package/dist/esm/core/types.mjs +26 -0
- package/dist/esm/core/types.mjs.map +1 -0
- package/dist/esm/core/types.native.js +148 -0
- package/dist/esm/core/types.native.js.map +1 -0
- package/dist/esm/core/wire.mjs +23 -0
- package/dist/esm/core/wire.mjs.map +1 -0
- package/dist/esm/core/wire.native.js +23 -0
- package/dist/esm/core/wire.native.js.map +1 -0
- package/dist/esm/core/wire.spec.mjs +479 -0
- package/dist/esm/core/wire.spec.mjs.map +1 -0
- package/dist/esm/core/wire.spec.native.js +480 -0
- package/dist/esm/core/wire.spec.native.js.map +1 -0
- package/dist/esm/db.mjs +329 -0
- package/dist/esm/db.mjs.map +1 -0
- package/dist/esm/db.native.js +440 -0
- package/dist/esm/db.native.js.map +1 -0
- package/dist/esm/db.spec.mjs +863 -0
- package/dist/esm/db.spec.mjs.map +1 -0
- package/dist/esm/db.spec.native.js +863 -0
- package/dist/esm/db.spec.native.js.map +1 -0
- package/dist/esm/devtools/FrappeDevtoolsPanel.mjs +813 -0
- package/dist/esm/devtools/FrappeDevtoolsPanel.mjs.map +1 -0
- package/dist/esm/devtools/FrappeDevtoolsPanel.native.js +880 -0
- package/dist/esm/devtools/FrappeDevtoolsPanel.native.js.map +1 -0
- package/dist/esm/devtools/index.mjs +4 -0
- package/dist/esm/devtools/index.mjs.map +1 -0
- package/dist/esm/devtools/index.native.js +4 -0
- package/dist/esm/devtools/index.native.js.map +1 -0
- package/dist/esm/devtools/plugin.mjs +14 -0
- package/dist/esm/devtools/plugin.mjs.map +1 -0
- package/dist/esm/devtools/plugin.native.js +17 -0
- package/dist/esm/devtools/plugin.native.js.map +1 -0
- package/dist/esm/devtools/theme.mjs +30 -0
- package/dist/esm/devtools/theme.mjs.map +1 -0
- package/dist/esm/devtools/theme.native.js +30 -0
- package/dist/esm/devtools/theme.native.js.map +1 -0
- package/dist/esm/doctype.mjs +381 -0
- package/dist/esm/doctype.mjs.map +1 -0
- package/dist/esm/doctype.native.js +489 -0
- package/dist/esm/doctype.native.js.map +1 -0
- package/dist/esm/doctype.spec.mjs +461 -0
- package/dist/esm/doctype.spec.mjs.map +1 -0
- package/dist/esm/doctype.spec.native.js +536 -0
- package/dist/esm/doctype.spec.native.js.map +1 -0
- package/dist/esm/file.mjs +16 -0
- package/dist/esm/file.mjs.map +1 -0
- package/dist/esm/file.native.js +56 -0
- package/dist/esm/file.native.js.map +1 -0
- package/dist/esm/file.spec.mjs +316 -0
- package/dist/esm/file.spec.mjs.map +1 -0
- package/dist/esm/file.spec.native.js +340 -0
- package/dist/esm/file.spec.native.js.map +1 -0
- package/dist/esm/fixtureDb.mjs +187 -0
- package/dist/esm/fixtureDb.mjs.map +1 -0
- package/dist/esm/fixtureDb.native.js +285 -0
- package/dist/esm/fixtureDb.native.js.map +1 -0
- package/dist/esm/fixtures.mjs +174 -0
- package/dist/esm/fixtures.mjs.map +1 -0
- package/dist/esm/fixtures.native.js +372 -0
- package/dist/esm/fixtures.native.js.map +1 -0
- package/dist/esm/frappeApp.mjs +92 -0
- package/dist/esm/frappeApp.mjs.map +1 -0
- package/dist/esm/frappeApp.native.js +151 -0
- package/dist/esm/frappeApp.native.js.map +1 -0
- package/dist/esm/frappeApp.spec.mjs +307 -0
- package/dist/esm/frappeApp.spec.mjs.map +1 -0
- package/dist/esm/frappeApp.spec.native.js +306 -0
- package/dist/esm/frappeApp.spec.native.js.map +1 -0
- package/dist/esm/frappeReact.mjs +286 -0
- package/dist/esm/frappeReact.mjs.map +1 -0
- package/dist/esm/frappeReact.native.js +320 -0
- package/dist/esm/frappeReact.native.js.map +1 -0
- package/dist/esm/frappeReact.spec.mjs +532 -0
- package/dist/esm/frappeReact.spec.mjs.map +1 -0
- package/dist/esm/frappeReact.spec.native.js +668 -0
- package/dist/esm/frappeReact.spec.native.js.map +1 -0
- package/dist/esm/index.mjs +25 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/index.native.js +25 -0
- package/dist/esm/index.native.js.map +1 -0
- package/dist/esm/optimistic.mjs +3 -0
- package/dist/esm/optimistic.mjs.map +1 -0
- package/dist/esm/optimistic.native.js +3 -0
- package/dist/esm/optimistic.native.js.map +1 -0
- package/dist/esm/optimistic.spec.mjs +12 -0
- package/dist/esm/optimistic.spec.mjs.map +1 -0
- package/dist/esm/optimistic.spec.native.js +17 -0
- package/dist/esm/optimistic.spec.native.js.map +1 -0
- package/dist/esm/pacer.mjs +173 -0
- package/dist/esm/pacer.mjs.map +1 -0
- package/dist/esm/pacer.native.js +244 -0
- package/dist/esm/pacer.native.js.map +1 -0
- package/dist/esm/pacer.spec.mjs +447 -0
- package/dist/esm/pacer.spec.mjs.map +1 -0
- package/dist/esm/pacer.spec.native.js +511 -0
- package/dist/esm/pacer.spec.native.js.map +1 -0
- package/dist/esm/plugin/index.mjs +99 -0
- package/dist/esm/plugin/index.mjs.map +1 -0
- package/dist/esm/plugin/index.native.js +165 -0
- package/dist/esm/plugin/index.native.js.map +1 -0
- package/dist/esm/realtime.mjs +239 -0
- package/dist/esm/realtime.mjs.map +1 -0
- package/dist/esm/realtime.native.js +358 -0
- package/dist/esm/realtime.native.js.map +1 -0
- package/dist/esm/realtime.spec.mjs +327 -0
- package/dist/esm/realtime.spec.mjs.map +1 -0
- package/dist/esm/realtime.spec.native.js +390 -0
- package/dist/esm/realtime.spec.native.js.map +1 -0
- package/dist/esm/sync/backfill.mjs +287 -0
- package/dist/esm/sync/backfill.mjs.map +1 -0
- package/dist/esm/sync/backfill.native.js +457 -0
- package/dist/esm/sync/backfill.native.js.map +1 -0
- package/dist/esm/sync/backfill.spec.mjs +563 -0
- package/dist/esm/sync/backfill.spec.mjs.map +1 -0
- package/dist/esm/sync/backfill.spec.native.js +686 -0
- package/dist/esm/sync/backfill.spec.native.js.map +1 -0
- package/dist/esm/sync/debug.spec.mjs +102 -0
- package/dist/esm/sync/debug.spec.mjs.map +1 -0
- package/dist/esm/sync/debug.spec.native.js +107 -0
- package/dist/esm/sync/debug.spec.native.js.map +1 -0
- package/dist/esm/sync/filters.mjs +276 -0
- package/dist/esm/sync/filters.mjs.map +1 -0
- package/dist/esm/sync/filters.native.js +408 -0
- package/dist/esm/sync/filters.native.js.map +1 -0
- package/dist/esm/sync/filters.spec.mjs +169 -0
- package/dist/esm/sync/filters.spec.mjs.map +1 -0
- package/dist/esm/sync/filters.spec.native.js +171 -0
- package/dist/esm/sync/filters.spec.native.js.map +1 -0
- package/dist/esm/sync/index.mjs +278 -0
- package/dist/esm/sync/index.mjs.map +1 -0
- package/dist/esm/sync/index.native.js +434 -0
- package/dist/esm/sync/index.native.js.map +1 -0
- package/dist/esm/sync/merge.mjs +396 -0
- package/dist/esm/sync/merge.mjs.map +1 -0
- package/dist/esm/sync/merge.native.js +675 -0
- package/dist/esm/sync/merge.native.js.map +1 -0
- package/dist/esm/sync/merge.spec.mjs +909 -0
- package/dist/esm/sync/merge.spec.mjs.map +1 -0
- package/dist/esm/sync/merge.spec.native.js +935 -0
- package/dist/esm/sync/merge.spec.native.js.map +1 -0
- package/dist/esm/sync/multiOrderBy.spec.mjs +166 -0
- package/dist/esm/sync/multiOrderBy.spec.mjs.map +1 -0
- package/dist/esm/sync/multiOrderBy.spec.native.js +227 -0
- package/dist/esm/sync/multiOrderBy.spec.native.js.map +1 -0
- package/dist/esm/sync/mutationEngine.mjs +756 -0
- package/dist/esm/sync/mutationEngine.mjs.map +1 -0
- package/dist/esm/sync/mutationEngine.native.js +1131 -0
- package/dist/esm/sync/mutationEngine.native.js.map +1 -0
- package/dist/esm/sync/mutationEngine.spec.mjs +1159 -0
- package/dist/esm/sync/mutationEngine.spec.mjs.map +1 -0
- package/dist/esm/sync/mutationEngine.spec.native.js +1171 -0
- package/dist/esm/sync/mutationEngine.spec.native.js.map +1 -0
- package/dist/esm/sync/mutationJournal.mjs +124 -0
- package/dist/esm/sync/mutationJournal.mjs.map +1 -0
- package/dist/esm/sync/mutationJournal.native.js +253 -0
- package/dist/esm/sync/mutationJournal.native.js.map +1 -0
- package/dist/esm/sync/mutationJournal.spec.mjs +331 -0
- package/dist/esm/sync/mutationJournal.spec.mjs.map +1 -0
- package/dist/esm/sync/mutationJournal.spec.native.js +331 -0
- package/dist/esm/sync/mutationJournal.spec.native.js.map +1 -0
- package/dist/esm/sync/mutations.spec.mjs +328 -0
- package/dist/esm/sync/mutations.spec.mjs.map +1 -0
- package/dist/esm/sync/mutations.spec.native.js +328 -0
- package/dist/esm/sync/mutations.spec.native.js.map +1 -0
- package/dist/esm/sync/normalizedCache.mjs +115 -0
- package/dist/esm/sync/normalizedCache.mjs.map +1 -0
- package/dist/esm/sync/normalizedCache.native.js +201 -0
- package/dist/esm/sync/normalizedCache.native.js.map +1 -0
- package/dist/esm/sync/normalizedCache.spec.mjs +303 -0
- package/dist/esm/sync/normalizedCache.spec.mjs.map +1 -0
- package/dist/esm/sync/normalizedCache.spec.native.js +309 -0
- package/dist/esm/sync/normalizedCache.spec.native.js.map +1 -0
- package/dist/esm/sync/persistence.mjs +602 -0
- package/dist/esm/sync/persistence.mjs.map +1 -0
- package/dist/esm/sync/persistence.native.js +883 -0
- package/dist/esm/sync/persistence.native.js.map +1 -0
- package/dist/esm/sync/persistence.spec.mjs +563 -0
- package/dist/esm/sync/persistence.spec.mjs.map +1 -0
- package/dist/esm/sync/persistence.spec.native.js +570 -0
- package/dist/esm/sync/persistence.spec.native.js.map +1 -0
- package/dist/esm/sync/realtime.mjs +189 -0
- package/dist/esm/sync/realtime.mjs.map +1 -0
- package/dist/esm/sync/realtime.native.js +312 -0
- package/dist/esm/sync/realtime.native.js.map +1 -0
- package/dist/esm/sync/realtime.spec.mjs +500 -0
- package/dist/esm/sync/realtime.spec.mjs.map +1 -0
- package/dist/esm/sync/realtime.spec.native.js +510 -0
- package/dist/esm/sync/realtime.spec.native.js.map +1 -0
- package/dist/esm/sync/rehydration.mjs +298 -0
- package/dist/esm/sync/rehydration.mjs.map +1 -0
- package/dist/esm/sync/rehydration.native.js +503 -0
- package/dist/esm/sync/rehydration.native.js.map +1 -0
- package/dist/esm/sync/rehydration.spec.mjs +732 -0
- package/dist/esm/sync/rehydration.spec.mjs.map +1 -0
- package/dist/esm/sync/rehydration.spec.native.js +734 -0
- package/dist/esm/sync/rehydration.spec.native.js.map +1 -0
- package/dist/esm/sync/storage.mjs +116 -0
- package/dist/esm/sync/storage.mjs.map +1 -0
- package/dist/esm/sync/storage.native.js +180 -0
- package/dist/esm/sync/storage.native.js.map +1 -0
- package/dist/esm/sync/storage.spec.mjs +423 -0
- package/dist/esm/sync/storage.spec.mjs.map +1 -0
- package/dist/esm/sync/storage.spec.native.js +444 -0
- package/dist/esm/sync/storage.spec.native.js.map +1 -0
- package/dist/esm/sync/subscriptionManager.mjs +462 -0
- package/dist/esm/sync/subscriptionManager.mjs.map +1 -0
- package/dist/esm/sync/subscriptionManager.native.js +920 -0
- package/dist/esm/sync/subscriptionManager.native.js.map +1 -0
- package/dist/esm/sync/subscriptionManager.spec.mjs +1079 -0
- package/dist/esm/sync/subscriptionManager.spec.mjs.map +1 -0
- package/dist/esm/sync/subscriptionManager.spec.native.js +1110 -0
- package/dist/esm/sync/subscriptionManager.spec.native.js.map +1 -0
- package/dist/esm/sync/subscriptions.spec.mjs +914 -0
- package/dist/esm/sync/subscriptions.spec.mjs.map +1 -0
- package/dist/esm/sync/subscriptions.spec.native.js +943 -0
- package/dist/esm/sync/subscriptions.spec.native.js.map +1 -0
- package/dist/esm/sync/syncModule.spec.mjs +207 -0
- package/dist/esm/sync/syncModule.spec.mjs.map +1 -0
- package/dist/esm/sync/syncModule.spec.native.js +220 -0
- package/dist/esm/sync/syncModule.spec.native.js.map +1 -0
- package/dist/esm/sync/types.mjs +65 -0
- package/dist/esm/sync/types.mjs.map +1 -0
- package/dist/esm/sync/types.native.js +65 -0
- package/dist/esm/sync/types.native.js.map +1 -0
- package/dist/esm/sync/types.spec.mjs +247 -0
- package/dist/esm/sync/types.spec.mjs.map +1 -0
- package/dist/esm/sync/types.spec.native.js +254 -0
- package/dist/esm/sync/types.spec.native.js.map +1 -0
- package/dist/esm/sync/virtualPageManager.mjs +794 -0
- package/dist/esm/sync/virtualPageManager.mjs.map +1 -0
- package/dist/esm/sync/virtualPageManager.native.js +1095 -0
- package/dist/esm/sync/virtualPageManager.native.js.map +1 -0
- package/dist/esm/sync/virtualPageManager.spec.mjs +802 -0
- package/dist/esm/sync/virtualPageManager.spec.mjs.map +1 -0
- package/dist/esm/sync/virtualPageManager.spec.native.js +871 -0
- package/dist/esm/sync/virtualPageManager.spec.native.js.map +1 -0
- package/dist/esm/util.mjs +6 -0
- package/dist/esm/util.mjs.map +1 -0
- package/dist/esm/util.native.js +6 -0
- package/dist/esm/util.native.js.map +1 -0
- package/dist/esm/util.spec.mjs +20 -0
- package/dist/esm/util.spec.mjs.map +1 -0
- package/dist/esm/util.spec.native.js +22 -0
- package/dist/esm/util.spec.native.js.map +1 -0
- package/dist/jsx/auth.mjs +25 -0
- package/dist/jsx/auth.mjs.map +1 -0
- package/dist/jsx/auth.native.js +100 -0
- package/dist/jsx/auth.native.js.map +1 -0
- package/dist/jsx/auth.spec.mjs +323 -0
- package/dist/jsx/auth.spec.mjs.map +1 -0
- package/dist/jsx/auth.spec.native.js +329 -0
- package/dist/jsx/auth.spec.native.js.map +1 -0
- package/dist/jsx/call.mjs +20 -0
- package/dist/jsx/call.mjs.map +1 -0
- package/dist/jsx/call.native.js +93 -0
- package/dist/jsx/call.native.js.map +1 -0
- package/dist/jsx/call.spec.mjs +428 -0
- package/dist/jsx/call.spec.mjs.map +1 -0
- package/dist/jsx/call.spec.native.js +430 -0
- package/dist/jsx/call.spec.native.js.map +1 -0
- package/dist/jsx/collection.mjs +250 -0
- package/dist/jsx/collection.mjs.map +1 -0
- package/dist/jsx/collection.native.js +494 -0
- package/dist/jsx/collection.native.js.map +1 -0
- package/dist/jsx/collection.spec.mjs +187 -0
- package/dist/jsx/collection.spec.mjs.map +1 -0
- package/dist/jsx/collection.spec.native.js +216 -0
- package/dist/jsx/collection.spec.native.js.map +1 -0
- package/dist/jsx/common/types.mjs +2 -0
- package/dist/jsx/common/types.mjs.map +1 -0
- package/dist/jsx/common/types.native.js +21 -0
- package/dist/jsx/common/types.native.js.map +1 -0
- package/dist/jsx/common/types.spec.mjs +267 -0
- package/dist/jsx/common/types.spec.mjs.map +1 -0
- package/dist/jsx/common/types.spec.native.js +271 -0
- package/dist/jsx/common/types.spec.native.js.map +1 -0
- package/dist/jsx/core/http.mjs +258 -0
- package/dist/jsx/core/http.mjs.map +1 -0
- package/dist/jsx/core/http.native.js +484 -0
- package/dist/jsx/core/http.native.js.map +1 -0
- package/dist/jsx/core/http.spec.mjs +1260 -0
- package/dist/jsx/core/http.spec.mjs.map +1 -0
- package/dist/jsx/core/http.spec.native.js +1401 -0
- package/dist/jsx/core/http.spec.native.js.map +1 -0
- package/dist/jsx/core/types.mjs +26 -0
- package/dist/jsx/core/types.mjs.map +1 -0
- package/dist/jsx/core/types.native.js +178 -0
- package/dist/jsx/core/types.native.js.map +1 -0
- package/dist/jsx/core/wire.mjs +23 -0
- package/dist/jsx/core/wire.mjs.map +1 -0
- package/dist/jsx/core/wire.native.js +56 -0
- package/dist/jsx/core/wire.native.js.map +1 -0
- package/dist/jsx/core/wire.spec.mjs +479 -0
- package/dist/jsx/core/wire.spec.mjs.map +1 -0
- package/dist/jsx/core/wire.spec.native.js +482 -0
- package/dist/jsx/core/wire.spec.native.js.map +1 -0
- package/dist/jsx/db.mjs +329 -0
- package/dist/jsx/db.mjs.map +1 -0
- package/dist/jsx/db.native.js +469 -0
- package/dist/jsx/db.native.js.map +1 -0
- package/dist/jsx/db.spec.mjs +863 -0
- package/dist/jsx/db.spec.mjs.map +1 -0
- package/dist/jsx/db.spec.native.js +865 -0
- package/dist/jsx/db.spec.native.js.map +1 -0
- package/dist/jsx/devtools/FrappeDevtoolsPanel.mjs +813 -0
- package/dist/jsx/devtools/FrappeDevtoolsPanel.mjs.map +1 -0
- package/dist/jsx/devtools/FrappeDevtoolsPanel.native.js +919 -0
- package/dist/jsx/devtools/FrappeDevtoolsPanel.native.js.map +1 -0
- package/dist/jsx/devtools/index.mjs +4 -0
- package/dist/jsx/devtools/index.mjs.map +1 -0
- package/dist/jsx/devtools/index.native.js +33 -0
- package/dist/jsx/devtools/index.native.js.map +1 -0
- package/dist/jsx/devtools/plugin.mjs +14 -0
- package/dist/jsx/devtools/plugin.mjs.map +1 -0
- package/dist/jsx/devtools/plugin.native.js +56 -0
- package/dist/jsx/devtools/plugin.native.js.map +1 -0
- package/dist/jsx/devtools/theme.mjs +30 -0
- package/dist/jsx/devtools/theme.mjs.map +1 -0
- package/dist/jsx/devtools/theme.native.js +58 -0
- package/dist/jsx/devtools/theme.native.js.map +1 -0
- package/dist/jsx/doctype.mjs +381 -0
- package/dist/jsx/doctype.mjs.map +1 -0
- package/dist/jsx/doctype.native.js +521 -0
- package/dist/jsx/doctype.native.js.map +1 -0
- package/dist/jsx/doctype.spec.mjs +461 -0
- package/dist/jsx/doctype.spec.mjs.map +1 -0
- package/dist/jsx/doctype.spec.native.js +538 -0
- package/dist/jsx/doctype.spec.native.js.map +1 -0
- package/dist/jsx/file.mjs +16 -0
- package/dist/jsx/file.mjs.map +1 -0
- package/dist/jsx/file.native.js +84 -0
- package/dist/jsx/file.native.js.map +1 -0
- package/dist/jsx/file.spec.mjs +316 -0
- package/dist/jsx/file.spec.mjs.map +1 -0
- package/dist/jsx/file.spec.native.js +342 -0
- package/dist/jsx/file.spec.native.js.map +1 -0
- package/dist/jsx/fixtureDb.mjs +187 -0
- package/dist/jsx/fixtureDb.mjs.map +1 -0
- package/dist/jsx/fixtureDb.native.js +313 -0
- package/dist/jsx/fixtureDb.native.js.map +1 -0
- package/dist/jsx/fixtures.mjs +174 -0
- package/dist/jsx/fixtures.mjs.map +1 -0
- package/dist/jsx/fixtures.native.js +400 -0
- package/dist/jsx/fixtures.native.js.map +1 -0
- package/dist/jsx/frappeApp.mjs +92 -0
- package/dist/jsx/frappeApp.mjs.map +1 -0
- package/dist/jsx/frappeApp.native.js +179 -0
- package/dist/jsx/frappeApp.native.js.map +1 -0
- package/dist/jsx/frappeApp.spec.mjs +307 -0
- package/dist/jsx/frappeApp.spec.mjs.map +1 -0
- package/dist/jsx/frappeApp.spec.native.js +308 -0
- package/dist/jsx/frappeApp.spec.native.js.map +1 -0
- package/dist/jsx/frappeReact.mjs +286 -0
- package/dist/jsx/frappeReact.mjs.map +1 -0
- package/dist/jsx/frappeReact.native.js +351 -0
- package/dist/jsx/frappeReact.native.js.map +1 -0
- package/dist/jsx/frappeReact.spec.mjs +532 -0
- package/dist/jsx/frappeReact.spec.mjs.map +1 -0
- package/dist/jsx/frappeReact.spec.native.js +670 -0
- package/dist/jsx/frappeReact.spec.native.js.map +1 -0
- package/dist/jsx/index.js +25 -0
- package/dist/jsx/index.js.map +1 -0
- package/dist/jsx/index.mjs +25 -0
- package/dist/jsx/index.mjs.map +1 -0
- package/dist/jsx/index.native.js +152 -0
- package/dist/jsx/index.native.js.map +1 -0
- package/dist/jsx/optimistic.mjs +3 -0
- package/dist/jsx/optimistic.mjs.map +1 -0
- package/dist/jsx/optimistic.native.js +31 -0
- package/dist/jsx/optimistic.native.js.map +1 -0
- package/dist/jsx/optimistic.spec.mjs +12 -0
- package/dist/jsx/optimistic.spec.mjs.map +1 -0
- package/dist/jsx/optimistic.spec.native.js +19 -0
- package/dist/jsx/optimistic.spec.native.js.map +1 -0
- package/dist/jsx/pacer.mjs +173 -0
- package/dist/jsx/pacer.mjs.map +1 -0
- package/dist/jsx/pacer.native.js +274 -0
- package/dist/jsx/pacer.native.js.map +1 -0
- package/dist/jsx/pacer.spec.mjs +447 -0
- package/dist/jsx/pacer.spec.mjs.map +1 -0
- package/dist/jsx/pacer.spec.native.js +537 -0
- package/dist/jsx/pacer.spec.native.js.map +1 -0
- package/dist/jsx/plugin/index.mjs +99 -0
- package/dist/jsx/plugin/index.mjs.map +1 -0
- package/dist/jsx/plugin/index.native.js +193 -0
- package/dist/jsx/plugin/index.native.js.map +1 -0
- package/dist/jsx/realtime.mjs +239 -0
- package/dist/jsx/realtime.mjs.map +1 -0
- package/dist/jsx/realtime.native.js +387 -0
- package/dist/jsx/realtime.native.js.map +1 -0
- package/dist/jsx/realtime.spec.mjs +327 -0
- package/dist/jsx/realtime.spec.mjs.map +1 -0
- package/dist/jsx/realtime.spec.native.js +392 -0
- package/dist/jsx/realtime.spec.native.js.map +1 -0
- package/dist/jsx/sync/backfill.mjs +287 -0
- package/dist/jsx/sync/backfill.mjs.map +1 -0
- package/dist/jsx/sync/backfill.native.js +487 -0
- package/dist/jsx/sync/backfill.native.js.map +1 -0
- package/dist/jsx/sync/backfill.spec.mjs +563 -0
- package/dist/jsx/sync/backfill.spec.mjs.map +1 -0
- package/dist/jsx/sync/backfill.spec.native.js +712 -0
- package/dist/jsx/sync/backfill.spec.native.js.map +1 -0
- package/dist/jsx/sync/debug.spec.mjs +102 -0
- package/dist/jsx/sync/debug.spec.mjs.map +1 -0
- package/dist/jsx/sync/debug.spec.native.js +133 -0
- package/dist/jsx/sync/debug.spec.native.js.map +1 -0
- package/dist/jsx/sync/filters.mjs +276 -0
- package/dist/jsx/sync/filters.mjs.map +1 -0
- package/dist/jsx/sync/filters.native.js +446 -0
- package/dist/jsx/sync/filters.native.js.map +1 -0
- package/dist/jsx/sync/filters.spec.mjs +169 -0
- package/dist/jsx/sync/filters.spec.mjs.map +1 -0
- package/dist/jsx/sync/filters.spec.native.js +173 -0
- package/dist/jsx/sync/filters.spec.native.js.map +1 -0
- package/dist/jsx/sync/index.mjs +278 -0
- package/dist/jsx/sync/index.mjs.map +1 -0
- package/dist/jsx/sync/index.native.js +462 -0
- package/dist/jsx/sync/index.native.js.map +1 -0
- package/dist/jsx/sync/merge.mjs +396 -0
- package/dist/jsx/sync/merge.mjs.map +1 -0
- package/dist/jsx/sync/merge.native.js +717 -0
- package/dist/jsx/sync/merge.native.js.map +1 -0
- package/dist/jsx/sync/merge.spec.mjs +909 -0
- package/dist/jsx/sync/merge.spec.mjs.map +1 -0
- package/dist/jsx/sync/merge.spec.native.js +937 -0
- package/dist/jsx/sync/merge.spec.native.js.map +1 -0
- package/dist/jsx/sync/multiOrderBy.spec.mjs +166 -0
- package/dist/jsx/sync/multiOrderBy.spec.mjs.map +1 -0
- package/dist/jsx/sync/multiOrderBy.spec.native.js +229 -0
- package/dist/jsx/sync/multiOrderBy.spec.native.js.map +1 -0
- package/dist/jsx/sync/mutationEngine.mjs +756 -0
- package/dist/jsx/sync/mutationEngine.mjs.map +1 -0
- package/dist/jsx/sync/mutationEngine.native.js +1159 -0
- package/dist/jsx/sync/mutationEngine.native.js.map +1 -0
- package/dist/jsx/sync/mutationEngine.spec.mjs +1159 -0
- package/dist/jsx/sync/mutationEngine.spec.mjs.map +1 -0
- package/dist/jsx/sync/mutationEngine.spec.native.js +1173 -0
- package/dist/jsx/sync/mutationEngine.spec.native.js.map +1 -0
- package/dist/jsx/sync/mutationJournal.mjs +124 -0
- package/dist/jsx/sync/mutationJournal.mjs.map +1 -0
- package/dist/jsx/sync/mutationJournal.native.js +282 -0
- package/dist/jsx/sync/mutationJournal.native.js.map +1 -0
- package/dist/jsx/sync/mutationJournal.spec.mjs +331 -0
- package/dist/jsx/sync/mutationJournal.spec.mjs.map +1 -0
- package/dist/jsx/sync/mutationJournal.spec.native.js +333 -0
- package/dist/jsx/sync/mutationJournal.spec.native.js.map +1 -0
- package/dist/jsx/sync/mutations.spec.mjs +328 -0
- package/dist/jsx/sync/mutations.spec.mjs.map +1 -0
- package/dist/jsx/sync/mutations.spec.native.js +330 -0
- package/dist/jsx/sync/mutations.spec.native.js.map +1 -0
- package/dist/jsx/sync/normalizedCache.mjs +115 -0
- package/dist/jsx/sync/normalizedCache.mjs.map +1 -0
- package/dist/jsx/sync/normalizedCache.native.js +229 -0
- package/dist/jsx/sync/normalizedCache.native.js.map +1 -0
- package/dist/jsx/sync/normalizedCache.spec.mjs +303 -0
- package/dist/jsx/sync/normalizedCache.spec.mjs.map +1 -0
- package/dist/jsx/sync/normalizedCache.spec.native.js +311 -0
- package/dist/jsx/sync/normalizedCache.spec.native.js.map +1 -0
- package/dist/jsx/sync/persistence.mjs +602 -0
- package/dist/jsx/sync/persistence.mjs.map +1 -0
- package/dist/jsx/sync/persistence.native.js +911 -0
- package/dist/jsx/sync/persistence.native.js.map +1 -0
- package/dist/jsx/sync/persistence.spec.mjs +563 -0
- package/dist/jsx/sync/persistence.spec.mjs.map +1 -0
- package/dist/jsx/sync/persistence.spec.native.js +572 -0
- package/dist/jsx/sync/persistence.spec.native.js.map +1 -0
- package/dist/jsx/sync/realtime.mjs +189 -0
- package/dist/jsx/sync/realtime.mjs.map +1 -0
- package/dist/jsx/sync/realtime.native.js +340 -0
- package/dist/jsx/sync/realtime.native.js.map +1 -0
- package/dist/jsx/sync/realtime.spec.mjs +500 -0
- package/dist/jsx/sync/realtime.spec.mjs.map +1 -0
- package/dist/jsx/sync/realtime.spec.native.js +512 -0
- package/dist/jsx/sync/realtime.spec.native.js.map +1 -0
- package/dist/jsx/sync/rehydration.mjs +298 -0
- package/dist/jsx/sync/rehydration.mjs.map +1 -0
- package/dist/jsx/sync/rehydration.native.js +531 -0
- package/dist/jsx/sync/rehydration.native.js.map +1 -0
- package/dist/jsx/sync/rehydration.spec.mjs +732 -0
- package/dist/jsx/sync/rehydration.spec.mjs.map +1 -0
- package/dist/jsx/sync/rehydration.spec.native.js +736 -0
- package/dist/jsx/sync/rehydration.spec.native.js.map +1 -0
- package/dist/jsx/sync/storage.mjs +116 -0
- package/dist/jsx/sync/storage.mjs.map +1 -0
- package/dist/jsx/sync/storage.native.js +209 -0
- package/dist/jsx/sync/storage.native.js.map +1 -0
- package/dist/jsx/sync/storage.spec.mjs +423 -0
- package/dist/jsx/sync/storage.spec.mjs.map +1 -0
- package/dist/jsx/sync/storage.spec.native.js +470 -0
- package/dist/jsx/sync/storage.spec.native.js.map +1 -0
- package/dist/jsx/sync/subscriptionManager.mjs +462 -0
- package/dist/jsx/sync/subscriptionManager.mjs.map +1 -0
- package/dist/jsx/sync/subscriptionManager.native.js +948 -0
- package/dist/jsx/sync/subscriptionManager.native.js.map +1 -0
- package/dist/jsx/sync/subscriptionManager.spec.mjs +1079 -0
- package/dist/jsx/sync/subscriptionManager.spec.mjs.map +1 -0
- package/dist/jsx/sync/subscriptionManager.spec.native.js +1136 -0
- package/dist/jsx/sync/subscriptionManager.spec.native.js.map +1 -0
- package/dist/jsx/sync/subscriptions.spec.mjs +914 -0
- package/dist/jsx/sync/subscriptions.spec.mjs.map +1 -0
- package/dist/jsx/sync/subscriptions.spec.native.js +969 -0
- package/dist/jsx/sync/subscriptions.spec.native.js.map +1 -0
- package/dist/jsx/sync/syncModule.spec.mjs +207 -0
- package/dist/jsx/sync/syncModule.spec.mjs.map +1 -0
- package/dist/jsx/sync/syncModule.spec.native.js +222 -0
- package/dist/jsx/sync/syncModule.spec.native.js.map +1 -0
- package/dist/jsx/sync/types.mjs +65 -0
- package/dist/jsx/sync/types.mjs.map +1 -0
- package/dist/jsx/sync/types.native.js +102 -0
- package/dist/jsx/sync/types.native.js.map +1 -0
- package/dist/jsx/sync/types.spec.mjs +247 -0
- package/dist/jsx/sync/types.spec.mjs.map +1 -0
- package/dist/jsx/sync/types.spec.native.js +256 -0
- package/dist/jsx/sync/types.spec.native.js.map +1 -0
- package/dist/jsx/sync/virtualPageManager.mjs +794 -0
- package/dist/jsx/sync/virtualPageManager.mjs.map +1 -0
- package/dist/jsx/sync/virtualPageManager.native.js +1125 -0
- package/dist/jsx/sync/virtualPageManager.native.js.map +1 -0
- package/dist/jsx/sync/virtualPageManager.spec.mjs +802 -0
- package/dist/jsx/sync/virtualPageManager.spec.mjs.map +1 -0
- package/dist/jsx/sync/virtualPageManager.spec.native.js +873 -0
- package/dist/jsx/sync/virtualPageManager.spec.native.js.map +1 -0
- package/dist/jsx/util.mjs +6 -0
- package/dist/jsx/util.mjs.map +1 -0
- package/dist/jsx/util.native.js +34 -0
- package/dist/jsx/util.native.js.map +1 -0
- package/dist/jsx/util.spec.mjs +20 -0
- package/dist/jsx/util.spec.mjs.map +1 -0
- package/dist/jsx/util.spec.native.js +48 -0
- package/dist/jsx/util.spec.native.js.map +1 -0
- package/package.json +96 -0
- package/src/auth.spec.ts +363 -0
- package/src/auth.ts +29 -0
- package/src/call.spec.ts +541 -0
- package/src/call.ts +21 -0
- package/src/collection.spec.ts +213 -0
- package/src/collection.ts +328 -0
- package/src/common/types.spec.ts +294 -0
- package/src/common/types.ts +41 -0
- package/src/core/http.spec.ts +1128 -0
- package/src/core/http.ts +324 -0
- package/src/core/types.ts +85 -0
- package/src/core/wire.spec.ts +570 -0
- package/src/core/wire.ts +487 -0
- package/src/db.spec.ts +1004 -0
- package/src/db.ts +589 -0
- package/src/devtools/FrappeDevtoolsPanel.tsx +873 -0
- package/src/devtools/index.ts +3 -0
- package/src/devtools/plugin.tsx +13 -0
- package/src/devtools/theme.ts +42 -0
- package/src/doctype.spec.ts +451 -0
- package/src/doctype.ts +828 -0
- package/src/file.spec.ts +347 -0
- package/src/file.ts +27 -0
- package/src/fixtureDb.ts +208 -0
- package/src/fixtures.ts +268 -0
- package/src/frappeApp.spec.ts +382 -0
- package/src/frappeApp.ts +125 -0
- package/src/frappeReact.spec.ts +505 -0
- package/src/frappeReact.ts +598 -0
- package/src/index.ts +215 -0
- package/src/optimistic.spec.ts +13 -0
- package/src/optimistic.ts +39 -0
- package/src/pacer.spec.ts +493 -0
- package/src/pacer.ts +426 -0
- package/src/plugin/README.md +162 -0
- package/src/plugin/index.ts +141 -0
- package/src/realtime.spec.ts +453 -0
- package/src/realtime.ts +279 -0
- package/src/sync/backfill.spec.ts +714 -0
- package/src/sync/backfill.ts +378 -0
- package/src/sync/debug.spec.ts +110 -0
- package/src/sync/filters.spec.ts +223 -0
- package/src/sync/filters.ts +513 -0
- package/src/sync/index.ts +412 -0
- package/src/sync/merge.spec.ts +812 -0
- package/src/sync/merge.ts +532 -0
- package/src/sync/multiOrderBy.spec.ts +187 -0
- package/src/sync/mutationEngine.spec.ts +1418 -0
- package/src/sync/mutationEngine.ts +957 -0
- package/src/sync/mutationJournal.spec.ts +337 -0
- package/src/sync/mutationJournal.ts +157 -0
- package/src/sync/mutations.spec.ts +358 -0
- package/src/sync/normalizedCache.spec.ts +262 -0
- package/src/sync/normalizedCache.ts +152 -0
- package/src/sync/persistence.spec.ts +908 -0
- package/src/sync/persistence.ts +802 -0
- package/src/sync/realtime.spec.ts +769 -0
- package/src/sync/realtime.ts +259 -0
- package/src/sync/rehydration.spec.ts +923 -0
- package/src/sync/rehydration.ts +362 -0
- package/src/sync/storage.spec.ts +473 -0
- package/src/sync/storage.ts +174 -0
- package/src/sync/subscriptionManager.spec.ts +1226 -0
- package/src/sync/subscriptionManager.ts +577 -0
- package/src/sync/subscriptions.spec.ts +1048 -0
- package/src/sync/syncModule.spec.ts +217 -0
- package/src/sync/types.spec.ts +276 -0
- package/src/sync/types.ts +384 -0
- package/src/sync/virtualPageManager.spec.ts +825 -0
- package/src/sync/virtualPageManager.ts +1069 -0
- package/src/util.spec.ts +17 -0
- package/src/util.ts +5 -0
|
@@ -0,0 +1,1226 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import type { FrappeDoc, FrappeDocData } from "../common/types";
|
|
3
|
+
import { SubscriptionManager } from "./subscriptionManager";
|
|
4
|
+
import { BackfillScope } from "./types";
|
|
5
|
+
import { Order } from "./types";
|
|
6
|
+
import type { SubscriptionQuery, SyncOptions } from "./types";
|
|
7
|
+
|
|
8
|
+
// Use real implementations - no mocking needed for internal modules
|
|
9
|
+
import * as filters from "./filters";
|
|
10
|
+
|
|
11
|
+
describe("SubscriptionManager", () => {
|
|
12
|
+
let subscriptionManager: SubscriptionManager;
|
|
13
|
+
let mockDb: any;
|
|
14
|
+
let mockNormalizedCache: any;
|
|
15
|
+
|
|
16
|
+
const mockDoc: FrappeDoc<FrappeDocData> = {
|
|
17
|
+
name: "test-doc",
|
|
18
|
+
doctype: "TestDoc",
|
|
19
|
+
title: "Test Document",
|
|
20
|
+
modified: "2024-01-01T10:00:00",
|
|
21
|
+
creation: "2024-01-01T09:00:00",
|
|
22
|
+
owner: "test-user",
|
|
23
|
+
modified_by: "test-user",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const mockDocs: any[] = [
|
|
27
|
+
{
|
|
28
|
+
name: "doc1",
|
|
29
|
+
doctype: "TestDoc",
|
|
30
|
+
modified: "2024-01-01T09:00:00",
|
|
31
|
+
title: "Document 1",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "doc2",
|
|
35
|
+
doctype: "TestDoc",
|
|
36
|
+
modified: "2024-01-01T10:00:00",
|
|
37
|
+
title: "Document 2",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "doc3",
|
|
41
|
+
doctype: "TestDoc",
|
|
42
|
+
modified: "2024-01-01T11:00:00",
|
|
43
|
+
title: "Document 3",
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
let uuidCount = 0;
|
|
48
|
+
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
uuidCount = 0;
|
|
51
|
+
|
|
52
|
+
// Spy on filters functions with default behavior
|
|
53
|
+
vi.spyOn(filters, "matchesFilters").mockReturnValue(true);
|
|
54
|
+
vi.spyOn(filters, "extractSingleName").mockReturnValue(undefined);
|
|
55
|
+
|
|
56
|
+
// Mock database module
|
|
57
|
+
mockDb = {
|
|
58
|
+
getDoc: vi.fn().mockResolvedValue(mockDoc),
|
|
59
|
+
getDocList: vi.fn().mockResolvedValue(mockDocs),
|
|
60
|
+
backfill: vi.fn().mockResolvedValue({
|
|
61
|
+
rows: [],
|
|
62
|
+
checkpoint: "2024-01-01T12:00:00",
|
|
63
|
+
}),
|
|
64
|
+
} as any;
|
|
65
|
+
|
|
66
|
+
// Mock normalized cache
|
|
67
|
+
mockNormalizedCache = {
|
|
68
|
+
upsert: vi.fn(),
|
|
69
|
+
get: vi.fn().mockImplementation(({ name }: { name: string }) => {
|
|
70
|
+
return mockDocs.find((doc) => doc.name === name) || mockDoc;
|
|
71
|
+
}),
|
|
72
|
+
remove: vi.fn(),
|
|
73
|
+
} as any;
|
|
74
|
+
|
|
75
|
+
// Mock crypto for ID generation - use sequential IDs so multiple subscribes get unique IDs
|
|
76
|
+
Object.defineProperty(global, "crypto", {
|
|
77
|
+
value: {
|
|
78
|
+
randomUUID: vi.fn().mockImplementation(() => `uuid-${++uuidCount}`),
|
|
79
|
+
},
|
|
80
|
+
writable: true,
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
afterEach(() => {
|
|
85
|
+
vi.restoreAllMocks();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("constructor", () => {
|
|
89
|
+
it("should initialize with default options", () => {
|
|
90
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
91
|
+
|
|
92
|
+
expect(subscriptionManager).toBeDefined();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should initialize with custom options", () => {
|
|
96
|
+
const options: SyncOptions = {
|
|
97
|
+
pageSize: 50,
|
|
98
|
+
useCursorPagination: true,
|
|
99
|
+
onBackfill: vi.fn(),
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache, options);
|
|
103
|
+
|
|
104
|
+
expect(subscriptionManager).toBeDefined();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("subscribe", () => {
|
|
109
|
+
beforeEach(() => {
|
|
110
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should create a subscription successfully", async () => {
|
|
114
|
+
const query: SubscriptionQuery = {
|
|
115
|
+
doctype: "TestDoc",
|
|
116
|
+
fields: ["title", "description"],
|
|
117
|
+
filters: { status: "Active" },
|
|
118
|
+
orderBy: { field: "modified", order: Order.Desc },
|
|
119
|
+
limit: 20,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const result = await subscriptionManager.subscribe(query);
|
|
123
|
+
|
|
124
|
+
expect(result.subscriptionId).toBe("uuid-1");
|
|
125
|
+
expect(result.rows).toEqual(mockDocs);
|
|
126
|
+
expect(result.checkpoint).toBe("2024-01-01T11:00:00"); // Max modified
|
|
127
|
+
expect(mockDb.getDocList).toHaveBeenCalledWith("TestDoc", {
|
|
128
|
+
fields: ["title", "description", "modified", "name"],
|
|
129
|
+
filters: { status: "Active" },
|
|
130
|
+
orderBy: { field: "modified", order: Order.Desc },
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("should handle single document queries", async () => {
|
|
135
|
+
(filters.extractSingleName as any).mockReturnValue("specific-doc");
|
|
136
|
+
|
|
137
|
+
const query: SubscriptionQuery = {
|
|
138
|
+
doctype: "TestDoc",
|
|
139
|
+
fields: ["*"],
|
|
140
|
+
filters: { name: "specific-doc" },
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const result = await subscriptionManager.subscribe(query);
|
|
144
|
+
|
|
145
|
+
expect(mockDb.getDoc).toHaveBeenCalledWith("TestDoc", "specific-doc");
|
|
146
|
+
expect(result.rows).toEqual([mockDoc]);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("should handle single document query errors", async () => {
|
|
150
|
+
(filters.extractSingleName as any).mockReturnValue("non-existent-doc");
|
|
151
|
+
mockDb.getDoc.mockRejectedValue(
|
|
152
|
+
Object.assign(new Error("Document not found"), { status: 404 }),
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const query: SubscriptionQuery = {
|
|
156
|
+
doctype: "TestDoc",
|
|
157
|
+
fields: ["*"],
|
|
158
|
+
filters: { name: "non-existent-doc" },
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const result = await subscriptionManager.subscribe(query);
|
|
162
|
+
|
|
163
|
+
expect(result.rows).toEqual([]);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("should handle cursor pagination", async () => {
|
|
167
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache, {
|
|
168
|
+
useCursorPagination: true,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
mockDb.getDocList.mockResolvedValue({
|
|
172
|
+
data: mockDocs,
|
|
173
|
+
cursor: "cursor-123",
|
|
174
|
+
} as any);
|
|
175
|
+
|
|
176
|
+
const query: SubscriptionQuery = {
|
|
177
|
+
doctype: "TestDoc",
|
|
178
|
+
fields: ["*"],
|
|
179
|
+
limit: 20,
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const result = await subscriptionManager.subscribe(query);
|
|
183
|
+
|
|
184
|
+
expect(mockDb.getDocList).toHaveBeenCalledWith("TestDoc", {
|
|
185
|
+
fields: ["*", "modified", "name"],
|
|
186
|
+
cursor: undefined,
|
|
187
|
+
});
|
|
188
|
+
expect(result.rows).toEqual(mockDocs);
|
|
189
|
+
|
|
190
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId);
|
|
191
|
+
expect(subscription?.cursor).toBe("cursor-123");
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("should seed normalized cache with returned documents", async () => {
|
|
195
|
+
const query: SubscriptionQuery = {
|
|
196
|
+
doctype: "TestDoc",
|
|
197
|
+
fields: ["*"],
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
await subscriptionManager.subscribe(query);
|
|
201
|
+
|
|
202
|
+
expect(mockNormalizedCache.upsert).toHaveBeenCalledTimes(3);
|
|
203
|
+
for (const doc of mockDocs) {
|
|
204
|
+
expect(mockNormalizedCache.upsert).toHaveBeenCalledWith(doc);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("should compute checkpoint as max modified time", async () => {
|
|
209
|
+
const query: SubscriptionQuery = {
|
|
210
|
+
doctype: "TestDoc",
|
|
211
|
+
fields: ["*"],
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const result = await subscriptionManager.subscribe(query);
|
|
215
|
+
|
|
216
|
+
expect(result.checkpoint).toBe("2024-01-01T11:00:00");
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("should set page boundaries", async () => {
|
|
220
|
+
const query: SubscriptionQuery = {
|
|
221
|
+
doctype: "TestDoc",
|
|
222
|
+
fields: ["*"],
|
|
223
|
+
limitStart: 10,
|
|
224
|
+
limit: 15,
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const result = await subscriptionManager.subscribe(query);
|
|
228
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId);
|
|
229
|
+
|
|
230
|
+
expect(subscription?.boundaries).toEqual({
|
|
231
|
+
firstItem: mockDocs[0],
|
|
232
|
+
lastItem: mockDocs[2],
|
|
233
|
+
offset: 10,
|
|
234
|
+
pageSize: 15,
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("should initialize metadata", async () => {
|
|
239
|
+
const query: SubscriptionQuery = {
|
|
240
|
+
doctype: "TestDoc",
|
|
241
|
+
fields: ["*"],
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const result = await subscriptionManager.subscribe(query);
|
|
245
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId);
|
|
246
|
+
|
|
247
|
+
expect(subscription?.metadata).toEqual({
|
|
248
|
+
itemsBeforePage: 0,
|
|
249
|
+
itemsAfterPage: 0,
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("should handle empty results", async () => {
|
|
254
|
+
mockDb.getDocList.mockResolvedValue([]);
|
|
255
|
+
|
|
256
|
+
const query: SubscriptionQuery = {
|
|
257
|
+
doctype: "TestDoc",
|
|
258
|
+
fields: ["*"],
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const result = await subscriptionManager.subscribe(query);
|
|
262
|
+
|
|
263
|
+
expect(result.rows).toEqual([]);
|
|
264
|
+
expect(result.checkpoint).toBeUndefined();
|
|
265
|
+
|
|
266
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId);
|
|
267
|
+
expect(subscription?.boundaries).toBeUndefined();
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
describe("unsubscribe", () => {
|
|
272
|
+
beforeEach(() => {
|
|
273
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it("should remove subscription", async () => {
|
|
277
|
+
const query: SubscriptionQuery = {
|
|
278
|
+
doctype: "TestDoc",
|
|
279
|
+
fields: ["*"],
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const result = await subscriptionManager.subscribe(query);
|
|
283
|
+
expect(subscriptionManager.getSubscription(result.subscriptionId)).toBeDefined();
|
|
284
|
+
|
|
285
|
+
subscriptionManager.unsubscribe(result.subscriptionId);
|
|
286
|
+
expect(subscriptionManager.getSubscription(result.subscriptionId)).toBeUndefined();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("should handle non-existent subscription", () => {
|
|
290
|
+
expect(() => {
|
|
291
|
+
subscriptionManager.unsubscribe("non-existent");
|
|
292
|
+
}).not.toThrow();
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe("getDocsForSubscription", () => {
|
|
297
|
+
beforeEach(() => {
|
|
298
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("should return documents from virtual page system when available", async () => {
|
|
302
|
+
const virtualPageManager = (subscriptionManager as any).virtualPageManager;
|
|
303
|
+
vi.spyOn(virtualPageManager, "getSubscription").mockReturnValue({
|
|
304
|
+
query: { doctype: "TestDoc" },
|
|
305
|
+
getProgressiveCache: () => ({ docIds: ["doc1", "doc2"] }),
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
const query: SubscriptionQuery = {
|
|
309
|
+
doctype: "TestDoc",
|
|
310
|
+
fields: ["*"],
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const result = await subscriptionManager.subscribe(query);
|
|
314
|
+
const docs = subscriptionManager.getDocsForSubscription(result.subscriptionId);
|
|
315
|
+
|
|
316
|
+
expect(docs).toHaveLength(2);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it("should resolve documents from the standard subscription map when virtual pages are absent", async () => {
|
|
320
|
+
const query: SubscriptionQuery = {
|
|
321
|
+
doctype: "TestDoc",
|
|
322
|
+
fields: ["*"],
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const result = await subscriptionManager.subscribe(query);
|
|
326
|
+
const docs = subscriptionManager.getDocsForSubscription(result.subscriptionId);
|
|
327
|
+
|
|
328
|
+
expect(docs).toHaveLength(3);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it("should return empty array for non-existent subscription", () => {
|
|
332
|
+
const docs = subscriptionManager.getDocsForSubscription("non-existent");
|
|
333
|
+
expect(docs).toEqual([]);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it("should handle missing documents in cache", async () => {
|
|
337
|
+
mockNormalizedCache.get.mockReturnValue(undefined);
|
|
338
|
+
|
|
339
|
+
const query: SubscriptionQuery = {
|
|
340
|
+
doctype: "TestDoc",
|
|
341
|
+
fields: ["*"],
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const result = await subscriptionManager.subscribe(query);
|
|
345
|
+
const docs = subscriptionManager.getDocsForSubscription(result.subscriptionId);
|
|
346
|
+
|
|
347
|
+
expect(docs).toEqual([]);
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
describe("virtual pagination methods", () => {
|
|
352
|
+
beforeEach(() => {
|
|
353
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it("should delegate getPage to virtual page system", async () => {
|
|
357
|
+
const virtualPageManager = (subscriptionManager as any).virtualPageManager;
|
|
358
|
+
const mockPageData = [mockDoc];
|
|
359
|
+
vi.spyOn(virtualPageManager, "getPage").mockResolvedValue(mockPageData);
|
|
360
|
+
|
|
361
|
+
const result = await subscriptionManager.getPage("sub1", 2);
|
|
362
|
+
|
|
363
|
+
expect(virtualPageManager.getPage).toHaveBeenCalledWith("sub1", 2);
|
|
364
|
+
expect(result).toEqual(mockPageData);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it("should delegate getNextBatch to virtual page system", async () => {
|
|
368
|
+
const virtualPageManager = (subscriptionManager as any).virtualPageManager;
|
|
369
|
+
const mockAfterData = [mockDoc];
|
|
370
|
+
vi.spyOn(virtualPageManager, "getNextBatch").mockResolvedValue(mockAfterData);
|
|
371
|
+
|
|
372
|
+
const result = await subscriptionManager.getNextBatch("sub1", "cursor-doc", 10);
|
|
373
|
+
|
|
374
|
+
expect(virtualPageManager.getNextBatch).toHaveBeenCalledWith("sub1", "cursor-doc", 10);
|
|
375
|
+
expect(result).toEqual(mockAfterData);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("should delegate getPageInfo to virtual page system", () => {
|
|
379
|
+
const virtualPageManager = (subscriptionManager as any).virtualPageManager;
|
|
380
|
+
const mockPageInfo = {
|
|
381
|
+
currentPage: 2,
|
|
382
|
+
pageSize: 20,
|
|
383
|
+
totalPages: 5,
|
|
384
|
+
hasMore: true,
|
|
385
|
+
itemsInCache: 100,
|
|
386
|
+
};
|
|
387
|
+
vi.spyOn(virtualPageManager, "getPageInfo").mockReturnValue(mockPageInfo);
|
|
388
|
+
|
|
389
|
+
const result = subscriptionManager.getPageInfo("sub1");
|
|
390
|
+
|
|
391
|
+
expect(virtualPageManager.getPageInfo).toHaveBeenCalledWith("sub1");
|
|
392
|
+
expect(result).toEqual(mockPageInfo);
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
describe("backfill", () => {
|
|
397
|
+
beforeEach(() => {
|
|
398
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache, {
|
|
399
|
+
pageSize: 100,
|
|
400
|
+
onBackfill: vi.fn(),
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
it("should backfill all subscriptions", async () => {
|
|
405
|
+
const query1: SubscriptionQuery = { doctype: "TestDoc", fields: ["*"] };
|
|
406
|
+
const query2: SubscriptionQuery = { doctype: "OtherDoc", fields: ["*"] };
|
|
407
|
+
|
|
408
|
+
await subscriptionManager.subscribe(query1);
|
|
409
|
+
await subscriptionManager.subscribe(query2);
|
|
410
|
+
|
|
411
|
+
const backfillSpy = vi.spyOn(subscriptionManager as any, "backfillSub");
|
|
412
|
+
|
|
413
|
+
await subscriptionManager.backfill({
|
|
414
|
+
scope: BackfillScope.All,
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
expect(backfillSpy).toHaveBeenCalledTimes(2);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it("should backfill specific subscriptions", async () => {
|
|
421
|
+
const result1 = await subscriptionManager.subscribe({
|
|
422
|
+
doctype: "TestDoc",
|
|
423
|
+
fields: ["*"],
|
|
424
|
+
});
|
|
425
|
+
const _result2 = await subscriptionManager.subscribe({
|
|
426
|
+
doctype: "OtherDoc",
|
|
427
|
+
fields: ["*"],
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
const backfillSpy = vi.spyOn(subscriptionManager as any, "backfillSub");
|
|
431
|
+
|
|
432
|
+
await subscriptionManager.backfill({
|
|
433
|
+
scope: BackfillScope.Subscriptions,
|
|
434
|
+
subscriptions: [result1.subscriptionId],
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
expect(backfillSpy).toHaveBeenCalledTimes(1);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it("should backfill by doctypes", async () => {
|
|
441
|
+
await subscriptionManager.subscribe({
|
|
442
|
+
doctype: "TestDoc",
|
|
443
|
+
fields: ["*"],
|
|
444
|
+
});
|
|
445
|
+
await subscriptionManager.subscribe({
|
|
446
|
+
doctype: "OtherDoc",
|
|
447
|
+
fields: ["*"],
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
const backfillSpy = vi.spyOn(subscriptionManager as any, "backfillSub");
|
|
451
|
+
|
|
452
|
+
await subscriptionManager.backfill({
|
|
453
|
+
scope: BackfillScope.Doctypes,
|
|
454
|
+
doctypes: ["TestDoc"],
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
expect(backfillSpy).toHaveBeenCalledTimes(1);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
it("should backfill specific documents", async () => {
|
|
461
|
+
const docTargets = [
|
|
462
|
+
{ doctype: "TestDoc", name: "doc1" },
|
|
463
|
+
{ doctype: "TestDoc", name: "doc2" },
|
|
464
|
+
];
|
|
465
|
+
|
|
466
|
+
await subscriptionManager.backfill({
|
|
467
|
+
scope: BackfillScope.Docs,
|
|
468
|
+
docs: docTargets,
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
expect(mockDb.getDoc).toHaveBeenCalledWith("TestDoc", "doc1");
|
|
472
|
+
expect(mockDb.getDoc).toHaveBeenCalledWith("TestDoc", "doc2");
|
|
473
|
+
expect(mockNormalizedCache.upsert).toHaveBeenCalledTimes(2);
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
describe("backfillSub", () => {
|
|
478
|
+
beforeEach(() => {
|
|
479
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache, {
|
|
480
|
+
onBackfill: vi.fn(),
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
it("should perform CDC backfill for subscription", async () => {
|
|
485
|
+
const result = await subscriptionManager.subscribe({
|
|
486
|
+
doctype: "TestDoc",
|
|
487
|
+
fields: ["*"],
|
|
488
|
+
filters: { status: "Active" },
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
492
|
+
const backfillResponse = {
|
|
493
|
+
rows: [{ name: "doc4", doctype: "TestDoc", modified: "2024-01-02T10:00:00" }],
|
|
494
|
+
checkpoint: "2024-01-02T10:00:00",
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
mockDb.backfill.mockResolvedValue(backfillResponse);
|
|
498
|
+
|
|
499
|
+
await subscriptionManager.backfillSub(subscription);
|
|
500
|
+
|
|
501
|
+
expect(mockDb.backfill).toHaveBeenCalledWith({
|
|
502
|
+
doctype: "TestDoc",
|
|
503
|
+
fields: ["*"],
|
|
504
|
+
filters: { status: "Active" },
|
|
505
|
+
modifiedAfter: "2024-01-01T11:00:00",
|
|
506
|
+
limit: 200, // Default pageSize
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
expect(subscription.checkpoint).toBe("2024-01-02T10:00:00");
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
it("should handle tombstones (deleted documents)", async () => {
|
|
513
|
+
const result = await subscriptionManager.subscribe({
|
|
514
|
+
doctype: "TestDoc",
|
|
515
|
+
fields: ["*"],
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
519
|
+
const backfillResponse = {
|
|
520
|
+
rows: [],
|
|
521
|
+
deleted: [{ doctype: "TestDoc", name: "doc2" }],
|
|
522
|
+
checkpoint: "2024-01-02T10:00:00",
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
mockDb.backfill.mockResolvedValue(backfillResponse);
|
|
526
|
+
|
|
527
|
+
await subscriptionManager.backfillSub(subscription);
|
|
528
|
+
|
|
529
|
+
expect(mockNormalizedCache.remove).toHaveBeenCalledWith({
|
|
530
|
+
doctype: "TestDoc",
|
|
531
|
+
name: "doc2",
|
|
532
|
+
});
|
|
533
|
+
expect(subscription.docIds).not.toContain("doc2");
|
|
534
|
+
expect(subscription.tombstones?.has("doc2")).toBe(true);
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
it("should reconcile membership with filters", async () => {
|
|
538
|
+
const result = await subscriptionManager.subscribe({
|
|
539
|
+
doctype: "TestDoc",
|
|
540
|
+
fields: ["*"],
|
|
541
|
+
filters: { status: "Active" },
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
545
|
+
const newDoc = {
|
|
546
|
+
name: "doc4",
|
|
547
|
+
doctype: "TestDoc",
|
|
548
|
+
status: "Active",
|
|
549
|
+
modified: "2024-01-02T10:00:00",
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
const backfillResponse = {
|
|
553
|
+
rows: [newDoc],
|
|
554
|
+
checkpoint: "2024-01-02T10:00:00",
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
mockDb.backfill.mockResolvedValue(backfillResponse);
|
|
558
|
+
(filters.matchesFilters as any).mockReturnValue(true);
|
|
559
|
+
|
|
560
|
+
await subscriptionManager.backfillSub(subscription);
|
|
561
|
+
|
|
562
|
+
expect(subscription.docIds).toContain("doc4");
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
it("should remove documents that no longer match filters", async () => {
|
|
566
|
+
const result = await subscriptionManager.subscribe({
|
|
567
|
+
doctype: "TestDoc",
|
|
568
|
+
fields: ["*"],
|
|
569
|
+
filters: { status: "Active" },
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
573
|
+
const updatedDoc = {
|
|
574
|
+
name: "doc1",
|
|
575
|
+
doctype: "TestDoc",
|
|
576
|
+
status: "Inactive",
|
|
577
|
+
modified: "2024-01-02T10:00:00",
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
const backfillResponse = {
|
|
581
|
+
rows: [updatedDoc],
|
|
582
|
+
checkpoint: "2024-01-02T10:00:00",
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
mockDb.backfill.mockResolvedValue(backfillResponse);
|
|
586
|
+
(filters.matchesFilters as any).mockReturnValue(false);
|
|
587
|
+
|
|
588
|
+
await subscriptionManager.backfillSub(subscription);
|
|
589
|
+
|
|
590
|
+
expect(subscription.docIds).not.toContain("doc1");
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
it("should update page boundaries after backfill", async () => {
|
|
594
|
+
const result = await subscriptionManager.subscribe({
|
|
595
|
+
doctype: "TestDoc",
|
|
596
|
+
fields: ["*"],
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
600
|
+
|
|
601
|
+
await subscriptionManager.backfillSub(subscription);
|
|
602
|
+
|
|
603
|
+
expect(subscription.boundaries).toBeDefined();
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
it("should call onBackfill callback", async () => {
|
|
607
|
+
const onBackfill = vi.fn();
|
|
608
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache, { onBackfill });
|
|
609
|
+
|
|
610
|
+
const result = await subscriptionManager.subscribe({
|
|
611
|
+
doctype: "TestDoc",
|
|
612
|
+
fields: ["*"],
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
616
|
+
|
|
617
|
+
await subscriptionManager.backfillSub(subscription);
|
|
618
|
+
|
|
619
|
+
expect(onBackfill).toHaveBeenCalledWith({
|
|
620
|
+
doctype: "TestDoc",
|
|
621
|
+
fetched: 0,
|
|
622
|
+
checkpoint: "2024-01-01T12:00:00",
|
|
623
|
+
});
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
it("should handle queries without filters", async () => {
|
|
627
|
+
const result = await subscriptionManager.subscribe({
|
|
628
|
+
doctype: "TestDoc",
|
|
629
|
+
fields: ["*"],
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
633
|
+
const backfillResponse = {
|
|
634
|
+
rows: [
|
|
635
|
+
{ name: "doc4", doctype: "TestDoc" },
|
|
636
|
+
{ name: "doc5", doctype: "TestDoc" },
|
|
637
|
+
],
|
|
638
|
+
checkpoint: "2024-01-02T10:00:00",
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
mockDb.backfill.mockResolvedValue(backfillResponse);
|
|
642
|
+
|
|
643
|
+
await subscriptionManager.backfillSub(subscription);
|
|
644
|
+
|
|
645
|
+
expect(subscription.docIds).toEqual(["doc4", "doc5"]);
|
|
646
|
+
});
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
describe("resortSubscriptionDocIds", () => {
|
|
650
|
+
beforeEach(() => {
|
|
651
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
it("should sort by orderBy field ascending", async () => {
|
|
655
|
+
const result = await subscriptionManager.subscribe({
|
|
656
|
+
doctype: "TestDoc",
|
|
657
|
+
fields: ["*"],
|
|
658
|
+
orderBy: { field: "modified", order: Order.Asc },
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
662
|
+
subscriptionManager.resortSubscriptionDocIds(subscription);
|
|
663
|
+
|
|
664
|
+
expect(subscription.docIds).toEqual(["doc1", "doc2", "doc3"]);
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
it("should sort by orderBy field descending", async () => {
|
|
668
|
+
const result = await subscriptionManager.subscribe({
|
|
669
|
+
doctype: "TestDoc",
|
|
670
|
+
fields: ["*"],
|
|
671
|
+
orderBy: { field: "modified", order: Order.Desc },
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
675
|
+
subscriptionManager.resortSubscriptionDocIds(subscription);
|
|
676
|
+
|
|
677
|
+
expect(subscription.docIds).toEqual(["doc3", "doc2", "doc1"]);
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
it("should handle documents with null values", async () => {
|
|
681
|
+
const docWithNull = { name: "doc4", doctype: "TestDoc", modified: null };
|
|
682
|
+
mockNormalizedCache.get.mockImplementation(({ name }: { name: string }) => {
|
|
683
|
+
if (name === "doc4") return docWithNull;
|
|
684
|
+
return mockDocs.find((doc) => doc.name === name);
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
const result = await subscriptionManager.subscribe({
|
|
688
|
+
doctype: "TestDoc",
|
|
689
|
+
fields: ["*"],
|
|
690
|
+
orderBy: { field: "modified", order: Order.Asc },
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
694
|
+
subscription.docIds = ["doc1", "doc4", "doc2"];
|
|
695
|
+
|
|
696
|
+
subscriptionManager.resortSubscriptionDocIds(subscription);
|
|
697
|
+
|
|
698
|
+
expect(subscription.docIds[0]).toBe("doc4"); // Null should come first for asc
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
it("should use name as tiebreaker", async () => {
|
|
702
|
+
const docsWithSameModified = [
|
|
703
|
+
{ name: "doc-b", doctype: "TestDoc", modified: "2024-01-01T10:00:00" },
|
|
704
|
+
{ name: "doc-a", doctype: "TestDoc", modified: "2024-01-01T10:00:00" },
|
|
705
|
+
{ name: "doc-c", doctype: "TestDoc", modified: "2024-01-01T10:00:00" },
|
|
706
|
+
];
|
|
707
|
+
|
|
708
|
+
mockNormalizedCache.get.mockImplementation(({ name }: { name: string }) => {
|
|
709
|
+
return docsWithSameModified.find((doc) => doc.name === name);
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
const result = await subscriptionManager.subscribe({
|
|
713
|
+
doctype: "TestDoc",
|
|
714
|
+
fields: ["*"],
|
|
715
|
+
orderBy: { field: "modified", order: Order.Asc },
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
719
|
+
subscription.docIds = ["doc-b", "doc-a", "doc-c"];
|
|
720
|
+
|
|
721
|
+
subscriptionManager.resortSubscriptionDocIds(subscription);
|
|
722
|
+
|
|
723
|
+
expect(subscription.docIds).toEqual(["doc-a", "doc-b", "doc-c"]);
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
it("should skip sorting when no orderBy", async () => {
|
|
727
|
+
const result = await subscriptionManager.subscribe({
|
|
728
|
+
doctype: "TestDoc",
|
|
729
|
+
fields: ["*"],
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
733
|
+
const originalOrder = [...subscription.docIds];
|
|
734
|
+
|
|
735
|
+
subscriptionManager.resortSubscriptionDocIds(subscription);
|
|
736
|
+
|
|
737
|
+
expect(subscription.docIds).toEqual(originalOrder);
|
|
738
|
+
});
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
describe("updateSubscriptionMembership", () => {
|
|
742
|
+
beforeEach(() => {
|
|
743
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
it("should return subscriptions needing rehydration for new documents", async () => {
|
|
747
|
+
const result = await subscriptionManager.subscribe({
|
|
748
|
+
doctype: "TestDoc",
|
|
749
|
+
fields: ["*"],
|
|
750
|
+
filters: { status: "Active" },
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
const newDoc = {
|
|
754
|
+
name: "new-doc",
|
|
755
|
+
doctype: "TestDoc",
|
|
756
|
+
status: "Active",
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
(filters.matchesFilters as any).mockReturnValue(true);
|
|
760
|
+
|
|
761
|
+
const needsRehydration = subscriptionManager.updateSubscriptionMembership(newDoc);
|
|
762
|
+
|
|
763
|
+
expect(needsRehydration).toHaveLength(1);
|
|
764
|
+
expect(needsRehydration[0]).toBe(subscriptionManager.getSubscription(result.subscriptionId));
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
it("should remove documents that no longer match filters", async () => {
|
|
768
|
+
const result = await subscriptionManager.subscribe({
|
|
769
|
+
doctype: "TestDoc",
|
|
770
|
+
fields: ["*"],
|
|
771
|
+
filters: { status: "Active" },
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
775
|
+
|
|
776
|
+
const updatedDoc = {
|
|
777
|
+
name: "doc1",
|
|
778
|
+
doctype: "TestDoc",
|
|
779
|
+
status: "Inactive",
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
(filters.matchesFilters as any).mockReturnValue(false);
|
|
783
|
+
|
|
784
|
+
subscriptionManager.updateSubscriptionMembership(updatedDoc);
|
|
785
|
+
|
|
786
|
+
expect(subscription.docIds).not.toContain("doc1");
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
it("should resort existing documents", async () => {
|
|
790
|
+
const result = await subscriptionManager.subscribe({
|
|
791
|
+
doctype: "TestDoc",
|
|
792
|
+
fields: ["*"],
|
|
793
|
+
orderBy: { field: "modified", order: Order.Desc },
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
797
|
+
const resortSpy = vi.spyOn(subscriptionManager, "resortSubscriptionDocIds");
|
|
798
|
+
|
|
799
|
+
const existingDoc = {
|
|
800
|
+
name: "doc2",
|
|
801
|
+
doctype: "TestDoc",
|
|
802
|
+
modified: "2024-01-02T10:00:00", // Updated time
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
(filters.matchesFilters as any).mockReturnValue(true);
|
|
806
|
+
|
|
807
|
+
subscriptionManager.updateSubscriptionMembership(existingDoc);
|
|
808
|
+
|
|
809
|
+
expect(resortSpy).toHaveBeenCalledWith(subscription);
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
it("should skip subscriptions with different doctypes", async () => {
|
|
813
|
+
await subscriptionManager.subscribe({
|
|
814
|
+
doctype: "TestDoc",
|
|
815
|
+
fields: ["*"],
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
const needsRehydration = subscriptionManager.updateSubscriptionMembership({
|
|
819
|
+
name: "other-doc",
|
|
820
|
+
doctype: "OtherDoc",
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
expect(needsRehydration).toEqual([]);
|
|
824
|
+
});
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
describe("removeFromAllSubscriptions", () => {
|
|
828
|
+
beforeEach(() => {
|
|
829
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
it("should remove document from all matching subscriptions", async () => {
|
|
833
|
+
const result1 = await subscriptionManager.subscribe({
|
|
834
|
+
doctype: "TestDoc",
|
|
835
|
+
fields: ["*"],
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
const result2 = await subscriptionManager.subscribe({
|
|
839
|
+
doctype: "TestDoc",
|
|
840
|
+
fields: ["title"],
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
const affectedSubs = subscriptionManager.removeFromAllSubscriptions("TestDoc", "doc2");
|
|
844
|
+
|
|
845
|
+
expect(affectedSubs).toHaveLength(2);
|
|
846
|
+
|
|
847
|
+
const sub1 = subscriptionManager.getSubscription(result1.subscriptionId)!;
|
|
848
|
+
const sub2 = subscriptionManager.getSubscription(result2.subscriptionId)!;
|
|
849
|
+
|
|
850
|
+
expect(sub1.docIds).not.toContain("doc2");
|
|
851
|
+
expect(sub2.docIds).not.toContain("doc2");
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
it("should return empty array when document not in any subscription", async () => {
|
|
855
|
+
await subscriptionManager.subscribe({
|
|
856
|
+
doctype: "TestDoc",
|
|
857
|
+
fields: ["*"],
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
const affectedSubs = subscriptionManager.removeFromAllSubscriptions(
|
|
861
|
+
"TestDoc",
|
|
862
|
+
"non-existent",
|
|
863
|
+
);
|
|
864
|
+
|
|
865
|
+
expect(affectedSubs).toEqual([]);
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
it("should skip subscriptions with different doctypes", async () => {
|
|
869
|
+
await subscriptionManager.subscribe({
|
|
870
|
+
doctype: "OtherDoc",
|
|
871
|
+
fields: ["*"],
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
const affectedSubs = subscriptionManager.removeFromAllSubscriptions("TestDoc", "doc1");
|
|
875
|
+
|
|
876
|
+
expect(affectedSubs).toEqual([]);
|
|
877
|
+
});
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
describe("utility methods", () => {
|
|
881
|
+
beforeEach(() => {
|
|
882
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
it("should get all subscriptions", async () => {
|
|
886
|
+
await subscriptionManager.subscribe({
|
|
887
|
+
doctype: "TestDoc",
|
|
888
|
+
fields: ["*"],
|
|
889
|
+
});
|
|
890
|
+
await subscriptionManager.subscribe({
|
|
891
|
+
doctype: "OtherDoc",
|
|
892
|
+
fields: ["*"],
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
const allSubs = subscriptionManager.getAllSubscriptions();
|
|
896
|
+
|
|
897
|
+
expect(allSubs.size).toBe(2);
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
it("should clear all subscriptions", async () => {
|
|
901
|
+
await subscriptionManager.subscribe({
|
|
902
|
+
doctype: "TestDoc",
|
|
903
|
+
fields: ["*"],
|
|
904
|
+
});
|
|
905
|
+
await subscriptionManager.subscribe({
|
|
906
|
+
doctype: "OtherDoc",
|
|
907
|
+
fields: ["*"],
|
|
908
|
+
});
|
|
909
|
+
|
|
910
|
+
subscriptionManager.clear();
|
|
911
|
+
|
|
912
|
+
expect(subscriptionManager.getAllSubscriptions().size).toBe(0);
|
|
913
|
+
});
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
describe("crypto ID generation", () => {
|
|
917
|
+
it("should use crypto.randomUUID when available", async () => {
|
|
918
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
919
|
+
|
|
920
|
+
const result = await subscriptionManager.subscribe({
|
|
921
|
+
doctype: "TestDoc",
|
|
922
|
+
fields: ["*"],
|
|
923
|
+
});
|
|
924
|
+
|
|
925
|
+
expect(result.subscriptionId).toBe("uuid-1");
|
|
926
|
+
expect(crypto.randomUUID).toHaveBeenCalled();
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
it("should fallback to Math.random when crypto not available", async () => {
|
|
930
|
+
(global as any).crypto = undefined;
|
|
931
|
+
vi.spyOn(Math, "random").mockReturnValue(0.123456789);
|
|
932
|
+
|
|
933
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
934
|
+
|
|
935
|
+
const result = await subscriptionManager.subscribe({
|
|
936
|
+
doctype: "TestDoc",
|
|
937
|
+
fields: ["*"],
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
expect(result.subscriptionId).toBe("4fzzzxjylrx");
|
|
941
|
+
expect(Math.random).toHaveBeenCalled();
|
|
942
|
+
});
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
describe("edge cases and error handling", () => {
|
|
946
|
+
beforeEach(() => {
|
|
947
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
it("should handle backfill response without checkpoint", async () => {
|
|
951
|
+
const result = await subscriptionManager.subscribe({
|
|
952
|
+
doctype: "TestDoc",
|
|
953
|
+
fields: ["*"],
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
957
|
+
const originalCheckpoint = subscription.checkpoint;
|
|
958
|
+
|
|
959
|
+
mockDb.backfill.mockResolvedValue({
|
|
960
|
+
rows: [],
|
|
961
|
+
// No checkpoint field
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
await subscriptionManager.backfillSub(subscription);
|
|
965
|
+
|
|
966
|
+
expect(subscription.checkpoint).toBe(originalCheckpoint);
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
it("should handle documents without modified field", async () => {
|
|
970
|
+
const docsWithoutModified = [
|
|
971
|
+
{ name: "doc1", doctype: "TestDoc", title: "Doc 1" },
|
|
972
|
+
{ name: "doc2", doctype: "TestDoc", title: "Doc 2" },
|
|
973
|
+
];
|
|
974
|
+
|
|
975
|
+
mockDb.getDocList.mockResolvedValue(docsWithoutModified);
|
|
976
|
+
|
|
977
|
+
const result = await subscriptionManager.subscribe({
|
|
978
|
+
doctype: "TestDoc",
|
|
979
|
+
fields: ["*"],
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
expect(result.checkpoint).toBeUndefined();
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
it("should handle missing documents during membership update", () => {
|
|
986
|
+
mockNormalizedCache.get.mockReturnValue(undefined);
|
|
987
|
+
|
|
988
|
+
const result = subscriptionManager.updateSubscriptionMembership({
|
|
989
|
+
name: "missing-doc",
|
|
990
|
+
doctype: "TestDoc",
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
expect(result).toEqual([]);
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
it("should handle tombstones with invalid data", async () => {
|
|
997
|
+
const result = await subscriptionManager.subscribe({
|
|
998
|
+
doctype: "TestDoc",
|
|
999
|
+
fields: ["*"],
|
|
1000
|
+
});
|
|
1001
|
+
|
|
1002
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
1003
|
+
const backfillResponse = {
|
|
1004
|
+
rows: [],
|
|
1005
|
+
deleted: [
|
|
1006
|
+
null, // Invalid tombstone
|
|
1007
|
+
{ doctype: "TestDoc" }, // Missing name
|
|
1008
|
+
{ name: "doc2" }, // Missing doctype
|
|
1009
|
+
{ doctype: "TestDoc", name: "doc2" }, // Valid
|
|
1010
|
+
],
|
|
1011
|
+
checkpoint: "2024-01-02T10:00:00",
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
mockDb.backfill.mockResolvedValue(backfillResponse);
|
|
1015
|
+
|
|
1016
|
+
await subscriptionManager.backfillSub(subscription);
|
|
1017
|
+
|
|
1018
|
+
expect(subscription.tombstones?.has("doc2")).toBe(true);
|
|
1019
|
+
expect(subscription.tombstones?.size).toBe(1);
|
|
1020
|
+
});
|
|
1021
|
+
|
|
1022
|
+
it("should handle backfill rows without names", async () => {
|
|
1023
|
+
const result = await subscriptionManager.subscribe({
|
|
1024
|
+
doctype: "TestDoc",
|
|
1025
|
+
fields: ["*"],
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
const subscription = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
1029
|
+
const backfillResponse = {
|
|
1030
|
+
rows: [
|
|
1031
|
+
{ doctype: "TestDoc", title: "No name" }, // Missing name
|
|
1032
|
+
{ name: "doc4", doctype: "TestDoc" }, // Valid
|
|
1033
|
+
],
|
|
1034
|
+
checkpoint: "2024-01-02T10:00:00",
|
|
1035
|
+
};
|
|
1036
|
+
|
|
1037
|
+
mockDb.backfill.mockResolvedValue(backfillResponse);
|
|
1038
|
+
|
|
1039
|
+
await subscriptionManager.backfillSub(subscription);
|
|
1040
|
+
|
|
1041
|
+
expect(subscription.docIds).toContain("doc4");
|
|
1042
|
+
});
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
describe("subscription deduplication", () => {
|
|
1046
|
+
beforeEach(() => {
|
|
1047
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
1048
|
+
});
|
|
1049
|
+
|
|
1050
|
+
it("should return the same subscriptionId for identical queries", async () => {
|
|
1051
|
+
const query: SubscriptionQuery = {
|
|
1052
|
+
doctype: "TestDoc",
|
|
1053
|
+
fields: ["title"],
|
|
1054
|
+
filters: { status: "Active" },
|
|
1055
|
+
};
|
|
1056
|
+
|
|
1057
|
+
const first = await subscriptionManager.subscribe(query);
|
|
1058
|
+
const second = await subscriptionManager.subscribe(query);
|
|
1059
|
+
|
|
1060
|
+
expect(second.subscriptionId).toBe(first.subscriptionId);
|
|
1061
|
+
expect(mockDb.getDocList).toHaveBeenCalledTimes(1);
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
it("should create separate subscriptions for different queries", async () => {
|
|
1065
|
+
const query1: SubscriptionQuery = { doctype: "TestDoc", filters: { status: "Active" } };
|
|
1066
|
+
const query2: SubscriptionQuery = { doctype: "TestDoc", filters: { status: "Draft" } };
|
|
1067
|
+
|
|
1068
|
+
const first = await subscriptionManager.subscribe(query1);
|
|
1069
|
+
const second = await subscriptionManager.subscribe(query2);
|
|
1070
|
+
|
|
1071
|
+
expect(second.subscriptionId).not.toBe(first.subscriptionId);
|
|
1072
|
+
expect(mockDb.getDocList).toHaveBeenCalledTimes(2);
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
it("should return cached docs on dedup hit", async () => {
|
|
1076
|
+
const query: SubscriptionQuery = { doctype: "TestDoc" };
|
|
1077
|
+
|
|
1078
|
+
const first = await subscriptionManager.subscribe(query);
|
|
1079
|
+
const second = await subscriptionManager.subscribe(query);
|
|
1080
|
+
|
|
1081
|
+
expect(second.rows).toBeDefined();
|
|
1082
|
+
expect(second.checkpoint).toBe(first.checkpoint);
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
it("should keep subscription alive when one consumer unsubscribes but another remains", async () => {
|
|
1086
|
+
const query: SubscriptionQuery = { doctype: "TestDoc" };
|
|
1087
|
+
|
|
1088
|
+
const first = await subscriptionManager.subscribe(query);
|
|
1089
|
+
await subscriptionManager.subscribe(query);
|
|
1090
|
+
|
|
1091
|
+
subscriptionManager.unsubscribe(first.subscriptionId);
|
|
1092
|
+
|
|
1093
|
+
const sub = subscriptionManager.getSubscription(first.subscriptionId);
|
|
1094
|
+
expect(sub).toBeDefined();
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
it("should remove subscription when last consumer unsubscribes", async () => {
|
|
1098
|
+
const query: SubscriptionQuery = { doctype: "TestDoc" };
|
|
1099
|
+
|
|
1100
|
+
const result = await subscriptionManager.subscribe(query);
|
|
1101
|
+
await subscriptionManager.subscribe(query);
|
|
1102
|
+
|
|
1103
|
+
subscriptionManager.unsubscribe(result.subscriptionId);
|
|
1104
|
+
subscriptionManager.unsubscribe(result.subscriptionId);
|
|
1105
|
+
|
|
1106
|
+
const sub = subscriptionManager.getSubscription(result.subscriptionId);
|
|
1107
|
+
expect(sub).toBeUndefined();
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
it("should allow re-subscribing after all consumers unsubscribe", async () => {
|
|
1111
|
+
const query: SubscriptionQuery = { doctype: "TestDoc" };
|
|
1112
|
+
|
|
1113
|
+
const first = await subscriptionManager.subscribe(query);
|
|
1114
|
+
subscriptionManager.unsubscribe(first.subscriptionId);
|
|
1115
|
+
|
|
1116
|
+
const second = await subscriptionManager.subscribe(query);
|
|
1117
|
+
expect(second.subscriptionId).not.toBe(first.subscriptionId);
|
|
1118
|
+
expect(mockDb.getDocList).toHaveBeenCalledTimes(2);
|
|
1119
|
+
});
|
|
1120
|
+
|
|
1121
|
+
it("should clear dedup maps on clear()", async () => {
|
|
1122
|
+
const query: SubscriptionQuery = { doctype: "TestDoc" };
|
|
1123
|
+
await subscriptionManager.subscribe(query);
|
|
1124
|
+
|
|
1125
|
+
subscriptionManager.clear();
|
|
1126
|
+
|
|
1127
|
+
const result = await subscriptionManager.subscribe(query);
|
|
1128
|
+
expect(mockDb.getDocList).toHaveBeenCalledTimes(2);
|
|
1129
|
+
expect(result.subscriptionId).toBeDefined();
|
|
1130
|
+
});
|
|
1131
|
+
});
|
|
1132
|
+
|
|
1133
|
+
describe("progressive VPM registration", () => {
|
|
1134
|
+
beforeEach(() => {
|
|
1135
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache);
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
it("should register with VPM when progressive is true", async () => {
|
|
1139
|
+
const query: SubscriptionQuery = {
|
|
1140
|
+
doctype: "TestDoc",
|
|
1141
|
+
progressive: true,
|
|
1142
|
+
limit: 20,
|
|
1143
|
+
};
|
|
1144
|
+
|
|
1145
|
+
const result = await subscriptionManager.subscribe(query);
|
|
1146
|
+
const vpm = subscriptionManager.getVirtualPageManager();
|
|
1147
|
+
const virtualSub = vpm.getSubscription(result.subscriptionId);
|
|
1148
|
+
|
|
1149
|
+
expect(virtualSub).toBeDefined();
|
|
1150
|
+
expect(virtualSub!.getProgressiveCache().docIds).toHaveLength(mockDocs.length);
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
it("should not register with VPM when progressive is false/undefined", async () => {
|
|
1154
|
+
const query: SubscriptionQuery = { doctype: "TestDoc" };
|
|
1155
|
+
|
|
1156
|
+
const result = await subscriptionManager.subscribe(query);
|
|
1157
|
+
const vpm = subscriptionManager.getVirtualPageManager();
|
|
1158
|
+
const virtualSub = vpm.getSubscription(result.subscriptionId);
|
|
1159
|
+
|
|
1160
|
+
expect(virtualSub).toBeUndefined();
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
it("should prefer VPM docs when subscription is progressive", async () => {
|
|
1164
|
+
const query: SubscriptionQuery = {
|
|
1165
|
+
doctype: "TestDoc",
|
|
1166
|
+
progressive: true,
|
|
1167
|
+
limit: 20,
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1170
|
+
const result = await subscriptionManager.subscribe(query);
|
|
1171
|
+
const docs = subscriptionManager.getDocsForSubscription(result.subscriptionId);
|
|
1172
|
+
|
|
1173
|
+
expect(docs.length).toBeGreaterThan(0);
|
|
1174
|
+
});
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
describe("tombstone cleanup", () => {
|
|
1178
|
+
beforeEach(() => {
|
|
1179
|
+
subscriptionManager = new SubscriptionManager(mockDb, mockNormalizedCache, {
|
|
1180
|
+
tombstoneMaxAge: 1000,
|
|
1181
|
+
tombstoneMaxCount: 3,
|
|
1182
|
+
});
|
|
1183
|
+
});
|
|
1184
|
+
|
|
1185
|
+
it("should remove tombstones older than maxAge", async () => {
|
|
1186
|
+
const query: SubscriptionQuery = { doctype: "TestDoc" };
|
|
1187
|
+
const result = await subscriptionManager.subscribe(query);
|
|
1188
|
+
const sub = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
1189
|
+
|
|
1190
|
+
sub.tombstones!.set("old-doc", Date.now() - 2000);
|
|
1191
|
+
sub.tombstones!.set("recent-doc", Date.now());
|
|
1192
|
+
|
|
1193
|
+
subscriptionManager.cleanupTombstones(result.subscriptionId);
|
|
1194
|
+
|
|
1195
|
+
expect(sub.tombstones!.has("old-doc")).toBe(false);
|
|
1196
|
+
expect(sub.tombstones!.has("recent-doc")).toBe(true);
|
|
1197
|
+
});
|
|
1198
|
+
|
|
1199
|
+
it("should trim tombstones exceeding maxCount (oldest first)", async () => {
|
|
1200
|
+
const now = Date.now();
|
|
1201
|
+
const query: SubscriptionQuery = { doctype: "TestDoc" };
|
|
1202
|
+
const result = await subscriptionManager.subscribe(query);
|
|
1203
|
+
const sub = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
1204
|
+
|
|
1205
|
+
sub.tombstones!.set("doc-1", now - 100);
|
|
1206
|
+
sub.tombstones!.set("doc-2", now - 50);
|
|
1207
|
+
sub.tombstones!.set("doc-3", now - 25);
|
|
1208
|
+
sub.tombstones!.set("doc-4", now);
|
|
1209
|
+
|
|
1210
|
+
subscriptionManager.cleanupTombstones(result.subscriptionId);
|
|
1211
|
+
|
|
1212
|
+
expect(sub.tombstones!.size).toBe(3);
|
|
1213
|
+
expect(sub.tombstones!.has("doc-1")).toBe(false);
|
|
1214
|
+
expect(sub.tombstones!.has("doc-4")).toBe(true);
|
|
1215
|
+
});
|
|
1216
|
+
|
|
1217
|
+
it("should handle subscriptions without tombstones", async () => {
|
|
1218
|
+
const query: SubscriptionQuery = { doctype: "TestDoc" };
|
|
1219
|
+
const result = await subscriptionManager.subscribe(query);
|
|
1220
|
+
const sub = subscriptionManager.getSubscription(result.subscriptionId)!;
|
|
1221
|
+
sub.tombstones = undefined;
|
|
1222
|
+
|
|
1223
|
+
expect(() => subscriptionManager.cleanupTombstones(result.subscriptionId)).not.toThrow();
|
|
1224
|
+
});
|
|
1225
|
+
});
|
|
1226
|
+
});
|