Full Code of dexie/Dexie.js for AI

master fdd54dd81a5b cached
792 files
2.3 MB
634.1k tokens
1558 symbols
1 requests
Download .txt
Showing preview only (2,518K chars total). Download the full file or copy to clipboard to get everything.
Repository: dexie/Dexie.js
Branch: master
Commit: fdd54dd81a5b
Files: 792
Total size: 2.3 MB

Directory structure:
gitextract_2syan8s_/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── dexie-cloud-common.yml
│       └── main.yml
├── .gitignore
├── .npmignore
├── .npmrc
├── .prettierrc
├── .prettierrc.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── NOTICE
├── README.md
├── SECURITY.md
├── addons/
│   ├── Dexie.Observable/
│   │   ├── .gitignore
│   │   ├── .npmignore
│   │   ├── README.md
│   │   ├── api.d.ts
│   │   ├── api.js
│   │   ├── dist/
│   │   │   └── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── .eslintrc.json
│   │   │   ├── Dexie.Observable.d.ts
│   │   │   ├── Dexie.Observable.js
│   │   │   ├── change_types.js
│   │   │   ├── delete-old-changes.js
│   │   │   ├── hooks/
│   │   │   │   ├── creating.js
│   │   │   │   ├── crud-monitor.js
│   │   │   │   ├── deleting.js
│   │   │   │   └── updating.js
│   │   │   ├── intercomm.js
│   │   │   ├── on-storage.js
│   │   │   ├── override-create-transaction.js
│   │   │   ├── override-open.js
│   │   │   ├── override-parse-stores-spec.js
│   │   │   ├── utils.js
│   │   │   └── wakeup-observers.js
│   │   ├── test/
│   │   │   ├── gh-actions.sh
│   │   │   ├── integration/
│   │   │   │   ├── karma-env.js
│   │   │   │   ├── karma.conf.js
│   │   │   │   └── test-observable-dexie-tests.html
│   │   │   ├── typings/
│   │   │   │   ├── test-typings.ts
│   │   │   │   └── tsconfig.json
│   │   │   └── unit/
│   │   │       ├── .eslintrc.json
│   │   │       ├── .gitignore
│   │   │       ├── deep-equal.js
│   │   │       ├── hooks/
│   │   │       │   ├── tests-creating.js
│   │   │       │   ├── tests-deleting.js
│   │   │       │   └── tests-updating.js
│   │   │       ├── karma.conf.js
│   │   │       ├── run-unit-tests.html
│   │   │       ├── tests-observable-misc.js
│   │   │       ├── tests-override-open.js
│   │   │       ├── tests-override-parse-stores-spec.js
│   │   │       └── unit-tests-all.js
│   │   └── tools/
│   │       ├── build-configs/
│   │       │   ├── banner.txt
│   │       │   ├── rollup.config.mjs
│   │       │   ├── rollup.tests.config.js
│   │       │   ├── rollup.tests.config.mjs
│   │       │   ├── rollup.tests.unit.config.js
│   │       │   └── rollup.tests.unit.config.mjs
│   │       └── replaceVersionAndDate.js
│   ├── Dexie.Syncable/
│   │   ├── .gitignore
│   │   ├── .npmignore
│   │   ├── README.md
│   │   ├── api.d.ts
│   │   ├── api.js
│   │   ├── dist/
│   │   │   └── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── .eslintrc.json
│   │   │   ├── Dexie.Syncable.d.ts
│   │   │   ├── Dexie.Syncable.js
│   │   │   ├── PersistedContext.js
│   │   │   ├── apply-changes.js
│   │   │   ├── bulk-update.js
│   │   │   ├── change_types.js
│   │   │   ├── combine-create-and-update.js
│   │   │   ├── combine-update-and-update.js
│   │   │   ├── connect-fn.js
│   │   │   ├── connect-protocol.js
│   │   │   ├── enqueue.js
│   │   │   ├── finally-commit-all-changes.js
│   │   │   ├── get-local-changes-for-node/
│   │   │   │   ├── get-base-revision-and-max-client-revision.js
│   │   │   │   ├── get-changes-since-revision.js
│   │   │   │   ├── get-local-changes-for-node.js
│   │   │   │   └── get-table-objects-as-changes.js
│   │   │   ├── get-or-create-sync-node.js
│   │   │   ├── merge-change.js
│   │   │   ├── save-to-uncommitted-changes.js
│   │   │   ├── statuses.js
│   │   │   └── syncable-connect.js
│   │   ├── test/
│   │   │   ├── gh-actions.sh
│   │   │   ├── integration/
│   │   │   │   ├── dummy-sync-protocol.js
│   │   │   │   ├── karma-env.js
│   │   │   │   ├── karma.conf.js
│   │   │   │   └── test-syncable-dexie-tests.html
│   │   │   ├── test-typings/
│   │   │   │   ├── test-typings.ts
│   │   │   │   └── tsconfig.json
│   │   │   └── unit/
│   │   │       ├── .eslintrc.json
│   │   │       ├── .gitignore
│   │   │       ├── get-local-changes-for-node/
│   │   │       │   ├── tests-get-base-revision-and-max-client-revision.js
│   │   │       │   ├── tests-get-changes-since-revision.js
│   │   │       │   └── tests-get-local-changes-for-node.js
│   │   │       ├── karma-env.js
│   │   │       ├── karma.conf.js
│   │   │       ├── run-unit-tests.html
│   │   │       ├── tests-PersistedContext.js
│   │   │       ├── tests-WebSocketSyncServer.js
│   │   │       ├── tests-apply-changes.js
│   │   │       ├── tests-bulk-update.js
│   │   │       ├── tests-changing-options.js
│   │   │       ├── tests-combine-create-and-update.js
│   │   │       ├── tests-combine-update-and-update.js
│   │   │       ├── tests-finally-commit-all-changes.js
│   │   │       ├── tests-get-or-create-sync-node.js
│   │   │       ├── tests-merge-change.js
│   │   │       ├── tests-register-sync-protocol.js
│   │   │       ├── tests-save-to-uncommitted-changes.js
│   │   │       ├── tests-syncable-partials.js
│   │   │       ├── tests-syncable.js
│   │   │       ├── tests-syncprovider.js
│   │   │       └── unit-tests-all.js
│   │   └── tools/
│   │       ├── build-configs/
│   │       │   ├── banner.txt
│   │       │   ├── rollup.config.mjs
│   │       │   ├── rollup.tests.config.js
│   │       │   └── rollup.tests.config.mjs
│   │       └── replaceVersionAndDate.js
│   ├── dexie-cloud/
│   │   ├── .gitignore
│   │   ├── .npmignore
│   │   ├── .vscode/
│   │   │   └── settings.json
│   │   ├── README.md
│   │   ├── TODO-SOCIALAUTH.md
│   │   ├── dexie-cloud-import.json
│   │   ├── oauth_flow.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── DISABLE_SERVICEWORKER_STRATEGY.ts
│   │   │   ├── DXCWebSocketStatus.ts
│   │   │   ├── DexieCloudAPI.ts
│   │   │   ├── DexieCloudOptions.ts
│   │   │   ├── DexieCloudSyncOptions.ts
│   │   │   ├── DexieCloudTable.ts
│   │   │   ├── InvalidLicenseError.ts
│   │   │   ├── Invite.ts
│   │   │   ├── PermissionChecker.ts
│   │   │   ├── TSON.ts
│   │   │   ├── WSObservable.ts
│   │   │   ├── associate.ts
│   │   │   ├── authentication/
│   │   │   │   ├── AuthPersistedContext.ts
│   │   │   │   ├── TokenErrorResponseError.ts
│   │   │   │   ├── TokenExpiredError.ts
│   │   │   │   ├── UNAUTHORIZED_USER.ts
│   │   │   │   ├── authenticate.ts
│   │   │   │   ├── currentUserObservable.ts
│   │   │   │   ├── exchangeOAuthCode.ts
│   │   │   │   ├── fetchAuthProviders.ts
│   │   │   │   ├── handleOAuthCallback.ts
│   │   │   │   ├── interactWithUser.ts
│   │   │   │   ├── login.ts
│   │   │   │   ├── logout.ts
│   │   │   │   ├── oauthLogin.ts
│   │   │   │   ├── otpFetchTokenCallback.ts
│   │   │   │   ├── setCurrentUser.ts
│   │   │   │   └── waitUntil.ts
│   │   │   ├── computeSyncState.ts
│   │   │   ├── createSharedValueObservable.ts
│   │   │   ├── currentUserEmitter.ts
│   │   │   ├── db/
│   │   │   │   ├── DexieCloudDB.ts
│   │   │   │   └── entities/
│   │   │   │       ├── BaseRevisionMapEntry.ts
│   │   │   │       ├── EntityCommon.ts
│   │   │   │       ├── GuardedJob.ts
│   │   │   │       ├── Member.ts
│   │   │   │       ├── PersistedSyncState.ts
│   │   │   │       ├── Realm.ts
│   │   │   │       ├── Role.ts
│   │   │   │       └── UserLogin.ts
│   │   │   ├── default-ui/
│   │   │   │   ├── Dialog.tsx
│   │   │   │   ├── LoginDialog.tsx
│   │   │   │   ├── OptionButton.tsx
│   │   │   │   ├── Styles.ts
│   │   │   │   └── index.tsx
│   │   │   ├── define-ydoc-trigger.ts
│   │   │   ├── dexie-cloud-addon.ts
│   │   │   ├── dexie-cloud-client.ts
│   │   │   ├── errors/
│   │   │   │   ├── HttpError.ts
│   │   │   │   ├── OAuthError.ts
│   │   │   │   └── OAuthRedirectError.ts
│   │   │   ├── extend-dexie-interface.ts
│   │   │   ├── getGlobalRolesObservable.ts
│   │   │   ├── getInternalAccessControlObservable.ts
│   │   │   ├── getInvitesObservable.ts
│   │   │   ├── getPermissionsLookupObservable.ts
│   │   │   ├── getTiedRealmId.ts
│   │   │   ├── helpers/
│   │   │   │   ├── BroadcastedAndLocalEvent.ts
│   │   │   │   ├── CancelToken.ts
│   │   │   │   ├── IS_SERVICE_WORKER.ts
│   │   │   │   ├── SWBroadcastChannel.ts
│   │   │   │   ├── allSettled.ts
│   │   │   │   ├── bulkUpdate.ts
│   │   │   │   ├── computeRealmSetHash.ts
│   │   │   │   ├── date-constants.ts
│   │   │   │   ├── flatten.ts
│   │   │   │   ├── getMutationTable.ts
│   │   │   │   ├── getSyncableTables.ts
│   │   │   │   ├── getTableFromMutationTable.ts
│   │   │   │   ├── makeArray.ts
│   │   │   │   ├── randomString.ts
│   │   │   │   ├── resolveText.ts
│   │   │   │   ├── throwVersionIncrementNeeded.ts
│   │   │   │   └── visibilityState.ts
│   │   │   ├── isEagerSyncDisabled.ts
│   │   │   ├── isFirefox.ts
│   │   │   ├── isSafari.ts
│   │   │   ├── mapValueObservable.ts
│   │   │   ├── mergePermissions.ts
│   │   │   ├── middleware-helpers/
│   │   │   │   ├── guardedTable.ts
│   │   │   │   └── idGenerationHelpers.ts
│   │   │   ├── middlewares/
│   │   │   │   ├── blobResolveMiddleware.ts
│   │   │   │   ├── createIdGenerationMiddleware.ts
│   │   │   │   ├── createImplicitPropSetterMiddleware.ts
│   │   │   │   ├── createMutationTrackingMiddleware.ts
│   │   │   │   └── outstandingTransaction.ts
│   │   │   ├── overrideParseStoresSpec.ts
│   │   │   ├── performInitialSync.ts
│   │   │   ├── permissions.ts
│   │   │   ├── prodLog.ts
│   │   │   ├── service-worker.ts
│   │   │   ├── sync/
│   │   │   │   ├── BLOB_TODO.md
│   │   │   │   ├── BlobDownloadTracker.ts
│   │   │   │   ├── BlobSavingQueue.ts
│   │   │   │   ├── DEXIE_CLOUD_SYNCER_ID.ts
│   │   │   │   ├── LocalSyncWorker.ts
│   │   │   │   ├── SyncRequiredError.ts
│   │   │   │   ├── applyServerChanges.ts
│   │   │   │   ├── blobOffloading.test.ts
│   │   │   │   ├── blobOffloading.ts
│   │   │   │   ├── blobProgress.ts
│   │   │   │   ├── blobResolve.ts
│   │   │   │   ├── connectWebSocket.ts
│   │   │   │   ├── eagerBlobDownloader.ts
│   │   │   │   ├── encodeIdsForServer.ts
│   │   │   │   ├── extractRealm.ts
│   │   │   │   ├── getLatestRevisionsPerTable.ts
│   │   │   │   ├── getTablesToSyncify.ts
│   │   │   │   ├── isOnline.ts
│   │   │   │   ├── isSyncNeeded.ts
│   │   │   │   ├── listClientChanges.ts
│   │   │   │   ├── listSyncifiedChanges.ts
│   │   │   │   ├── loadCachedAccessToken.ts
│   │   │   │   ├── messageConsumerIsReady.ts
│   │   │   │   ├── messagesFromServerQueue.ts
│   │   │   │   ├── modifyLocalObjectsWithNewUserId.ts
│   │   │   │   ├── myId.ts
│   │   │   │   ├── numUnsyncedMutations.ts
│   │   │   │   ├── old_startSyncingClientChanges.ts
│   │   │   │   ├── performGuardedJob.ts
│   │   │   │   ├── ratelimit.ts
│   │   │   │   ├── registerSyncEvent.ts
│   │   │   │   ├── sync.ts
│   │   │   │   ├── syncIfPossible.ts
│   │   │   │   ├── syncWithServer.ts
│   │   │   │   ├── triggerSync.ts
│   │   │   │   └── updateBaseRevs.ts
│   │   │   ├── tsconfig.json
│   │   │   ├── types/
│   │   │   │   ├── DXCAlert.ts
│   │   │   │   ├── DXCInputField.ts
│   │   │   │   ├── DXCUserInteraction.ts
│   │   │   │   ├── NewIdOptions.ts
│   │   │   │   ├── SWMessageEvent.ts
│   │   │   │   ├── SWSyncEvent.ts
│   │   │   │   ├── SyncState.ts
│   │   │   │   └── TXExpandos.ts
│   │   │   ├── updateSchemaFromOptions.ts
│   │   │   ├── userIsActive.ts
│   │   │   ├── verifyConfig.ts
│   │   │   ├── verifySchema.ts
│   │   │   └── yjs/
│   │   │       ├── YDexieCloudSyncState.ts
│   │   │       ├── YTable.ts
│   │   │       ├── applyYMessages.ts
│   │   │       ├── awareness.ts
│   │   │       ├── createYClientUpdateObservable.ts
│   │   │       ├── createYHandler.ts
│   │   │       ├── downloadYDocsFromServer.ts
│   │   │       ├── getUpdatesTable.ts
│   │   │       ├── listUpdatesSince.ts
│   │   │       ├── listYClientMessagesAndStateVector.ts
│   │   │       ├── reopenDocSignal.ts
│   │   │       └── updateYSyncStates.ts
│   │   ├── test/
│   │   │   ├── promisedTest.ts
│   │   │   ├── qunit.d.ts
│   │   │   ├── tsconfig.json
│   │   │   └── unit/
│   │   │       ├── index.ts
│   │   │       ├── karma-env.js
│   │   │       ├── karma.conf.cjs
│   │   │       ├── run-unit-tests.html
│   │   │       ├── test-dexie-cloud-client.ts
│   │   │       ├── tests-github-issues.ts
│   │   │       └── tests-migrate-to-cloud.ts
│   │   └── tools/
│   │       ├── build-configs/
│   │       │   ├── banner.txt
│   │       │   ├── rollup.config.mjs
│   │       │   └── rollup.test.unit.config.js
│   │       ├── release-dexie-cloud-addon.sh
│   │       └── replaceVersionAndDate.cjs
│   ├── dexie-export-import/
│   │   ├── .gitignore
│   │   ├── .npmignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── dexie-export-import.ts
│   │   │   ├── export.ts
│   │   │   ├── helpers.ts
│   │   │   ├── import.ts
│   │   │   ├── index.ts
│   │   │   ├── json-stream.ts
│   │   │   ├── json-structure.ts
│   │   │   ├── tsconfig.json
│   │   │   ├── tson-arraybuffer.ts
│   │   │   ├── tson-typed-array.ts
│   │   │   └── tson.ts
│   │   ├── test/
│   │   │   ├── .gitignore
│   │   │   ├── basic-tests.ts
│   │   │   ├── edge-cases.ts
│   │   │   ├── gh-actions.sh
│   │   │   ├── index.html
│   │   │   ├── index.ts
│   │   │   ├── karma.conf.js
│   │   │   ├── qunit.d.ts
│   │   │   ├── test-data.ts
│   │   │   ├── tools.ts
│   │   │   └── tsconfig.json
│   │   └── tools/
│   │       └── build-configs/
│   │           ├── banner.txt
│   │           ├── fake-stream.js
│   │           ├── rollup.config.mjs
│   │           └── rollup.tests.config.mjs
│   └── y-dexie/
│       ├── .gitignore
│       ├── .npmignore
│       ├── README.md
│       ├── package.json
│       ├── src/
│       │   ├── DexieYProvider.ts
│       │   ├── TODO.md
│       │   ├── compressYDocs.ts
│       │   ├── createYDocProperty.ts
│       │   ├── createYjsMiddleware.ts
│       │   ├── currentUpdateRow.ts
│       │   ├── docCache.ts
│       │   ├── getOrCreateDocument.ts
│       │   ├── helpers/
│       │   │   ├── Disposable.ts
│       │   │   ├── hasOwn.ts
│       │   │   ├── nonStoppableEventChain.ts
│       │   │   ├── nop.ts
│       │   │   └── promisableChain.ts
│       │   ├── observeYDocUpdates.ts
│       │   ├── periodicGC.ts
│       │   ├── tsconfig.json
│       │   ├── types/
│       │   │   ├── DexieYDocMeta.ts
│       │   │   ├── YDocCache.ts
│       │   │   ├── YLastCompressed.ts
│       │   │   ├── YSyncState.ts
│       │   │   ├── YUpdateRow.ts
│       │   │   └── index.ts
│       │   └── y-dexie.ts
│       ├── test/
│       │   ├── gh-actions.sh
│       │   ├── promisedTest.ts
│       │   ├── qunit.d.ts
│       │   ├── tsconfig.json
│       │   └── unit/
│       │       ├── dexie-unittest-utils.js
│       │       ├── index.ts
│       │       ├── karma-env.js
│       │       ├── karma.conf.cjs
│       │       ├── run-unit-tests.html
│       │       ├── tests-dummy.ts
│       │       └── tests-yjs.ts
│       └── tools/
│           ├── build-configs/
│           │   ├── banner.txt
│           │   ├── rollup.config.mjs
│           │   └── rollup.test.unit.config.js
│           ├── release-y-dexie.sh
│           └── replaceVersionAndDate.cjs
├── dist/
│   └── README.md
├── import-wrapper-prod.d.mts
├── import-wrapper-prod.mjs
├── import-wrapper.d.mts
├── import-wrapper.mjs
├── libs/
│   ├── dexie-cloud-common/
│   │   ├── .gitignore
│   │   ├── .npmignore
│   │   ├── jest.config.js
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── AuthProvidersResponse.ts
│   │   │   ├── AuthorizationCodeTokenRequest.ts
│   │   │   ├── BaseRevisionMapEntry.ts
│   │   │   ├── DBOperation.ts
│   │   │   ├── DBOperationsSet.ts
│   │   │   ├── DBPermissionSet.ts
│   │   │   ├── DexieCloudSchema.ts
│   │   │   ├── OAuthProviderInfo.ts
│   │   │   ├── SyncChange.ts
│   │   │   ├── SyncChangeSet.ts
│   │   │   ├── SyncRequest.ts
│   │   │   ├── SyncResponse.ts
│   │   │   ├── async-generators/
│   │   │   │   ├── asyncIterablePipeline.ts
│   │   │   │   ├── consumeChunkedBinaryStream.test.ts
│   │   │   │   ├── consumeChunkedBinaryStream.ts
│   │   │   │   ├── getFetchResponseBodyGenerator.ts
│   │   │   │   └── produceChunkedBinaryStream.ts
│   │   │   ├── change-processing/
│   │   │   │   ├── DBKeyMutation.ts
│   │   │   │   ├── DBKeyMutationSet.ts
│   │   │   │   ├── applyOperation.ts
│   │   │   │   ├── applyOperations.ts
│   │   │   │   ├── subtractChanges.ts
│   │   │   │   ├── toDBOperationSet.ts
│   │   │   │   └── toSyncChangeSet.ts
│   │   │   ├── common/
│   │   │   │   ├── _global.ts
│   │   │   │   ├── b64lex.ts
│   │   │   │   ├── base64.ts
│   │   │   │   └── bigint-conversion.ts
│   │   │   ├── entities/
│   │   │   │   ├── DBRealm.ts
│   │   │   │   ├── DBRealmMember.ts
│   │   │   │   ├── DBRealmRole.ts
│   │   │   │   └── DBSyncedObject.ts
│   │   │   ├── getDbNameFromDbUrl.ts
│   │   │   ├── index.ts
│   │   │   ├── newId.ts
│   │   │   ├── tson/
│   │   │   │   ├── FakeBlob.ts
│   │   │   │   ├── FakeFile.ts
│   │   │   │   ├── StreamingSyncProcessor.ts
│   │   │   │   ├── TSONRef.ts
│   │   │   │   ├── TypeDef.ts
│   │   │   │   ├── TypeDefSet.ts
│   │   │   │   ├── TypesonSimplified.ts
│   │   │   │   ├── __tests__/
│   │   │   │   │   ├── TSONRef.test.ts
│   │   │   │   │   ├── TypesonSimplified.test.ts
│   │   │   │   │   ├── encoding.test.ts
│   │   │   │   │   ├── newId.test.ts
│   │   │   │   │   └── undefined.test.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── presets/
│   │   │   │   │   └── builtin.ts
│   │   │   │   ├── readBlobSync.ts
│   │   │   │   ├── readableStreamIterator.ts
│   │   │   │   ├── string2ArrayBuffer.ts
│   │   │   │   └── types/
│   │   │   │       ├── ArrayBuffer.ts
│   │   │   │       ├── Blob.ts
│   │   │   │       ├── BlobRef.ts
│   │   │   │       ├── Date.ts
│   │   │   │       ├── FakeBlob.ts
│   │   │   │       ├── FakeFile.ts
│   │   │   │       ├── File.ts
│   │   │   │       ├── Map.ts
│   │   │   │       ├── Set.ts
│   │   │   │       ├── TypedArray.ts
│   │   │   │       ├── bigint.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── number.ts
│   │   │   │       └── undefined.ts
│   │   │   ├── types.ts
│   │   │   ├── typings/
│   │   │   │   └── TypedArray.ts
│   │   │   ├── utils.ts
│   │   │   ├── validation/
│   │   │   │   ├── isValidSyncableID.ts
│   │   │   │   └── toStringTag.ts
│   │   │   └── yjs/
│   │   │       ├── YMessage.ts
│   │   │       ├── decoding.ts
│   │   │       └── encoding.ts
│   │   └── tsconfig.json
│   ├── dexie-react-hooks/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── rollup.config.mjs
│   │   ├── src/
│   │   │   ├── dexie-react-hooks.ts
│   │   │   ├── index.ts
│   │   │   ├── types/
│   │   │   │   ├── y-dexie.d.ts
│   │   │   │   └── yjs.d.ts
│   │   │   ├── useDocument.ts
│   │   │   ├── useLiveQuery.ts
│   │   │   ├── useObservable.ts
│   │   │   ├── usePermissions.ts
│   │   │   ├── usePromise.ts
│   │   │   ├── useSuspendingLiveQuery.ts
│   │   │   └── useSuspendingObservable.ts
│   │   ├── test/
│   │   │   ├── components/
│   │   │   │   ├── App.tsx
│   │   │   │   ├── ErrorBoundrary.tsx
│   │   │   │   ├── ItemComponent.tsx
│   │   │   │   ├── ItemListComponent.tsx
│   │   │   │   └── ItemLoaderComponent.tsx
│   │   │   ├── db/
│   │   │   │   └── index.ts
│   │   │   ├── gh-actions.sh
│   │   │   ├── index.html
│   │   │   ├── index.ts
│   │   │   ├── karma.conf.js
│   │   │   ├── models/
│   │   │   │   └── Item.ts
│   │   │   ├── tsconfig.json
│   │   │   ├── utils/
│   │   │   │   ├── BinarySemaphore.ts
│   │   │   │   ├── closest.ts
│   │   │   │   ├── sleep.ts
│   │   │   │   ├── timeout.ts
│   │   │   │   ├── waitTilEqual.ts
│   │   │   │   └── waitTilOk.ts
│   │   │   └── webpack.config.js
│   │   ├── tsconfig.json
│   │   └── webpack.config.js
│   └── dexie-svelte-query/
│       ├── .gitignore
│       ├── .npmrc
│       ├── README.md
│       ├── package.json
│       ├── src/
│       │   └── lib/
│       │       ├── index.ts
│       │       └── stateQuery.svelte.ts
│       └── tsconfig.json
├── package.json
├── pnpm-workspace.yaml
├── samples/
│   ├── angular/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── angular.json
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── app.component.ts
│   │   │   │   ├── db.ts
│   │   │   │   └── item-list.component.ts
│   │   │   ├── index.html
│   │   │   └── main.ts
│   │   └── tsconfig.json
│   ├── dexie-cloud-todo-app/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── components.json
│   │   ├── configure-app.sh
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── postcss.config.js
│   │   ├── public/
│   │   │   └── robots.txt
│   │   ├── src/
│   │   │   ├── App.test.tsx
│   │   │   ├── App.tsx
│   │   │   ├── components/
│   │   │   │   ├── AddTodoItem.tsx
│   │   │   │   ├── AddTodoList.tsx
│   │   │   │   ├── ResetDatabaseButton.tsx
│   │   │   │   ├── TodoItemView.tsx
│   │   │   │   ├── TodoListView.tsx
│   │   │   │   ├── TodoLists.tsx
│   │   │   │   ├── access-control/
│   │   │   │   │   ├── EditMember.tsx
│   │   │   │   │   ├── EditMemberAccess.tsx
│   │   │   │   │   ├── Invites.tsx
│   │   │   │   │   └── SharingForm.tsx
│   │   │   │   ├── navbar/
│   │   │   │   │   ├── NavBar.tsx
│   │   │   │   │   └── SyncStatusIcon.tsx
│   │   │   │   └── ui/
│   │   │   │       ├── CheckedSign.tsx
│   │   │   │       ├── button.tsx
│   │   │   │       ├── card.tsx
│   │   │   │       ├── checkbox.tsx
│   │   │   │       ├── dropdown-menu.tsx
│   │   │   │       └── input.tsx
│   │   │   ├── data/
│   │   │   │   ├── demoUsers.json
│   │   │   │   └── roles.json
│   │   │   ├── db/
│   │   │   │   ├── TodoDB.ts
│   │   │   │   ├── TodoItem.ts
│   │   │   │   ├── TodoList.ts
│   │   │   │   ├── db.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── logout.ts
│   │   │   ├── helpers/
│   │   │   │   ├── handleError.ts
│   │   │   │   ├── simplify-debugging.ts
│   │   │   │   └── usePersistedOpenState.ts
│   │   │   ├── index.css
│   │   │   ├── index.tsx
│   │   │   ├── lib/
│   │   │   │   └── utils.ts
│   │   │   ├── serviceWorkerRegistration.ts
│   │   │   ├── setupTests.ts
│   │   │   ├── sw.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tailwind.config.js
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   ├── vite.config.ts
│   │   └── vitest.config.ts
│   ├── full-text-search/
│   │   └── FullTextSearch.js
│   ├── liveQuery/
│   │   └── liveQuery.html
│   ├── open-existing-db/
│   │   └── dump-databases.html
│   ├── react/
│   │   └── README.md
│   ├── remote-sync/
│   │   ├── ajax/
│   │   │   ├── AjaxSyncProtocol.js
│   │   │   └── jquery-2.1.0.js
│   │   └── websocket/
│   │       ├── WebSocketSyncProtocol.js
│   │       ├── WebSocketSyncServer.js
│   │       └── websocketserver-shim.js
│   ├── svelte/
│   │   └── README.md
│   ├── vanilla-js/
│   │   ├── hello-world-modern.html
│   │   └── hello-world.html
│   └── vue/
│       ├── .gitignore
│       ├── README.md
│       ├── index.html
│       ├── package.json
│       ├── public/
│       │   └── index.html
│       ├── src/
│       │   ├── App.vue
│       │   ├── components/
│       │   │   ├── AddTodo.vue
│       │   │   ├── Todo.vue
│       │   │   └── TodoList.vue
│       │   ├── database.js
│       │   └── main.js
│       └── vite.config.js
├── src/
│   ├── classes/
│   │   ├── collection/
│   │   │   ├── collection-constructor.ts
│   │   │   ├── collection-helpers.ts
│   │   │   ├── collection.ts
│   │   │   └── index.ts
│   │   ├── dexie/
│   │   │   ├── dexie-dom-dependencies.ts
│   │   │   ├── dexie-open.ts
│   │   │   ├── dexie-static-props.ts
│   │   │   ├── dexie.ts
│   │   │   ├── generate-middleware-stacks.ts
│   │   │   ├── index.ts
│   │   │   ├── transaction-helpers.ts
│   │   │   └── vip.ts
│   │   ├── entity/
│   │   │   └── Entity.ts
│   │   ├── observable/
│   │   │   └── observable.ts
│   │   ├── table/
│   │   │   ├── index.ts
│   │   │   ├── table-constructor.ts
│   │   │   ├── table-helpers.ts
│   │   │   └── table.ts
│   │   ├── transaction/
│   │   │   ├── index.ts
│   │   │   ├── transaction-constructor.ts
│   │   │   └── transaction.ts
│   │   ├── version/
│   │   │   ├── schema-helpers.ts
│   │   │   ├── version-constructor.ts
│   │   │   └── version.ts
│   │   └── where-clause/
│   │       ├── where-clause-constructor.ts
│   │       ├── where-clause-helpers.ts
│   │       └── where-clause.ts
│   ├── dbcore/
│   │   ├── cache-existing-values-middleware.ts
│   │   ├── dbcore-indexeddb.ts
│   │   ├── get-effective-keys.ts
│   │   ├── get-key-extractor.ts
│   │   ├── keyrange.ts
│   │   ├── proxy-cursor.ts
│   │   └── virtual-index-middleware.ts
│   ├── errors/
│   │   ├── errors.d.ts
│   │   ├── errors.js
│   │   └── index.ts
│   ├── functions/
│   │   ├── apply-update-spec.ts
│   │   ├── bulk-delete.ts
│   │   ├── chaining-functions.js
│   │   ├── cmp.ts
│   │   ├── combine.ts
│   │   ├── compare-functions.ts
│   │   ├── event-wrappers.ts
│   │   ├── get-object-diff.ts
│   │   ├── is-promise-like.ts
│   │   ├── make-class-constructor.ts
│   │   ├── propmods/
│   │   │   ├── add.ts
│   │   │   ├── index.ts
│   │   │   ├── remove.ts
│   │   │   └── replace-prefix.ts
│   │   ├── quirks.ts
│   │   ├── stringify-key.d.ts
│   │   ├── stringify-key.js
│   │   ├── temp-transaction.ts
│   │   ├── utils.ts
│   │   └── workaround-undefined-primkey.ts
│   ├── globals/
│   │   ├── connections.ts
│   │   ├── constants.ts
│   │   ├── global-events.ts
│   │   └── global.ts
│   ├── helpers/
│   │   ├── Events.js
│   │   ├── database-enumerator.ts
│   │   ├── debug.ts
│   │   ├── index-spec.ts
│   │   ├── promise.d.ts
│   │   ├── promise.js
│   │   ├── prop-modification.ts
│   │   ├── rangeset.ts
│   │   ├── table-schema.ts
│   │   ├── vipify.ts
│   │   └── yield-support.ts
│   ├── hooks/
│   │   └── hooks-middleware.ts
│   ├── index-umd.ts
│   ├── index.ts
│   ├── live-query/
│   │   ├── cache/
│   │   │   ├── adjust-optimistic-request-from-failures.ts
│   │   │   ├── apply-optimistic-ops.ts
│   │   │   ├── are-ranges-equal.ts
│   │   │   ├── cache-middleware.ts
│   │   │   ├── cache.ts
│   │   │   ├── does-ranges-overlap.ts
│   │   │   ├── find-compatible-query.ts
│   │   │   ├── is-cachable-context.ts
│   │   │   ├── is-cachable-request.ts
│   │   │   ├── is-super-range.ts
│   │   │   ├── is-within-range.ts
│   │   │   ├── signalSubscribers.ts
│   │   │   └── subscribe-cachentry.ts
│   │   ├── enable-broadcast.ts
│   │   ├── extend-observability-set.ts
│   │   ├── index.ts
│   │   ├── live-query.ts
│   │   ├── obs-sets-overlap.ts
│   │   ├── observability-middleware.ts
│   │   └── propagate-locally.ts
│   ├── public/
│   │   ├── index.d.ts
│   │   └── types/
│   │       ├── _insert-type.d.ts
│   │       ├── cache.d.ts
│   │       ├── collection.d.ts
│   │       ├── db-events.d.ts
│   │       ├── db-schema.d.ts
│   │       ├── dbcore.d.ts
│   │       ├── dbquerycore.d.ts
│   │       ├── dexie-constructor.d.ts
│   │       ├── dexie-dom-dependencies.d.ts
│   │       ├── dexie-event-set.d.ts
│   │       ├── dexie-event.d.ts
│   │       ├── dexie.d.ts
│   │       ├── entity-table.d.ts
│   │       ├── entity.d.ts
│   │       ├── errors.d.ts
│   │       ├── global.d.ts
│   │       ├── index-spec.d.ts
│   │       ├── indexable-type.d.ts
│   │       ├── insert-type.d.ts
│   │       ├── is-strictly-any.d.ts
│   │       ├── keypaths.d.ts
│   │       ├── middleware.d.ts
│   │       ├── observable.d.ts
│   │       ├── promise-extended.d.ts
│   │       ├── prop-modification.d.ts
│   │       ├── rangeset.d.ts
│   │       ├── table-hooks.d.ts
│   │       ├── table-schema.d.ts
│   │       ├── table.d.ts
│   │       ├── then-shortcut.d.ts
│   │       ├── transaction-events.d.ts
│   │       ├── transaction-mode.d.ts
│   │       ├── transaction.d.ts
│   │       ├── update-spec.d.ts
│   │       ├── version.d.ts
│   │       └── where-clause.d.ts
│   ├── support-bfcache.ts
│   └── tsconfig.json
├── test/
│   ├── .eslintrc.json
│   ├── .gitignore
│   ├── data.json
│   ├── deepEqual.js
│   ├── dexie-unittest-utils.js
│   ├── gh-actions.sh
│   ├── integrations/
│   │   └── test-dexie-relationships/
│   │       ├── basic-tests.js
│   │       ├── gh-actions.sh
│   │       ├── index.js
│   │       ├── karma.conf.js
│   │       ├── package.json
│   │       └── webpack.config.js
│   ├── is-idb-and-promise-compatible.js
│   ├── karma-env.js
│   ├── karma.browsers.matrix.d.ts
│   ├── karma.browsers.matrix.js
│   ├── karma.common.d.ts
│   ├── karma.common.js
│   ├── karma.conf.js
│   ├── karma.lambdatest.d.ts
│   ├── karma.lambdatest.js
│   ├── lt-local.js
│   ├── rebalance.md
│   ├── run-unit-tests.html
│   ├── tests-all.js
│   ├── tests-asyncawait.js
│   ├── tests-binarykeys.js
│   ├── tests-blobs.js
│   ├── tests-chrome-transaction-durability.js
│   ├── tests-cmp.js
│   ├── tests-collection.js
│   ├── tests-crud-hooks.js
│   ├── tests-exception-handling.js
│   ├── tests-extendability.js
│   ├── tests-idb30.js
│   ├── tests-live-query.js
│   ├── tests-max-connections.js
│   ├── tests-misc.js
│   ├── tests-open.js
│   ├── tests-performance.js
│   ├── tests-promise.js
│   ├── tests-rangeset.js
│   ├── tests-table.js
│   ├── tests-transaction.js
│   ├── tests-upgrading.js
│   ├── tests-whereclause.js
│   ├── tests-yield.js
│   ├── tsconfig.json
│   ├── typings-test/
│   │   ├── test-extend-dexie.ts
│   │   ├── test-misc.ts
│   │   ├── test-typings.ts
│   │   ├── test-updatespec.ts
│   │   └── tsconfig.json
│   └── worker.js
├── tools/
│   ├── .eslintrc.json
│   ├── build-configs/
│   │   ├── banner.txt
│   │   ├── rollup.config.js
│   │   ├── rollup.config.mjs
│   │   ├── rollup.modern.config.js
│   │   ├── rollup.modern.config.mjs
│   │   ├── rollup.tests.config.js
│   │   ├── rollup.tests.config.mjs
│   │   ├── rollup.umd.config.js
│   │   └── rollup.umd.config.mjs
│   ├── fix-dts-duplicates.js
│   ├── prepend.js
│   ├── release.sh
│   └── replaceVersionAndDate.js
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
github: dfahlander


================================================
FILE: .github/workflows/dexie-cloud-common.yml
================================================
name: dexie-cloud-common Tests

on:
  workflow_dispatch:
  push:
    branches:
      - master
    paths:
      - 'libs/dexie-cloud-common/**'
      - '.github/workflows/dexie-cloud-common.yml'
  pull_request:
    types: [opened, synchronize, reopened]
    paths:
      - 'libs/dexie-cloud-common/**'
      - '.github/workflows/dexie-cloud-common.yml'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 9

      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: "pnpm"

      - name: Install dependencies
        run: pnpm install --no-frozen-lockfile

      - name: Build dexie-cloud-common
        run: pnpm --filter dexie-cloud-common run build

      - name: Run tests
        run: pnpm --filter dexie-cloud-common test


================================================
FILE: .github/workflows/main.yml
================================================
name: Build and Test

on:
  workflow_dispatch:
  push:
    branches:
      - master # Add also master-4 when dexie@4 is stable and master will represent dexie@5. dexie@3 has its own workflow.
  pull_request:
      types: [opened, synchronize, reopened]
env:
  LAMBDATEST: "true"
  GH_ACTIONS: "true"
  LT_USERNAME: ${{ secrets.LT_USERNAME }}
  LT_ACCESS_KEY: ${{ secrets.LT_ACCESS_KEY }}

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        TF:
          - test
          - addons/Dexie.Observable/test
          - addons/Dexie.Syncable/test
          - addons/dexie-export-import/test
          - addons/y-dexie/test
          - libs/dexie-react-hooks/test
      fail-fast: true # If one test fails, abort the rest of the tests
      max-parallel: 6 # At least for browserstack, this seems to be needed to avoid timeouts
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Set up pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 9
      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: "pnpm"
      - name: Install dependencies
        run: pnpm install --no-frozen-lockfile
      - name: Build
        run: pnpm run build
      - name: Set LT_TUNNEL_NAME
        run: echo "LT_TUNNEL_NAME=${{ matrix.TF }}-${{ github.run_id }}-${{ github.run_attempt }}" >> $GITHUB_ENV
      - name: Run headless test
        uses: coactions/setup-xvfb@v1
        with:
          run: bash -e ./gh-actions.sh
          working-directory: ${{ matrix.TF }}


================================================
FILE: .gitignore
================================================
# Ignore node_modules
node_modules/

# Ignore all build output
dist/*.js
dist/*.map
dist/*.ts
dist/*.gz
dist/*.mjs
dist/**/*.js
dist/**/*.map
dist/**/*.ts
dist/**/*.gz
dist/**/*.mjs

# Other ignores
tmp/
.idea/
.eslintcache

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# User-specific files
*.suo
*.user
*.sln.docstates

# Build results

[Dd]ebug/
[Rr]elease/
x64/
[Bb]in/
[Oo]bj/

# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
!packages/*/build/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile

# Visual Studio profiler
*.psess
*.vsp
*.vspx

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# NCrunch
*.ncrunch*
.*crunch*.local.xml

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.Publish.xml
*.pubxml

# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/

# Windows Azure Build Output
csx
*.build.csdef

# Windows Store app package directory
AppPackages/

# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm

# SQL Server files
App_Data/*.mdf
App_Data/*.ldf

# =========================
# Windows detritus
# =========================

# Windows image file caches
Thumbs.db
ehthumbs.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Mac crap
.DS_Store

*.csproj
Dexie.sln
samples/typescript/appdb.js
samples/typescript/app.js
samples/typescript/app.js.map
samples/typescript/appdb.js.map
samples/typescript/console.js
samples/typescript/console.js.map
samples/typescript/utils.js
samples/typescript/utils.js.map
/.vscode
/jsconfig.json

/.ntvs_analysis.dat
/*.njsproj
libs/dexie-cloud-common/tsconfig.tsbuildinfo

#lambdatest tunnel binary
.lambdatest
tunnel.pid


================================================
FILE: .npmignore
================================================
**/tmp/
samples/
addons/
libs/
*.njsproj
.*
*.log
test/
tools/
bower.json
src/
.lambdatest
tunnel.pid
tsconfig.json
pnpm-workspace.yaml


================================================
FILE: .npmrc
================================================
auto-install-peers=true


================================================
FILE: .prettierrc
================================================
{
  "trailingComma": "es5",
  "tabWidth": 2,
  "singleQuote": true
}


================================================
FILE: .prettierrc.yml
================================================
trailingComma: 'none'
tabWidth: 2
semi: true
singleQuote: true


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at code@dexie.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: CONTRIBUTING.md
================================================
HOW TO CONTRIBUTE
=================

We appreciate contributions in forms of:

* issues
* help answering questions in [issues](https://github.com/dexie/Dexie.js/issues) and on [stackoverflow](https://stackexchange.com/filters/233583/dexie-stackoverflow)
* fixing bugs via pull-requests
* developing addons or other [derived work](https://dexie.org/docs/DerivedWork)
* promoting Dexie.js
* sharing ideas

Contribute while developing your own app
========================================

Dexie uses pnpm package manager. Refer to [pnpm.io/installation](https://pnpm.io/installation) for how to install pnpm.

Here is a little cheat-sheet for how to symlink your app's `node_modules/dexie` to a place where you can edit the source, version control your changes and create pull requests back to Dexie. Assuming you've already ran `npm install dexie` for the app your are developing.

1. Fork Dexie.js from the web gui on github
2. Clone your fork locally by launching a shell/command window and cd to a neutral place (like `~repos/`, `c:\repos` or whatever)
3. Run the following commands:

    ```
    git clone https://github.com/YOUR-USERNAME/Dexie.js.git dexie
    cd dexie
    pnpm install
    pnpm run build
    npm link # Or yarn link or pnpm link --global depending on what package manager you are using.
    ```
3. cd to your app directory and write:
    ```
    npm link dexie # Or yarn link dexie / pnpm link dexie depending on your package manager.
    ```

Your app's `node_modules/dexie/` is now sym-linked to the Dexie.js clone on your hard drive so any change you do there will propagate to your app. Build dexie.js using `pnpm run build` or `pnpm run watch`. The latter will react on any source file change and rebuild the dist files.

That's it. Now you're up and running to test and commit changes to files under dexie/src/* or dexie/test/* and the changes will instantly affect the app you are developing.

If you're on yarn or pnpm, do the same procedures using yarn link / pnpm link.

Pull requests are more than welcome. Some advices are:

* Run pnpm test before making a pull request.
* If you find an issue, a unit test that reproduces it is lovely ;). If you don't know where to put it, put it in `test/tests-misc.js`. We use qunit. Just look at existing tests in `tests-misc.js` to see how they should be written. Tests are transpiled in the build script so you can use ES6 if you like.

Build
-----
```
# To install pnpm, see https://pnpm.io/installation
pnpm install
pnpm run build
```

Test
----
```
pnpm test
```

Watch
-----
```
pnpm run watch
```


================================================
FILE: LICENSE
================================================
Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright {yyyy} {name of copyright owner}

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.



================================================
FILE: NOTICE
================================================
Dexie.js

Copyright (c) 2014-2017 David Fahlander

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


================================================
FILE: README.md
================================================
# Dexie.js

[![NPM Version][npm-image]][npm-url] ![Build Status](https://github.com/dexie/Dexie.js/actions/workflows/main.yml/badge.svg) [![Join our Discord](https://img.shields.io/discord/1328303736363421747?label=Discord&logo=discord&style=badge)](https://discord.gg/huhre7MHBF)

Dexie.js is a wrapper library for indexedDB - the standard database in the browser. https://dexie.org.

#### Why Dexie.js?

IndexedDB is the portable database for all browser engines. Dexie.js makes it fun and easy to work with.

But also:

* Dexie.js is widely used by 100,000 of web sites, apps and other projects and supports all browsers, Electron for Desktop apps, Capacitor for iOS / Android apps and of course pure PWAs.
* Dexie.js works around bugs in the IndexedDB implementations, giving a more stable user experience.
* Need sync? [Dexie Cloud](https://dexie.org/cloud/) adds real-time sync, auth, and collaboration on top of Dexie.js — no backend needed.

#### Hello World (vanilla JS)

```html
<!DOCTYPE html>
<html>
  <head>
    <script type="module">
      // Import Dexie
      import { Dexie } from 'https://unpkg.com/dexie/dist/modern/dexie.mjs';

      //
      // Declare Database
      //
      const db = new Dexie('FriendDatabase');
      db.version(1).stores({
        friends: '++id, age'
      });

      //
      // Play with it
      //
      try {
        await db.friends.add({ name: 'Alice', age: 21 });

        const youngFriends = await db.friends
            .where('age')
            .below(30)
            .toArray();

        alert(`My young friends: ${JSON.stringify(youngFriends)}`);
      } catch (e) {
        alert(`Oops: ${e}`);
      }
    </script>
  </head>
</html>
```

Yes, it's that simple. Read [the docs](https://dexie.org/docs/) to get into the details.

#### Hello World (legacy script tags)

```html
<!DOCTYPE html>
<html>
  <head>
    <script src="https://unpkg.com/dexie/dist/dexie.js"></script>
    <script>

      //
      // Declare Database
      //
      const db = new Dexie('FriendDatabase');
      db.version(1).stores({
        friends: '++id, age'
      });

      //
      // Play with it
      //
      db.friends.add({ name: 'Alice', age: 21 }).then(() => {
        return db.friends
          .where('age')
          .below(30)
          .toArray();
      }).then(youngFriends => {
        alert (`My young friends: ${JSON.stringify(youngFriends)}`);
      }).catch (e => {
        alert(`Oops: ${e}`);
      });

    </script>
  </head>
</html>
```

#### Hello World (React + Typescript)

Real-world apps are often built using components in various frameworks. Here's a version of Hello World written for React and Typescript. There are also links below this sample to more tutorials for different frameworks...

```tsx
import React from 'react';
import { Dexie, type EntityTable } from 'dexie';
import { useLiveQuery } from 'dexie-react-hooks';

// Typing for your entities (hint is to move this to its own module)
export interface Friend {
  id: number;
  name: string;
  age: number;
}

// Database declaration (move this to its own module also)
export const db = new Dexie('FriendDatabase') as Dexie & {
  friends: EntityTable<Friend, 'id'>;
};
db.version(1).stores({
  friends: '++id, age',
});

// Component:
export function MyDexieReactComponent() {
  const youngFriends = useLiveQuery(() =>
    db.friends
      .where('age')
      .below(30)
      .toArray()
  );

  return (
    <>
      <h3>My young friends</h3>
      <ul>
        {youngFriends?.map((f) => (
          <li key={f.id}>
            Name: {f.name}, Age: {f.age}
          </li>
        ))}
      </ul>
      <button
        onClick={() => {
          db.friends.add({ name: 'Alice', age: 21 });
        }}
      >
        Add another friend
      </button>
    </>
  );
}
```

[Tutorials for React, Svelte, Vue, Angular and vanilla JS](https://dexie.org/docs/Tutorial/Getting-started)

[API Reference](https://dexie.org/docs/API-Reference)

[Samples](https://dexie.org/docs/Samples)

### Performance

Dexie has kick-ass performance. Its [bulk methods](<https://dexie.org/docs/Table/Table.bulkPut()>) take advantage of a lesser-known feature in IndexedDB that makes it possible to store stuff without listening to every onsuccess event. This speeds up the performance to a maximum.

#### Supported operations

```js
above(key): Collection;
aboveOrEqual(key): Collection;
add(item, key?): Promise;
and(filter: (x) => boolean): Collection;
anyOf(keys[]): Collection;
anyOfIgnoreCase(keys: string[]): Collection;
below(key): Collection;
belowOrEqual(key): Collection;
between(lower, upper, includeLower?, includeUpper?): Collection;
bulkAdd(items: Array): Promise;
bulkDelete(keys: Array): Promise;
bulkPut(items: Array): Promise;
clear(): Promise;
count(): Promise;
delete(key): Promise;
distinct(): Collection;
each(callback: (obj) => any): Promise;
eachKey(callback: (key) => any): Promise;
eachPrimaryKey(callback: (key) => any): Promise;
eachUniqueKey(callback: (key) => any): Promise;
equals(key): Collection;
equalsIgnoreCase(key): Collection;
filter(fn: (obj) => boolean): Collection;
first(): Promise;
get(key): Promise;
inAnyRange(ranges): Collection;
keys(): Promise;
last(): Promise;
limit(n: number): Collection;
modify(changeCallback: (obj: T, ctx:{value: T}) => void): Promise;
modify(changes: { [keyPath: string]: any } ): Promise;
noneOf(keys: Array): Collection;
notEqual(key): Collection;
offset(n: number): Collection;
or(indexOrPrimayKey: string): WhereClause;
orderBy(index: string): Collection;
primaryKeys(): Promise;
put(item: T, key?: Key): Promise;
reverse(): Collection;
sortBy(keyPath: string): Promise;
startsWith(key: string): Collection;
startsWithAnyOf(prefixes: string[]): Collection;
startsWithAnyOfIgnoreCase(prefixes: string[]): Collection;
startsWithIgnoreCase(key: string): Collection;
toArray(): Promise;
toCollection(): Collection;
uniqueKeys(): Promise;
until(filter: (value) => boolean, includeStopEntry?: boolean): Collection;
update(key: Key, changes: { [keyPath: string]: any }): Promise;
```

This is a mix of methods from [WhereClause](https://dexie.org/docs/WhereClause/WhereClause), [Table](https://dexie.org/docs/Table/Table) and [Collection](https://dexie.org/docs/Collection/Collection). Dive into the [API reference](https://dexie.org/docs/API-Reference) to see the details.

## Dexie Cloud

[Dexie Cloud](https://dexie.org/cloud/) is the easiest way to add sync, authentication, and real-time collaboration to your Dexie app. You keep writing frontend code with Dexie.js — Dexie Cloud handles the rest.

**What you get:**
- 🔄 **Sync across devices** — changes propagate in real time, no polling needed
- 🔐 **Authentication** — built-in user auth, no identity provider required
- 🛡️ **Access control** — share data between users with fine-grained permissions
- 📁 **File & blob storage** — store attachments alongside your structured data
- ✈️ **Offline-first** — works fully offline, syncs when back online

**Getting started is just a few lines:**

```bash
npm install dexie-cloud-addon
```

```ts
import Dexie from 'dexie';
import dexieCloud from 'dexie-cloud-addon';

const db = new Dexie('MyDatabase', { addons: [dexieCloud] });
db.version(1).stores({ items: '@id, title' });
db.cloud.configure({ databaseUrl: 'https://<your-db>.dexie.cloud' });
```

That's it. Your existing Dexie app now syncs. Hosted cloud or self-hosted on your own infrastructure. 👋

→ [Quickstart guide](https://dexie.org/cloud/docs/quickstart)

**Sample app:**

Source: [Dexie Cloud To-do app](https://github.com/dexie/Dexie.js/tree/master/samples/dexie-cloud-todo-app)

Live demo: https://dexie.github.io/Dexie.js/dexie-cloud-todo-app/

## Samples

https://dexie.org/docs/Samples

https://github.com/dexie/Dexie.js/tree/master/samples

## Knowledge Base

[https://dexie.org/docs/Questions-and-Answers](https://dexie.org/docs/Questions-and-Answers)

## Website

[https://dexie.org](https://dexie.org)

## Install via npm

```
npm install dexie
```

## Download

For those who don't like package managers, here's the download links:

### UMD (for legacy script includes as well as commonjs require):

https://unpkg.com/dexie@latest/dist/dexie.min.js

https://unpkg.com/dexie@latest/dist/dexie.min.js.map

### Modern (ES module):

https://unpkg.com/dexie@latest/dist/modern/dexie.min.mjs

https://unpkg.com/dexie@latest/dist/modern/dexie.min.mjs.map

### Typings:

https://unpkg.com/dexie@latest/dist/dexie.d.ts

# Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md)

## Build

```
pnpm install
pnpm run build
```

## Test

```
pnpm test
```

## Watch

```
pnpm run watch
```

<br/>

[![Browser testing via LAMDBATEST](https://dexie.org/assets/images/lambdatest2.png)](https://www.lambdatest.com/)

[npm-image]: https://img.shields.io/npm/v/dexie.svg?style=flat
[npm-url]: https://npmjs.org/package/dexie


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Supported Versions

| Version | Supported          | Branch
| ------- | ------------------ | --------
| 4.x     | :white_check_mark: | master
| 3.x     | :white_check_mark: | master-3
| 2.0.x   | :x: | master-2
| 1.5.x   | :x: | master-1
| < 1.5.1 | :x:                |

## Reporting a Vulnerability

To report a security vulnerability in Dexie.js, please send an email to code@dexie.org describing the vulnerability and how to reproduce it.

If we find an issue to be regarded as a security vulnerability, we will patch and release a new version in all the supported versions as soon as possible.
Keep in mind though that this is an uncommercial open source project which means that sometimes you might have to be the one that
*fixes* the issue and not just report it.

## Fixing a Vulnerability

Fix the issue in the corresponding branch for the major version according to the table above where it applies and
create pull requests. Make sure that you have the words "security" or "vulnerability" in the title of the Pull Request
in order to get the correct attention for it to be merged and released as soon as possible.



================================================
FILE: addons/Dexie.Observable/.gitignore
================================================
dist/*.js
dist/*.map
dist/*.ts
dist/*.gz
**/tmp/


================================================
FILE: addons/Dexie.Observable/.npmignore
================================================
tools/
src/
.*
tmp/
**/tmp/
test
*.log


================================================
FILE: addons/Dexie.Observable/README.md
================================================
# Dexie.Observable.js

*NOTE! Dexie's liveQuery feature is NOT dependent on this old package. This package has been unmaintained for a looong time and might be retired*

Observe changes to database - even when they happen in another browser window.

### Install
```
npm install dexie --save
npm install dexie-observable --save
```

### Use
```js
import Dexie from 'dexie';
import 'dexie-observable';

// Use Dexie as normally - but you can also subscribe to db.on('changes').

```

#### Usage with existing DB

In case you want to use Dexie.Observable with your existing database, you will have to do a schema upgrade. Without it Dexie.Observable will not be able to properly work.

```javascript
import Dexie from 'dexie';
import 'dexie-observable';

var db = new Dexie('myExistingDb');
db.version(1).stores(... existing schema ...);

// Now, add another version, just to trigger an upgrade for Dexie.Observable
db.version(2).stores({}); // No need to add / remove tables. This is just to allow the addon to install its tables.
```

### Dependency Tree

 * [Dexie.Syncable.js](https://dexie.org/docs/Syncable/Dexie.Syncable.js)
   * **Dexie.Observable.js**
     * [Dexie.js](https://dexie.org/docs/Dexie/Dexie.js)
       * [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)

### Source

[Dexie.Observable.js](https://github.com/dexie/Dexie.js/blob/master/addons/Dexie.Observable/src/Dexie.Observable.js)

### Description

Dexie.Observable is an add-on to Dexie.js makes it possible to listen for changes on the database even if the changes are made in a foreign window. The addon provides a "storage" event for IndexedDB, much like the storage event (onstorage) for localStorage.

In contrary to the [Dexie CRUD hooks](https://dexie.org/docs/Tutorial/Design#the-crud-hooks-create-read-update-delete), this event reacts not only on changes made on the current db instance but also on changes occurring on db instances in other browser windows. <u>This enables a Web Apps to react to database changes and update their views accordingly.</u>

Dexie.Observable is also the base of [Dexie.Syncable.js](https://dexie.org/docs/Syncable//Dexie.Syncable.js) - an add-on that enables two-way replication with a remote server.

### Extended Methods, Properties and Events

#### UUID key generator
When defining your stores in [Version.stores()](https://dexie.org/docs/Version/Version.stores()) you may use the $$ (double dollar) prefix to your primary key. This will make it auto-generated to a UUID string. See sample below.

#### Dexie.Observable.createUUID()
A static method added to Dexie that creates a UUID. This method is used internally when using the $$ prefix to primary keys. To change the format of $$ primary keys, just override Dexie.createUUID by setting it to your desired function instead.

#### db.on('changes') event
Subscribe to any database changes no matter if they occur locally or in other browser window.

Parameters to your callback:

<table>
<tr><td>changes : Array&lt;<a href="https://dexie.org/docs/Observable/Dexie.Observable.DatabaseChange">DatabaseChange</a>&gt;</td><td>Array of changes that have occured in database (locally or in other window) since last time event was triggered, or the time of starting subscribing to changes.</td></tr>
<tr><td>partial: Boolean</td><td>True in case the array does not contain all changes. In this case, your callback will soon be called again with the additional changes and partial=false when all changes are delivered.</td></tr>
</table>

#### Example (here we're using plain ES6 script tags):
```html
<html>
    <head>
    <script src="dexie.min.js"></script>
    <script src="dexie-observable.min.js"></script> <!-- Enable DB observation -->
    <script>
        var db = new Dexie("ObservableTest");
        db.version(1).stores({
            friends: "$$uuid,name"
        });
        db.on('changes', function (changes) {
            changes.forEach(function (change) {
                switch (change.type) {
                    case 1: // CREATED
                        console.log('An object was created: ' + JSON.stringify(change.obj);
                        break;
                    case 2: // UPDATED
                        console.log('An object with key ' + change.key + ' was updated with modifications: ' + JSON.stringify(change.mods));
                        break;
                    case 3: // DELETED
                        console.log('An object was deleted: ' + JSON.stringify(change.oldObj);
                        break;
            });
        });
        db.open();
        // Make an initial put() - will result in a CREATE-change:
        db.friends.put({name: "Kalle"}).then(function(primKey) {
            // Call put() with existing primary key - will result in an UPDATE-change:
            db.friends.put({uuid: primKey, name: "Olle"}).then (function () {
                // Call delete() will result in a DELETE-change:
                db.friends.delete(primKey);
            });
        });

        // Result that will be logged:
        // An object was created: {"uuid": "23bada36-d27a-4e78-a978-1ab3c4129cd0", name: "Kalle"}
        // An object with key: 23bada36-d27a-4e78-a978-1ab3c4129cd0 was updated with modifications: {"name": "Olle"}
        // An object was deleted: {"uuid": "23bada36-d27a-4e78-a978-1ab3c4129cd0", name: "Olle"}
    </script>
    </head>
    <body>
    </body>
</html>
```


================================================
FILE: addons/Dexie.Observable/api.d.ts
================================================
/**
 * API for Dexie.Observable.
 *
 * Contains interfaces used by dexie-observable.
 *
 * By separating module 'dexie-observable' from 'dexie-observable/api' we
 * distinguish that:
 *
 *   import {...} from 'dexie-observable/api' is only for getting access to its
 *                                            interfaces and has no side-effects.
 *                                            Typescript-only import.
 *
 *   import 'dexie-observable' is only for side effects - to extend Dexie with
 *                             functionality of dexie-observable.
 *                             Javascript / Typescript import.
 *
 */
export const enum DatabaseChangeType {
    Create = 1,
    Update = 2,
    Delete = 3,
}

export interface ICreateChange {
    type: DatabaseChangeType.Create;
    table: string;
    key: any;
    obj: any;
    source?: string;
}

export interface IUpdateChange {
    type: DatabaseChangeType.Update;
    table: string;
    key: any;
    mods: { [keyPath: string]: any | undefined };
    obj: any;
    oldObj: any;
    source?: string;
}

export interface IDeleteChange {
    type: DatabaseChangeType.Delete;
    table: string;
    key: any;
    oldObj: any;
    source?: string;
}

export type IDatabaseChange = ICreateChange | IUpdateChange | IDeleteChange;


================================================
FILE: addons/Dexie.Observable/api.js
================================================
// This file is deliberatly left empty to allow the api.d.ts to contain the definitions for Dexie.Observable without generating an error on webpack


================================================
FILE: addons/Dexie.Observable/dist/README.md
================================================
## Can't find dexie-observable.js?
Transpiled code (dist version) IS ONLY checked in to
the [releases](https://github.com/dexie/Dexie.js/tree/releases/addons/Dexie.Observable/dist)
branch.

## Download
[unpkg.com/dexie-observable/dist/dexie-observable.js](https://unpkg.com/dexie-observable/dist/dexie-observable.js)

[unpkg.com/dexie-observable/dist/dexie-observable.min.js](https://unpkg.com/dexie-observable/dist/dexie-observable.min.js)

[unpkg.com/dexie-observable/dist/dexie-observable.js.map](https://unpkg.com/dexie-observable/dist/dexie-observable.js.map)

[unpkg.com/dexie-observable/dist/dexie-observable.min.js.map](https://unpkg.com/dexie-observable/dist/dexie-observable.min.js.map)

## npm
```
npm install dexie-observable --save
```
## bower
Since Dexie v1.3.4, addons are included in the dexie bower package. 
```
$ bower install dexie --save
$ ls bower_components/dexie/addons/Dexie.Observable/dist
dexie-observable.js  dexie-observable.js.map  dexie-observable.min.js  dexie-observable.min.js.map

```
## Or build them yourself...
Fork Dexie.js, then:
```
git clone https://github.com/YOUR-USERNAME/Dexie.js.git
cd Dexie.js
npm install
cd addons/Dexie.Observable
npm run build       # or npm run watch

```
If you're on windows, you need to use an elevated command prompt of some reason to get `npm install` to work.


================================================
FILE: addons/Dexie.Observable/package.json
================================================
{
  "name": "dexie-observable",
  "version": "4.0.1-beta.13",
  "description": "Addon to Dexie that makes it possible to observe database changes no matter if they occur on other db instance or other window.",
  "main": "dist/dexie-observable.js",
  "module": "dist/dexie-observable.es.js",
  "jsnext:main": "dist/dexie-observable.es.js",
  "typings": "dist/dexie-observable.d.ts",
  "jspm": {
    "format": "cjs",
    "ignore": [
      "src/"
    ]
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/dexie/Dexie.js.git"
  },
  "keywords": [
    "indexeddb",
    "browser",
    "dexie",
    "addon"
  ],
  "author": "David Fahlander",
  "contributors": [
    "Nikolas Poniros <https://github.com/nponiros>",
    "Yury Solovyov <https://github.com/YurySolovyov>",
    "Martin Diphoorn <https://github.com/martindiphoorn>",
    "Corbin Crutchley <https://github.com/crutchcorn>"
  ],
  "license": "Apache-2.0",
  "bugs": {
    "url": "https://github.com/dexie/Dexie.js/issues"
  },
  "scripts": {
    "build": "just-build",
    "watch": "just-build --watch",
    "test": "pnpm run build && pnpm run test:typings && pnpm run test:unit && pnpm run test:integration",
    "test:unit": "karma start test/unit/karma.conf.js --single-run",
    "test:integration": "karma start test/integration/karma.conf.js --single-run",
    "test:typings": "just-build test-typings",
    "test:unit:debug": "karma start test/unit/karma.conf.js --log-level debug",
    "test:integration:debug": "karma start test/integrations/karma.conf.js --log-level debug",
    "test:ltcloud": "cross-env LAMBDATEST=true pnpm run test:ltTunnel & sleep 10 && pnpm run test:unit; UNIT_STATUS=$?; exit $UNIT_STATUS",
    "test:ltTunnel": "node ../../test/lt-local",
    "test:ltcloud:integration": "cross-env LAMBDATEST=true pnpm run test:integration; UNIT_STATUS=$?; kill $(cat tunnel.pid); exit $UNIT_STATUS"
  },
  "just-build": {
    "default": [
      "just-build release test"
    ],
    "dev": [
      "just-build dexie-observable test"
    ],
    "dexie-observable": [
      "# Build UMD module",
      "tsc --allowJs -t es5 -m es2015 --outDir tools/tmp/es5/src/ --sourceMap --skipLibCheck src/Dexie.Observable.js [--watch 'Compilation complete.']",
      "rollup -c tools/build-configs/rollup.config.mjs",
      "node tools/replaceVersionAndDate.js dist/dexie-observable.js",
      "# eslint ",
      "eslint src --cache"
    ],
    "release": [
      "just-build dexie-observable",
      "# Copy Dexie.Observable.d.ts to dist and replace version in it",
      "node -e \"fs.writeFileSync('dist/dexie-observable.d.ts', fs.readFileSync('src/Dexie.Observable.d.ts'))\"",
      "node tools/replaceVersionAndDate.js dist/dexie-observable.d.ts",
      "# Minify the default ES5 UMD module",
      "cd dist",
      "uglifyjs dexie-observable.js -m -c negate_iife=0 -o dexie-observable.min.js --source-map"
    ],
    "test": [
      "# Build the unit tests (integration tests need no build)",
      "tsc --allowJs --moduleResolution node --lib es2018,dom -t es5 -m es2015 --outDir tools/tmp/es5/test --rootDir ../.. --sourceMap --skipLibCheck test/unit/unit-tests-all.js [--watch 'Compilation complete.']",
      "rollup -c tools/build-configs/rollup.tests.config.mjs"
    ],
    "test-typings": [
      "tsc -p test/typings/"
    ]
  },
  "homepage": "https://dexie.org",
  "peerDependencies": {
    "dexie": "workspace:^"
  },
  "devDependencies": {
    "@types/node": "^18.11.18",
    "dexie": "workspace:^",
    "eslint": "^7.27.0",
    "just-build": "^0.9.24",
    "qunit": "2.10.0",
    "qunitjs": "1.23.1",
    "typescript": "^5.3.3",
    "uglify-js": "^3.5.6",
    "undici-types": "^6.21.0"
  }
}


================================================
FILE: addons/Dexie.Observable/src/.eslintrc.json
================================================
{
  "extends": "eslint:recommended",
  "parserOptions": {
    "ecmaVersion": 2020,
    "sourceType": "module",
    "ecmaFeatures": {
    }
  },
  "rules": {
    "no-undef": ["error"],
    "no-unused-vars": 1,
    "no-console": 0,
    "no-empty": 0
  },
  "globals": {
    "indexedDB": false,
    "IDBKeyRange": false,
    "setTimeout": false,
    "clearTimeout": false,
    "Symbol": false,
    "setImmediate": false,
    "console": false,
    "self": false,
    "window": false,
    "global": false,
    "navigator": false,
    "location": false,
    "chrome": false,
    "document": false,
    "MutationObserver": false,
    "CustomEvent": false,
    "dispatchEvent": false,
    "localStorage": false
  }
}


================================================
FILE: addons/Dexie.Observable/src/Dexie.Observable.d.ts
================================================
// Type definitions for dexie-observable v{version}
// Project: https://github.com/dexie/Dexie.js/tree/master/addons/Dexie.Observable
// Definitions by: David Fahlander <http://github.com/dfahlander>

import Dexie, { DexieEventSet } from 'dexie';
import { IDatabaseChange } from '../api';

export interface SyncNodeConstructor {
    new() : SyncNode;
}

//
// Interfaces of Dexie.Observable
//            


/**
 * A SyncNode represents a local database instance that subscribes
 * to changes made on the database.
 * SyncNodes are stored in the _syncNodes table.
 * 
 * Dexie.Syncable extends this interface and allows 'remote' nodes to be stored
 * as well.
 */
export interface SyncNode {
    id?: number,
    myRevision: number,
    type: 'local' | 'remote',
    lastHeartBeat: number,
    deleteTimeStamp: number, // In case lastHeartBeat is too old, a value of now + HIBERNATE_GRACE_PERIOD will be set here. If reached before node wakes up, node will be deleted.
    isMaster: number // 1 if true. Not using Boolean because it's not possible to index Booleans.
}

export interface ObservableEventSet extends DexieEventSet {
    (eventName: 'latestRevisionIncremented', subscriber: (dbName: string, latestRevision: number) => void): void;
    (eventName: 'suicideNurseCall', subscriber: (dbName: string, nodeID: number) => void): void;
    (eventName: 'intercomm', subscriber: (dbName: string) => void): void;
    (eventName: 'beforeunload', subscriber: () => void): void;
}

// Object received by on('message') after sendMessage() or broadcastMessage()
interface MessageEvent {
    id: number;
    type: string;
    message: any;
    destinationNode: number;
    wantReply?: boolean;
    resolve(result: any): void;
    reject(error: any): void;
}

//
// Extend Dexie interface
//
declare module 'dexie' {
    // Extend methods on db (db.sendMessage(), ...)
    interface Dexie {
        // Placeholder where to access the SyncNode class constructor.
        // (makes it valid to do new db.observable.SyncNode())
        observable: {
            version: string;
            SyncNode: SyncNodeConstructor;
            sendMessage(
                type: string, // Don't use 'response' as it is used internally by the framework
                message: any, // anything that can be saved by IndexedDB
                destinationNode: number,
                options: {
                    wantReply?: boolean;
                }
            ): Promise<any> | void; // When wantReply is undefined or false return is void

            broadcastMessage(
                type: string,
                message: any, // anything that can be saved by IndexedDB
                bIncludeSelf: boolean
            ): void;
        }

        readonly _localSyncNode: SyncNode;

        _changes: Dexie.Table<IDatabaseChange & {rev: number}, number>;
        _syncNodes: Dexie.Table<SyncNode, number>;
        _intercomm: Dexie.Table<any, number>;
    }

    // Extended events db.on('changes', subscriber), ...
    interface DbEvents {
        (eventName: 'changes', subscriber: (changes: IDatabaseChange[], partial: boolean)=>void): void;
        (eventName: 'cleanup', subscriber: ()=>any): void;
        (eventName: 'message', subscriber: (msg: MessageEvent)=>any): void;
    }

    // Extended IndexSpec with uuid boolean for primary key.
    interface IndexSpec {
        uuid: boolean;
    }

    interface DexieConstructor {
        Observable: {
            (db: Dexie) : void;

            version: string;
            createUUID: () => string;
            on: ObservableEventSet;
            localStorageImpl: {
                setItem(key: string, value: string): void,
                getItem(key: string): string,
                removeItem(key: string): void; 
            };
            _onStorage: (event: StorageEvent) => void;
        }

    }
}

export default Dexie.Observable;


================================================
FILE: addons/Dexie.Observable/src/Dexie.Observable.js
================================================
/* ========================================================================== 
 *                           dexie-observable.js
 * ==========================================================================
 *
 * Dexie addon for observing database changes not just on local db instance
 * but also on other instances, tabs and windows.
 *
 * Comprises a base framework for dexie-syncable.js
 *
 * By David Fahlander, david.fahlander@gmail.com,
 *    Nikolas Poniros, https://github.com/nponiros
 *
 * ==========================================================================
 *
 * Version {version}, {date}
 *
 * https://dexie.org
 *
 * Apache License Version 2.0, January 2004, http://www.apache.org/licenses/
 * 
 */
import Dexie from 'dexie';
import { nop, promisableChain, createUUID } from './utils';

import initOverrideCreateTransaction from './override-create-transaction';
import initWakeupObservers from './wakeup-observers';
import initCrudMonitor from './hooks/crud-monitor';
import initOnStorage from './on-storage';
import initOverrideOpen from './override-open';
import initIntercomm from './intercomm';

import overrideParseStoresSpec from './override-parse-stores-spec';

import deleteOldChanges from './delete-old-changes';

var global = self;

/** class DatabaseChange
    *
    *  Object contained by the _changes table.
    */
var DatabaseChange = Dexie.defineClass({
    rev: Number, // Auto-incremented primary key
    source: String, // Optional source creating the change. Set if transaction.source was set when doing the operation.
    table: String, // Table name
    key: Object, // Primary key. Any type.
    type: Number, // 1 = CREATE, 2 = UPDATE, 3 = DELETE
    obj: Object, // CREATE: obj contains the object created.
    mods: Object, // UPDATE: mods contains the modifications made to the object.
    oldObj: Object // DELETE: oldObj contains the object deleted. UPDATE: oldObj contains the old object before updates applied.
});

// Import some usable helper functions
var override = Dexie.override;
var Promise = Dexie.Promise;
var browserIsShuttingDown = false;

/** Dexie addon for change tracking and real-time observation.
 * 
 * @param {Dexie} db 
 */
function Observable(db) {
    if (!/^(3|4)\./.test(Dexie.version))
        throw new Error(`Missing dexie version 3.x or 4.x`);
    if (db.observable) {
        if (db.observable.version !== "{version}") throw new Error(`Mixed versions of dexie-observable`);
        return; // Addon already active.
    }

    var NODE_TIMEOUT = 20000, // 20 seconds before local db instances are timed out. This is so that old changes can be deleted when not needed and to garbage collect old _syncNodes objects.
        HIBERNATE_GRACE_PERIOD = 20000, // 20 seconds
        // LOCAL_POLL: The time to wait before polling local db for changes and cleaning up old nodes. 
        // Polling for changes is a fallback only needed in certain circomstances (when the onstorage event doesnt reach all listeners - when different browser windows doesnt share the same process)
        LOCAL_POLL = 500, // 500 ms. In real-world there will be this value + the time it takes to poll(). A small value is needed in Workers where we cannot rely on storage event.
        HEARTBEAT_INTERVAL = NODE_TIMEOUT - 5000;

    var localStorage = Observable.localStorageImpl;

    /** class SyncNode
        *
        * Object contained in the _syncNodes table.
        */
    var SyncNode = Dexie.defineClass({
        //id: Number,
        myRevision: Number,
        type: String, // "local" or "remote"
        lastHeartBeat: Number,
        deleteTimeStamp: Number, // In case lastHeartBeat is too old, a value of now + HIBERNATE_GRACE_PERIOD will be set here. If reached before node wakes up, node will be deleted.
        url: String, // Only applicable for "remote" nodes. Only used in Dexie.Syncable.
        isMaster: Number, // 1 if true. Not using Boolean because it's not possible to index Booleans in IE implementation of IDB.

        // Below properties should be extended in Dexie.Syncable. Not here. They apply to remote nodes only (type == "remote"):
        syncProtocol: String, // Tells which implementation of ISyncProtocol to use for remote syncing. 
        syncContext: null,
        syncOptions: Object,
        connected: false, // FIXTHIS: Remove! Replace with status.
        status: Number,
        appliedRemoteRevision: null,
        remoteBaseRevisions: [{ local: Number, remote: null }],
        dbUploadState: {
            tablesToUpload: [String],
            currentTable: String,
            currentKey: null,
            localBaseRevision: Number
        }
    });

    db.observable = {version: "{version}"};
    db.observable.SyncNode = SyncNode;

    const wakeupObservers = initWakeupObservers(db, Observable, localStorage);
    const overrideCreateTransaction = initOverrideCreateTransaction(db, wakeupObservers);
    const crudMonitor = initCrudMonitor(db);
    const overrideOpen = initOverrideOpen(db, SyncNode, crudMonitor);

    var mySyncNode = {node: null};

    const intercomm = initIntercomm(db, Observable, SyncNode, mySyncNode, localStorage);
    const onIntercomm = intercomm.onIntercomm;
    const consumeIntercommMessages = intercomm.consumeIntercommMessages;

    // Allow other addons to access the local sync node. May be needed by Dexie.Syncable.
    Object.defineProperty(db, "_localSyncNode", {
        get: function() { return mySyncNode.node; }
    });

    var pollHandle = null,
        heartbeatHandle = null;

    if (Dexie.fake) {
        // This code will never run.
        // It's here just to enable auto-complete in visual studio - helps a lot when writing code.
        db.version(1).stores({
            _syncNodes: "++id,myRevision,lastHeartBeat",
            _changes: "++rev",
            _intercomm: "++id,destinationNode",
            _uncommittedChanges: "++id,node"
        });
        db._syncNodes.mapToClass(SyncNode);
        db._changes.mapToClass(DatabaseChange);
        mySyncNode.node = new SyncNode({
            myRevision: 0,
            type: "local",
            lastHeartBeat: Date.now(),
            deleteTimeStamp: null
        });
    }

    //
    // Override parsing the stores to add "_changes" and "_syncNodes" tables.
    // It also adds UUID support for the primary key and sets tables as observable tables.
    //
    db.Version.prototype._parseStoresSpec = override(db.Version.prototype._parseStoresSpec, overrideParseStoresSpec);

    // changes event on db:
    db.on.addEventType({
        changes: 'asap',
        cleanup: [promisableChain, nop], // fire (nodesTable, changesTable, trans). Hook called when cleaning up nodes. Subscribers may return a Promise to to more stuff. May do additional stuff if local sync node is master.
        message: 'asap'
    });

    //
    // Override transaction creation to always include the "_changes" store when any observable store is involved.
    //
    db._createTransaction = override(db._createTransaction, overrideCreateTransaction);

    // If Observable.latestRevsion[db.name] is undefined, set it to 0 so that comparing against it always works.
    // You might think that it will always be undefined before this call, but in case another Dexie instance in the same
    // window with the same database name has been created already, this static property will already be set correctly.
    Observable.latestRevision[db.name] = Observable.latestRevision[db.name] || 0;

    //
    // Override open to setup hooks for db changes and map the _syncNodes table to class
    //
    db.open = override(db.open, overrideOpen);

    db.close = override(db.close, function(origClose) {
        return function () {
            if (db.dynamicallyOpened()) return origClose.apply(this, arguments); // Don't observe dynamically opened databases.
            // Teardown our framework.
            if (wakeupObservers.timeoutHandle) {
                clearTimeout(wakeupObservers.timeoutHandle);
                delete wakeupObservers.timeoutHandle;
            }
            Observable.on('latestRevisionIncremented').unsubscribe(onLatestRevisionIncremented);
            Observable.on('suicideNurseCall').unsubscribe(onSuicide);
            Observable.on('intercomm').unsubscribe(onIntercomm);
            Observable.on('beforeunload').unsubscribe(onBeforeUnload);
            // Inform other db instances in same window that we are dying:
            if (mySyncNode.node && mySyncNode.node.id) {
                Observable.on.suicideNurseCall.fire(db.name, mySyncNode.node.id);
                // Inform other windows as well:
                if (localStorage) {
                    localStorage.setItem('Dexie.Observable/deadnode:' + mySyncNode.node.id.toString() + '/' + db.name, "dead"); // In IE, this will also wakeup our own window. cleanup() may trigger twice per other db instance. But that doesnt to anything.
                }
                mySyncNode.node.deleteTimeStamp = 1; // One millisecond after 1970. Makes it occur in the past but still keeps it truthy.
                mySyncNode.node.lastHeartBeat = 0;
                db._syncNodes.put(mySyncNode.node); // This async operation may be cancelled since the browser is closing down now.
                mySyncNode.node = null;
            }

            if (pollHandle) clearTimeout(pollHandle);
            pollHandle = null;
            if (heartbeatHandle) clearTimeout(heartbeatHandle);
            heartbeatHandle = null;
            return origClose.apply(this, arguments);
        };
    });

    // Override Dexie.delete() in order to delete Observable.latestRevision[db.name].
    db.delete = override(db.delete, function(origDelete) {
        return function() {
            return origDelete.apply(this, arguments).then(function(result) {
                // Reset Observable.latestRevision[db.name]
                Observable.latestRevision[db.name] = 0;
                return result;
            });
        };
    });

    // When db opens, make sure to start monitor any changes before other db operations will start.
    db.on("ready", function startObserving() {
        if (db.dynamicallyOpened()) return db; // Don't observe dynamically opened databases.
        
        return db.table("_changes").orderBy("rev").last(function(lastChange) {
            // Since startObserving() is called before database open() method, this will be the first database operation enqueued to db.
            // Therefore we know that the retrieved value will be This query will
            var latestRevision = (lastChange ? lastChange.rev : 0);
            mySyncNode.node = new SyncNode({
                myRevision: latestRevision,
                type: "local",
                lastHeartBeat: Date.now(),
                deleteTimeStamp: null,
                isMaster: 0
            });
            if (Observable.latestRevision[db.name] < latestRevision) {
                // Side track . For correctness whenever setting Observable.latestRevision[db.name] we must make sure the event is fired if increased:
                // There are other db instances in same window that hasnt yet been informed about a new revision
                Observable.latestRevision[db.name] = latestRevision;
                Dexie.ignoreTransaction(function() {
                    Observable.on.latestRevisionIncremented.fire(latestRevision);
                });
            }
            // Add new sync node or if this is a reopening of the database after a close() call, update it.
            return db._syncNodes.put(mySyncNode.node).then(Dexie.ignoreTransaction(() => {
                // By default, this node will become master unless we discover an existing, up-to-date master
                var mySyncNodeShouldBecomeMaster = 1;
                return db._syncNodes.orderBy('isMaster').reverse().modify(existingNode => {
                    if (existingNode.isMaster) {
                        if (existingNode.lastHeartBeat < Date.now() - NODE_TIMEOUT) {
                            // Existing master record is out-of-date; demote it
                            existingNode.isMaster = 0;
                        } else {
                            // An existing up-to-date master record exists, so it will remain master
                            mySyncNodeShouldBecomeMaster = 0;
                        }
                    }

                    // The local node reference may be unassigned at any point by a database close() operation
                    if (!mySyncNode.node) return;

                    // Assign the local node state
                    // This is guaranteed to apply *after* any existing master records have been inspected, due to the orderBy clause
                    if (existingNode.id === mySyncNode.node.id) {
                        existingNode.isMaster = mySyncNode.node.isMaster = mySyncNodeShouldBecomeMaster;
                    }
                });
            })).then(() => {
                Observable.on('latestRevisionIncremented', onLatestRevisionIncremented); // Wakeup when a new revision is available.
                Observable.on('beforeunload', onBeforeUnload);
                Observable.on('suicideNurseCall', onSuicide);
                Observable.on('intercomm', onIntercomm);
                // Start polling for changes and do cleanups:
                pollHandle = setTimeout(poll, LOCAL_POLL);
                // Start heartbeat
                heartbeatHandle = setTimeout(heartbeat, HEARTBEAT_INTERVAL);
            }).then(function () {
                cleanup();
            });
        });
    }, true); // True means the on(ready) event will survive a db reopening (db.close() / db.open()).

    var handledRevision = 0;

    function onLatestRevisionIncremented(dbname, latestRevision) {
        if (dbname === db.name) {
            if (handledRevision >= latestRevision) return; // Make sure to only run once per revision. (Workaround for IE triggering storage event on same window)
            handledRevision = latestRevision;
            Dexie.vip(function() {
                readChanges(latestRevision).catch('DatabaseClosedError', ()=>{
                    // Handle database closed error gracefully while reading changes.
                    // Don't trigger 'unhandledrejection'.
                    // Even though we intercept the close() method, it might be called when in the middle of
                    // reading changes and then that flow will cancel with DatabaseClosedError.
                });
            });
        }
    }

    function readChanges(latestRevision, recursion, wasPartial) {
        // Whenever changes are read, fire db.on("changes") with the array of changes. Eventually, limit the array to 1000 entries or so (an entire database is
        // downloaded from server AFTER we are initiated. For example, if first sync call fails, then after a while we get reconnected. However, that scenario
        // should be handled in case database is totally empty we should fail if sync is not available)
        if (!recursion && readChanges.ongoingOperation) {
            // We are already reading changes. Prohibit a parallell execution of this which would lead to duplicate trigging of 'changes' event.
            // Instead, the callback in toArray() will always check Observable.latestRevision[db.name] to see if it has changed and if so, re-launch readChanges().
            // The caller should get the Promise instance from the ongoing operation so that the then() method will resolve when operation is finished.
            return readChanges.ongoingOperation;
        }

        var partial = false;
        var ourSyncNode = mySyncNode.node; // Because mySyncNode can suddenly be set to null on database close, and worse, can be set to a new value if database is reopened.
        if (!ourSyncNode) {
            return Promise.reject(new Dexie.DatabaseClosedError());
        }
        var LIMIT = 1000;
        var promise = db._changes.where("rev").above(ourSyncNode.myRevision).limit(LIMIT).toArray(function (changes) {
            if (changes.length > 0) {
                var lastChange = changes[changes.length - 1];
                partial = (changes.length === LIMIT);
                db.on('changes').fire(changes, partial);
                ourSyncNode.myRevision = lastChange.rev;
            } else if (wasPartial) {
                // No more changes, BUT since we have triggered on('changes') with partial = true,
                // we HAVE TO trigger changes again with empty list and partial = false
                db.on('changes').fire([], false);
            }

            let ourNodeStillExists = false;
            return db._syncNodes.where(':id').equals(ourSyncNode.id).modify(syncNode => {
                ourNodeStillExists = true;
                syncNode.lastHeartBeat = Date.now(); // Update heart beat (not nescessary, but why not!)
                syncNode.deleteTimeStamp = null; // Reset "deleteTimeStamp" flag if it was there.
                syncNode.myRevision = Math.max(syncNode.myRevision, ourSyncNode.myRevision);
            }).then(()=>ourNodeStillExists);
        }).then(ourNodeStillExists =>{
            if (!ourNodeStillExists) {
                // My node has been deleted. We must have been lazy and got removed by another node.
                if (browserIsShuttingDown) {
                    throw new Error("Browser is shutting down");
                } else {
                    db.close();
                    console.error("Out of sync"); // TODO: What to do? Reload the page?
                    if (global.location) global.location.reload(true);
                    throw new Error("Out of sync"); // Will make current promise reject
                }
            }

            // Check if more changes have come since we started reading changes in the first place. If so, relaunch readChanges and let the ongoing promise not
            // resolve until all changes have been read.
            if (partial || Observable.latestRevision[db.name] > ourSyncNode.myRevision) {
                // Either there were more than 1000 changes or additional changes where added while we were reading these changes,
                // In either case, call readChanges() again until we're done.
                return readChanges(Observable.latestRevision[db.name], (recursion || 0) + 1, partial);
            }

        }).finally(function() {
            delete readChanges.ongoingOperation;
        });

        if (!recursion) {
            readChanges.ongoingOperation = promise;
        }
        return promise;
    }

    /**
     * The reason we need heartbeat in parallell with poll() is due to the risk of long-running
     * transactions while syncing changes from server to client in Dexie.Syncable. That transaction will
     * include _changes (which will block readChanges()) but not _syncNodes. So this heartbeat will go on
     * during that changes are being applied and update our lastHeartBeat property while poll() is waiting.
     * When cleanup() (who also is blocked by the sync) wakes up, it won't kill the master node because this
     * heartbeat job will have updated the master node's heartbeat during the long-running sync transaction.
     * 
     * If we did not have this heartbeat, and a server send lots of changes that took more than NODE_TIMEOUT
     * (20 seconds), another node waking up after the sync would kill the master node and take over because
     * it would believe it was dead.
     */
    function heartbeat() {
        heartbeatHandle = null;
        var currentInstance = mySyncNode.node && mySyncNode.node.id;
        if (!currentInstance) return;
        db.transaction('rw!', db._syncNodes, ()=>{
            db._syncNodes.where({id: currentInstance}).first(ourSyncNode => {
                if (!ourSyncNode) {
                    // We do not exist anymore. Call db.close() to teardown polls etc.
                    if (db.isOpen()) db.close();
                    return;
                }
                ourSyncNode.lastHeartBeat = Date.now();
                ourSyncNode.deleteTimeStamp = null; // Reset "deleteTimeStamp" flag if it was there.
                return db._syncNodes.put(ourSyncNode);
            });
        }).catch('DatabaseClosedError', () => {
            // Ignore silently
        }).finally(() => {
            if (mySyncNode.node && mySyncNode.node.id === currentInstance && db.isOpen()) {
                heartbeatHandle = setTimeout(heartbeat, HEARTBEAT_INTERVAL);
            }
        });
    }

    function poll() {
        pollHandle = null;
        var currentInstance = mySyncNode.node && mySyncNode.node.id;
        if (!currentInstance) return;
        Dexie.vip(function() { // VIP ourselves. Otherwise we might not be able to consume intercomm messages from master node before database has finished opening. This would make DB stall forever. Cannot rely on storage-event since it may not always work in some browsers of different processes.
            readChanges(Observable.latestRevision[db.name]).then(cleanup).then(consumeIntercommMessages)
            .catch('DatabaseClosedError', ()=>{
                // Handle database closed error gracefully while reading changes.
                // Don't trigger 'unhandledrejection'.
                // Even though we intercept the close() method, it might be called when in the middle of
                // reading changes and then that flow will cancel with DatabaseClosedError.
            })
            .finally(function() {
                // Poll again in given interval:
                if (mySyncNode.node && mySyncNode.node.id === currentInstance && db.isOpen()) {
                    pollHandle = setTimeout(poll, LOCAL_POLL);
                }
            });
        });
    }

    
    function cleanup() {
        var ourSyncNode = mySyncNode.node;
        if (!ourSyncNode) return Promise.reject(new Dexie.DatabaseClosedError());
        return db.transaction('rw', '_syncNodes', '_changes', '_intercomm', function() {
            // Cleanup dead local nodes that has no heartbeat for over a minute
            // Dont do the following:
            //nodes.where("lastHeartBeat").below(Date.now() - NODE_TIMEOUT).and(function (node) { return node.type == "local"; }).delete();
            // Because client may have been in hybernate mode and recently woken up. That would lead to deletion of all nodes.
            // Instead, we should mark any old nodes for deletion in a minute or so. If they still dont wakeup after that minute we could consider them dead.
            var weBecameMaster = false;
            db._syncNodes.where("lastHeartBeat").below(Date.now() - NODE_TIMEOUT).filter(node => node.type === 'local').modify(function(node) {
                if (node.deleteTimeStamp && node.deleteTimeStamp < Date.now()) {
                    // Delete the node.
                    delete this.value;
                    // Cleanup localStorage "deadnode:" entry for this node (localStorage API was used to wakeup other windows (onstorage event) - an event type missing in indexedDB.)
                    if (localStorage) {
                        localStorage.removeItem('Dexie.Observable/deadnode:' + node.id + '/' + db.name);
                    }
                    // Check if we are deleting a master node
                    if (node.isMaster) {
                        // The node we are deleting is master. We must take over that role.
                        // OK to call nodes.update(). No need to call Dexie.vip() because nodes is opened in existing transaction!
                        db._syncNodes.update(ourSyncNode, { isMaster: 1 });
                        weBecameMaster = true;
                    }
                    // Cleanup intercomm messages destinated to the node being deleted.
                    // Those that waits for reply should be redirected to us.
                    db._intercomm.where({destinationNode: node.id}).modify(function(msg) {
                        if (msg.wantReply)
                            msg.destinationNode = ourSyncNode.id;
                        else
                            // Delete the message from DB and if someone is waiting for reply, let ourselved answer the request.
                            delete this.value;
                    });
                } else if (!node.deleteTimeStamp) {
                    // Mark the node for deletion
                    node.deleteTimeStamp = Date.now() + HIBERNATE_GRACE_PERIOD;
                }
            }).then(function() {
                // Cleanup old revisions that no node is interested of.
                Observable.deleteOldChanges(db);
                return db.on("cleanup").fire(weBecameMaster);
            });
        });
    }

    function onBeforeUnload() {
        // Mark our own sync node for deletion.
        if (!mySyncNode.node) return;
        browserIsShuttingDown = true;
        mySyncNode.node.deleteTimeStamp = 1; // One millisecond after 1970. Makes it occur in the past but still keeps it truthy.
        mySyncNode.node.lastHeartBeat = 0;
        db._syncNodes.put(mySyncNode.node); // This async operation may be cancelled since the browser is closing down now.
        Observable.wereTheOneDying = true; // If other nodes in same window wakes up by this call, make sure they dont start taking over mastership and stuff...
        // Inform other windows that we're gone, so that they may take over our role if needed. Setting localStorage item below will trigger Observable.onStorage, which will trigger onSuicie() below:
        if (localStorage) {
            localStorage.setItem('Dexie.Observable/deadnode:' + mySyncNode.node.id.toString() + '/' + db.name, "dead"); // In IE, this will also wakeup our own window. However, that is doublechecked in nursecall subscriber below.
        }
    }

    function onSuicide(dbname, nodeID) {
        if (dbname === db.name && !Observable.wereTheOneDying) {
            // Make sure it's dead indeed. Second bullet. Why? Because it has marked itself for deletion in the onbeforeunload event, which is fired just before window dies.
            // It's own call to put() may have been cancelled.
            // Note also that in IE, this event may be called twice, but that doesnt harm!
            Dexie.vip(function() {
                db._syncNodes.update(nodeID, { deleteTimeStamp: 1, lastHeartBeat: 0 }).then(cleanup);
            });
        }
    }

}

//
// Static properties and methods
// 

Observable.version = "{version}";
Observable.latestRevision = {}; // Latest revision PER DATABASE. Example: Observable.latestRevision.FriendsDB = 37;
Observable.on = Dexie.Events(null, "latestRevisionIncremented", "suicideNurseCall", "intercomm", "beforeunload"); // fire(dbname, value);
Observable.createUUID = createUUID;

Observable.deleteOldChanges = deleteOldChanges;

Observable._onStorage = initOnStorage(Observable);

Observable._onBeforeUnload = function() {
    Observable.on.beforeunload.fire();
};

try {
    Observable.localStorageImpl = global.localStorage;
} catch (ex){}

//
// Map window events to static events in Dexie.Observable:
//
if (global?.addEventListener) {
    global.addEventListener("storage", Observable._onStorage);
    global.addEventListener("beforeunload", Observable._onBeforeUnload);
}

if (Dexie.Observable) {
    if (Dexie.Observable.version !== "{version}") {
        throw new Error (`Mixed versions of dexie-observable`);
    }
} else {
    // Register addon:
    Dexie.Observable = Observable;
    Dexie.addons.push(Observable);
}

export default Dexie.Observable;


================================================
FILE: addons/Dexie.Observable/src/change_types.js
================================================
// Change Types
export const CREATE = 1;
export const UPDATE = 2;
export const DELETE = 3;


================================================
FILE: addons/Dexie.Observable/src/delete-old-changes.js
================================================
import Dexie from 'dexie';

export default function deleteOldChanges(db) {
  // This is a background job and should never be done within
  // a caller's transaction. Use Dexie.ignoreTransaction() to ensure that.
  // We should not return the Promise but catch it ourselves instead.

  // To prohibit starving the database we want to lock transactions as short as possible
  // and since we're not in a hurry, we could do this job in chunks and reschedule a
  // continuation every 500 ms.
  const CHUNK_SIZE = 100;

  Dexie.ignoreTransaction(()=>{
    return db._syncNodes.orderBy("myRevision").first(oldestNode => {
      return db._changes
          .where("rev").below(oldestNode.myRevision)
          .limit(CHUNK_SIZE)
          .primaryKeys();
    }).then(keysToDelete => {
      if (keysToDelete.length === 0) return; // Done.
      return db._changes.bulkDelete(keysToDelete).then(()=> {
        // If not done garbage collecting, reschedule a continuation of it until done.
        if (keysToDelete.length === CHUNK_SIZE) {
          // Limit reached. Changes are there are more job to do. Schedule again:
          setTimeout(() => db.isOpen() && deleteOldChanges(db), 500);
        }
      });
    });
  }).catch(()=>{
    // The operation is not crucial. A failure could almost only be due to that database has been closed.
    // No need to log this.
  });
}


================================================
FILE: addons/Dexie.Observable/src/hooks/creating.js
================================================
import Dexie from 'dexie';

import {CREATE} from '../change_types';

export default function initCreatingHook(db, table) {
  return function creatingHook(primKey, obj, trans) {
    /// <param name="trans" type="db.Transaction"></param>
    var rv = undefined;
    if (primKey === undefined && table.schema.primKey.uuid) {
      primKey = rv = Dexie.Observable.createUUID();
      if (table.schema.primKey.keyPath) {
        Dexie.setByKeyPath(obj, table.schema.primKey.keyPath, primKey);
      }
    }

    var change = {
      source: trans.source || null, // If a "source" is marked on the transaction, store it. Useful for observers that want to ignore their own changes.
      table: table.name,
      key: primKey === undefined ? null : primKey,
      type: CREATE,
      obj: obj
    };

    var promise = db._changes.add(change).then(function (rev) {
      trans._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rev);
      return rev;
    });

    // Wait for onsuccess so that we have the primKey if it is auto-incremented and update the change item if so.
    this.onsuccess = function (resultKey) {
      if (primKey != resultKey)
        promise._then(function () {
          change.key = resultKey;
          db._changes.put(change);
        });
    };

    this.onerror = function () {
      // If the main operation fails, make sure to regret the change
      promise._then(function (rev) {
        // Will only happen if app code catches the main operation error to prohibit transaction from aborting.
        db._changes.delete(rev);
      });
    };

    return rv;
  };
}


================================================
FILE: addons/Dexie.Observable/src/hooks/crud-monitor.js
================================================
import initCreatingHook from './creating';
import initUpdatingHook from './updating';
import initDeletingHook from './deleting';

export default function initCrudMonitor(db) {
//
// The Creating/Updating/Deleting hook will make sure any change is stored to the changes table
//
  return function crudMonitor(table) {
    /// <param name="table" type="db.Table"></param>
    if (table.hook._observing) return;
    table.hook._observing = true;

    const tableName = table.name;
    table.hook('creating').subscribe(initCreatingHook(db, table));

    table.hook('updating').subscribe(initUpdatingHook(db, tableName));

    table.hook('deleting').subscribe(initDeletingHook(db, tableName));
  };
}


================================================
FILE: addons/Dexie.Observable/src/hooks/deleting.js
================================================
import {DELETE} from '../change_types';

export default function initDeletingHook(db, tableName) {
  return function deletingHook(primKey, obj, trans) {
    /// <param name="trans" type="db.Transaction"></param>
    var promise = db._changes.add({
      source: trans.source || null, // If a "source" is marked on the transaction, store it. Useful for observers that want to ignore their own changes.
      table: tableName,
      key: primKey,
      type: DELETE,
      oldObj: obj
    }).then(function (rev) {
      trans._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rev);
      return rev;
    })
        .catch((e) => {
          console.log(obj)
          console.log(e.stack)
        })
    this.onerror = function () {
      // If the main operation fails, make sure to regret the change.
      // Using _then because if promise is already fullfilled, the standard then() would
      // do setTimeout() and we would loose the transaction.
      promise._then(function (rev) {
        // Will only happen if app code catches the main operation error to prohibit transaction from aborting.
        db._changes.delete(rev);
      });
    };
  };
}


================================================
FILE: addons/Dexie.Observable/src/hooks/updating.js
================================================
import Dexie from 'dexie';

import {UPDATE} from '../change_types';

export default function initUpdatingHook(db, tableName) {
  return function updatingHook(mods, primKey, oldObj, trans) {
    /// <param name="trans" type="db.Transaction"></param>
    // mods may contain property paths with undefined as value if the property
    // is being deleted. Since we cannot persist undefined we need to act
    // like those changes is setting the value to null instead.
    var modsWithoutUndefined = {};
    // As of current Dexie version (1.0.3) hook may be called even if it wouldn't really change.
    // Therefore we may do that kind of optimization here - to not add change entries if
    // there's nothing to change.
    var anythingChanged = false;
    var newObj = Dexie.deepClone(oldObj);
    for (var propPath in mods) {
      var mod = mods[propPath];
      if (typeof mod === 'undefined') {
        Dexie.delByKeyPath(newObj, propPath);
        modsWithoutUndefined[propPath] = null; // Null is as close we could come to deleting a property when not allowing undefined.
        anythingChanged = true;
      } else {
        var currentValue = Dexie.getByKeyPath(oldObj, propPath);
        if (mod !== currentValue && JSON.stringify(mod) !== JSON.stringify(currentValue)) {
          Dexie.setByKeyPath(newObj, propPath, mod);
          modsWithoutUndefined[propPath] = mod;
          anythingChanged = true;
        }
      }
    }
    if (anythingChanged) {
      var change = {
        source: trans.source || null, // If a "source" is marked on the transaction, store it. Useful for observers that want to ignore their own changes.
        table: tableName,
        key: primKey,
        type: UPDATE,
        mods: modsWithoutUndefined,
        oldObj: oldObj,
        obj: newObj
      };
      var promise = db._changes.add(change); // Just so we get the correct revision order of the update...
      this.onsuccess = function () {
        promise._then(function (rev) {
          trans._lastWrittenRevision = Math.max(trans._lastWrittenRevision, rev);
        });
      };
      this.onerror = function () {
        // If the main operation fails, make sure to regret the change.
        promise._then(function (rev) {
          // Will only happen if app code catches the main operation error to prohibit transaction from aborting.
          db._changes.delete(rev);
        });
      };
    }
  };
}


================================================
FILE: addons/Dexie.Observable/src/intercomm.js
================================================
import Dexie from 'dexie';

const Promise = Dexie.Promise;

export default function initIntercomm(db, Observable, SyncNode, mySyncNode, localStorage) {
//
// Intercommunication between nodes
//
// Enable inter-process communication between browser windows using localStorage storage event (is registered in Dexie.Observable)

  var requestsWaitingForReply = {};

  /**
   * @param {string} type Type of message
   * @param message Message to send
   * @param {number} destinationNode ID of destination node
   * @param {{wantReply: boolean, isFailure: boolean, requestId: number}} options If {wantReply: true}, the returned promise will complete with the reply from remote. Otherwise it will complete when message has been successfully sent.</param>
   */
  db.observable.sendMessage = function (type, message, destinationNode, options) {
    /// <param name="type" type="String">Type of message</param>
    /// <param name="message">Message to send</param>
    /// <param name="destinationNode" type="Number">ID of destination node</param>
    /// <param name="options" type="Object" optional="true">{wantReply: Boolean, isFailure: Boolean, requestId: Number}. If wantReply, the returned promise will complete with the reply from remote. Otherwise it will complete when message has been successfully sent.</param>
    options = options || {};
    if (!mySyncNode.node)
      return options.wantReply ?
          Promise.reject(new Dexie.DatabaseClosedError()) :
          Promise.resolve(); // If caller doesn't want a reply, it won't catch errors either.

    var msg = {message: message, destinationNode: destinationNode, sender: mySyncNode.node.id, type: type};
    Dexie.extend(msg, options); // wantReply: wantReply, success: !isFailure, requestId: ...
    return Dexie.ignoreTransaction(()=> {
      var tables = ["_intercomm"];
      if (options.wantReply) tables.push("_syncNodes"); // If caller wants a reply, include "_syncNodes" in transaction to check that there's a receiver there. Otherwise, new master will get it.
      var promise = db.transaction('rw', tables, () => {
        if (options.wantReply) {
          // Check that there is a receiver there to take the request.
          return db._syncNodes.where('id').equals(destinationNode).count(receiverAlive => {
            if (receiverAlive)
              return db._intercomm.add(msg);
            else // If we couldn't find a node -> send to master
              return db._syncNodes.where('isMaster').above(0).first(function (masterNode) {
                msg.destinationNode = masterNode.id;
                return db._intercomm.add(msg)
              });
          });
        } else {
          // If caller doesn't need a response, we don't have to make sure that it gets one.
          return db._intercomm.add(msg);
        }
      }).then(messageId => {
        var rv = null;
        if (options.wantReply) {
          rv = new Promise(function (resolve, reject) {
            requestsWaitingForReply[messageId.toString()] = {resolve: resolve, reject: reject};
          });
        }
        if (localStorage) {
          localStorage.setItem("Dexie.Observable/intercomm/" + db.name, messageId.toString());
        }
        Observable.on.intercomm.fire(db.name);
        return rv;
      });

      if (!options.wantReply) {
        promise.catch(()=> {
        });
        return;
      } else {
        // Forward rejection to caller if it waits for reply.
        return promise;
      }
    });
  };

  // Send a message to all local _syncNodes
  db.observable.broadcastMessage = function (type, message, bIncludeSelf) {
    if (!mySyncNode.node) return;
    var mySyncNodeId = mySyncNode.node.id;
    Dexie.ignoreTransaction(()=> {
      db._syncNodes.toArray(nodes => {
        return Promise.all(nodes
            .filter(node => node.type === 'local' && (bIncludeSelf || node.id !== mySyncNodeId))
            .map(node => db.observable.sendMessage(type, message, node.id)));
      }).catch(()=> {
      });
    });
  };

  function consumeIntercommMessages() {
    // Check if we got messages:
    if (!mySyncNode.node) return Promise.reject(new Dexie.DatabaseClosedError());

    return Dexie.ignoreTransaction(()=> {
      return db.transaction('rw', '_intercomm', function() {
        return db._intercomm.where({destinationNode: mySyncNode.node.id}).toArray(messages => {
          messages.forEach(msg => consumeMessage(msg));
          return db._intercomm.where('id').anyOf(messages.map(msg => msg.id)).delete();
        });
      });
    });
  }

  function consumeMessage(msg) {
    if (msg.type === 'response') {
      // This is a response. Lookup pending request and fulfill its promise.
      var request = requestsWaitingForReply[msg.requestId.toString()];
      if (request) {
        if (msg.isFailure) {
          request.reject(msg.message.error);
        } else {
          request.resolve(msg.message.result);
        }
        delete requestsWaitingForReply[msg.requestId.toString()];
      }
    } else {
      // This is a message or request. Fire the event and add an API for the subscriber to use if reply is requested
      msg.resolve = function (result) {
        db.observable.sendMessage('response', {result: result}, msg.sender, {requestId: msg.id});
      };
      msg.reject = function (error) {
        db.observable.sendMessage('response', {error: error.toString()}, msg.sender, {isFailure: true, requestId: msg.id});
      };
      db.on.message.fire(msg);
    }
  }

  // Listener for 'intercomm' events
  // Gets fired when we get a 'storage' event from local storage or when sendMessage is called
  // 'storage' is used to communicate between tabs (sendMessage changes the localStorage to trigger the event)
  // sendMessage is used to communicate in the same tab and to trigger a storage event
  function onIntercomm(dbname) {
    // When storage event trigger us to check
    if (dbname === db.name) {
      consumeIntercommMessages().catch('DatabaseClosedError', ()=> {});
    }
  }

  return {
    onIntercomm,
    consumeIntercommMessages
  };
}


================================================
FILE: addons/Dexie.Observable/src/on-storage.js
================================================
import Dexie from 'dexie';

export default function initOnStorage(Observable) {
  return function onStorage(event) {
    // We use the onstorage event to trigger onLatestRevisionIncremented since we will wake up when other windows modify the DB as well!
    if (event.key && event.key.indexOf("Dexie.Observable/") === 0) { // For example "Dexie.Observable/latestRevision/FriendsDB"
      var parts = event.key.split('/');
      var prop = parts[1];
      var dbname = parts[2];
      if (prop === 'latestRevision') {
        var rev = parseInt(event.newValue, 10);
        if (!isNaN(rev) && rev > Observable.latestRevision[dbname]) {
          Observable.latestRevision[dbname] = rev;
          Dexie.ignoreTransaction(function () {
            Observable.on('latestRevisionIncremented').fire(dbname, rev);
          });
        }
      } else if (prop.indexOf("deadnode:") === 0) {
        var nodeID = parseInt(prop.split(':')[1], 10);
        if (event.newValue) {
          Observable.on.suicideNurseCall.fire(dbname, nodeID);
        }
      } else if (prop === 'intercomm') {
        if (event.newValue) {
          Observable.on.intercomm.fire(dbname);
        }
      }
    }
  };
}


================================================
FILE: addons/Dexie.Observable/src/override-create-transaction.js
================================================
export default function initOverrideCreateTransaction(db, wakeupObservers) {
  return function overrideCreateTransaction(origFunc) {
    return function (mode, storenames, dbschema, parent) {
      if (db.dynamicallyOpened()) return origFunc.apply(this, arguments); // Don't observe dynamically opened databases.
      var addChanges = false;
      if (mode === 'readwrite' && storenames.some(function (storeName) {
            return dbschema[storeName] && dbschema[storeName].observable;
          })) {
        // At least one included store is a observable store. Make sure to also include the _changes store.
        addChanges = true;
        storenames = storenames.slice(0); // Clone
        if (storenames.indexOf("_changes") === -1)
          storenames.push("_changes"); // Otherwise, firefox will hang... (I've reported the bug to Mozilla@Bugzilla)
      }
      // Call original db._createTransaction()
      var trans = origFunc.call(this, mode, storenames, dbschema, parent);
      // If this transaction is bound to any observable table, make sure to add changes when transaction completes.
      if (addChanges) {
        trans._lastWrittenRevision = 0;
        trans.on('complete', function () {
          if (trans._lastWrittenRevision) {
            // Changes were written in this transaction.
            if (!parent) {
              // This is root-level transaction, i.e. a physical commit has happened.
              // Delay-trigger a wakeup call:
              if (wakeupObservers.timeoutHandle) clearTimeout(wakeupObservers.timeoutHandle);
              wakeupObservers.timeoutHandle = setTimeout(function () {
                delete wakeupObservers.timeoutHandle;
                wakeupObservers(trans._lastWrittenRevision);
              }, 25);
            } else {
              // This is just a virtual commit of a sub transaction.
              // Wait with waking up observers until root transaction has committed.
              // Make sure to mark root transaction so that it will wakeup observers upon commit.
              var rootTransaction = (function findRootTransaction(trans) {
                return trans.parent ? findRootTransaction(trans.parent) : trans;
              })(parent);
              rootTransaction._lastWrittenRevision = Math.max(
                  trans._lastWrittenRevision,
                  rootTransaction.lastWrittenRevision || 0);
            }
          }
        });
        // Derive "source" property from parent transaction by default
        if (trans.parent && trans.parent.source) trans.source = trans.parent.source;
      }
      return trans;
    };
  };
}


================================================
FILE: addons/Dexie.Observable/src/override-open.js
================================================
export default function initOverrideOpen(db, SyncNode, crudMonitor) {
  return function overrideOpen(origOpen) {
    return function () {
      //
      // Make sure to subscribe to "creating", "updating" and "deleting" hooks for all observable tables that were created in the stores() method.
      //
      Object.keys(db._allTables).forEach(tableName => {
        let table = db._allTables[tableName];
        if (table.schema.observable) {
          crudMonitor(table);
        }
        if (table.name === "_syncNodes") {
          table.mapToClass(SyncNode);
        }
      });
      return origOpen.apply(this, arguments);
    }
  };
}


================================================
FILE: addons/Dexie.Observable/src/override-parse-stores-spec.js
================================================
export default function overrideParseStoresSpec(origFunc) {
  return function(stores, dbSchema) {
    // Create the _changes and _syncNodes tables
    stores["_changes"] = "++rev";
    stores["_syncNodes"] = "++id,myRevision,lastHeartBeat,&url,isMaster,type,status";
    stores["_intercomm"] = "++id,destinationNode";
    stores["_uncommittedChanges"] = "++id,node"; // For remote syncing when server returns a partial result.
    // Call default implementation. Will populate the dbSchema structures.
    origFunc.call(this, stores, dbSchema);
    // Allow UUID primary keys using $$ prefix on primary key or indexes
    Object.keys(dbSchema).forEach(function(tableName) {
      var schema = dbSchema[tableName];
      if (schema.primKey.name.indexOf('$$') === 0) {
        schema.primKey.uuid = true;
        schema.primKey.name = schema.primKey.name.substr(2);
        schema.primKey.keyPath = schema.primKey.keyPath.substr(2);
      }
    });
    // Now mark all observable tables
    Object.keys(dbSchema).forEach(function(tableName) {
      // Marked observable tables with "observable" in their TableSchema.
      if (tableName.indexOf('_') !== 0 && tableName.indexOf('$') !== 0) {
        dbSchema[tableName].observable = true;
      }
    });
  };
}


================================================
FILE: addons/Dexie.Observable/src/utils.js
================================================
export function nop() {}

export function promisableChain(f1, f2) {
  if (f1 === nop) return f2;
  return function() {
    var res = f1.apply(this, arguments);
    if (res && typeof res.then === 'function') {
      var thiz = this, args = arguments;
      return res.then(function() {
        return f2.apply(thiz, args);
      });
    }
    return f2.apply(this, arguments);
  };
}

export function createUUID() {
  // Decent solution from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
  var d = Date.now();
  var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = (d + Math.random() * 16) % 16 | 0;
    d = Math.floor(d / 16);
    return (c === 'x' ? r : (r & 0x7 | 0x8)).toString(16);
  });
  return uuid;
}


================================================
FILE: addons/Dexie.Observable/src/wakeup-observers.js
================================================
import Dexie from 'dexie';

export default function initWakeupObservers(db, Observable, localStorage) {
  return function wakeupObservers(lastWrittenRevision) {
    // Make sure Observable.latestRevision[db.name] is still below our value, now when some time has elapsed and other db instances in same window possibly could have made changes too.
    if (Observable.latestRevision[db.name] < lastWrittenRevision) {
      // Set the static property lastRevision[db.name] to the revision of the last written change.
      Observable.latestRevision[db.name] = lastWrittenRevision;
      // Wakeup ourselves, and any other db instances on this window:
      Dexie.ignoreTransaction(function () {
        Observable.on('latestRevisionIncremented').fire(db.name, lastWrittenRevision);
      });
      // Observable.on.latestRevisionIncremented will only wakeup db's in current window.
      // We need a storage event to wakeup other windwos.
      // Since indexedDB lacks storage events, let's use the storage event from WebStorage just for
      // the purpose to wakeup db instances in other windows.
      if (localStorage) localStorage.setItem('Dexie.Observable/latestRevision/' + db.name, lastWrittenRevision); // In IE, this will also wakeup our own window. However, onLatestRevisionIncremented will work around this by only running once per revision id.
    }
  };
}


================================================
FILE: addons/Dexie.Observable/test/gh-actions.sh
================================================
#!/bin/bash -e
echo "Installing dependencies for dexie-observable"
pnpm install >/dev/null
pnpm run build
pnpm run test:typings
pnpm run test:ltcloud
pnpm run test:ltcloud:integration


================================================
FILE: addons/Dexie.Observable/test/integration/karma-env.js
================================================
// workerImports will be used by tests-open.js in the dexie test suite when
// launching a Worker. This line will instruct the worker to import dexie-observable.
window.workerImports.push("../addons/Dexie.Observable/dist/dexie-observable.js");


================================================
FILE: addons/Dexie.Observable/test/integration/karma.conf.js
================================================
// Include common configuration
const {karmaCommon, getKarmaConfig, defaultBrowserMatrix} = require('../../../../test/karma.common');

module.exports = function (config) {
  const browserMatrixOverrides = {
    // Be fine with testing on local travis firefox + browserstack chrome, latest supported.
    ci: ["remote_chrome"],
    // Safari fails to reply on browserstack. Need to not have it here.
    // Just complement with old chrome browser that is not part of CI test suite.
    pre_npm_publish: [
      "Chrome",
    ]
  };

  const cfg = getKarmaConfig(browserMatrixOverrides, {
    // Base path should point at the root 
    basePath: '../../../../',
    // The files needed to apply dexie-observable to the standard dexie unit tests.
    files: karmaCommon.files.concat([
      'dist/dexie.js',
      'addons/Dexie.Observable/test/integration/karma-env.js',
      'addons/Dexie.Observable/dist/dexie-observable.js', // Apply observable addon
      'test/bundle.js', // The dexie standard test suite
      { pattern: 'addons/Dexie.Observable/dist/*.map', watched: false, included: false }
    ])
  });

  config.set(cfg);
}


================================================
FILE: addons/Dexie.Observable/test/integration/test-observable-dexie-tests.html
================================================
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Dexie Unit tests with Dexie.Observable applied</title>
  <base href="../../../../test/" />
  <link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
</head>
<body>
    <div id="qunit"></div>
    <div id="qunit-fixture"></div>
    <script src="babel-polyfill/polyfill.min.js"></script>
    <script>
        // Hack for making the WebWorker test behave also here...
        window.workerSource = "worker.js";
        window.workerImports = ["../dist/dexie.js", "../addons/Dexie.Observable/dist/dexie-observable.js"];
    </script>
    <script src="../node_modules/qunitjs/qunit/qunit.js"></script>
    <script src="../dist/dexie.js"></script>
    <script src="../addons/Dexie.Observable/dist/dexie-observable.js"></script>
    <script src="bundle.js"></script>
</body>
</html>


================================================
FILE: addons/Dexie.Observable/test/typings/test-typings.ts
================================================

import Dexie from 'dexie';
import '../../src/Dexie.Observable';
import dexieObservable from '../../src/Dexie.Observable';
import { IDatabaseChange, DatabaseChangeType } from '../../api';

interface Foo {
    id: string;
}

class MyDb extends Dexie {
    foos: Dexie.Table<Foo, string>;

    constructor() {
        super('testdb', {addons: [dexieObservable, Dexie.Observable]});
        this.version(1).stores({foos: '$$id'});
    }
}

let db = new MyDb();

let syncNode = new db.observable.SyncNode();
syncNode.isMaster;
syncNode.deleteTimeStamp.toExponential();
syncNode.lastHeartBeat.toExponential();
syncNode.myRevision.toFixed();

db.on('message', msg => {
    msg.type;
    msg.message;
    msg.destinationNode * 1;
    msg.wantReply;
    msg.resolve('foo');
    msg.reject(new Error('Foo'));
});
db.observable.sendMessage('myMsgType', {foo: 'bar'}, 13, {wantReply: true});
db.observable.sendMessage('myMsgType', 'foobar', 13, {wantReply: false});

db.observable.broadcastMessage('myBroadcastMsgType', {foo2: 'bar2'}, false);

db.on('changes', changes => {
    changes.forEach(change => {
        switch (change.type) {
            case DatabaseChangeType.Create:
                change.table.toLowerCase();
                change.key;
                change.obj;                
                break;
            case DatabaseChangeType.Update:
                change.table.toLowerCase();
                change.key;
                change.mods;
                break;
            case DatabaseChangeType.Delete:
                change.table.toLowerCase();
                change.key;
                break;
        }
    })
});

Dexie.Observable.createUUID().toLowerCase();
Dexie.Observable.on('latestRevisionIncremented', (dbName, rev) => {dbName.toLowerCase(); rev.toFixed()});
Dexie.Observable.on('latestRevisionIncremented').subscribe(()=>{});
Dexie.Observable.on('latestRevisionIncremented').fire(()=>{});
Dexie.Observable.on('latestRevisionIncremented').unsubscribe(()=>{});

Dexie.Observable.on('suicideNurseCall', (dbName, nodeId)=>{dbName.toLowerCase(); nodeId.toExponential()});
Dexie.Observable.on('intercomm', dbName=>{dbName.toLowerCase()});
Dexie.Observable.on('beforeunload', ()=>{});

Dexie.Observable.on('latestRevisionIncremented').unsubscribe(()=>{});
var x: IDatabaseChange = {key: 1, table: "", type: DatabaseChangeType.Delete, oldObj: {}};
x.key;
x.type;
x.oldObj;


================================================
FILE: addons/Dexie.Observable/test/typings/tsconfig.json
================================================
{
    "compilerOptions": {
        "module": "es6",
        "target": "es5",
        "noImplicitAny": true,
        "strictNullChecks": true,
        "outDir": "../../tools/tmp/test-typings",
        "moduleResolution": "node",
        "lib": ["dom", "es2020"]
    },
    "files": [
        "test-typings.ts"
    ]
}


================================================
FILE: addons/Dexie.Observable/test/unit/.eslintrc.json
================================================
{
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
    }
  },
  "env": {
    "browser": true,
    "node": true
  },
  "rules": {
    "no-undef": ["error"]
  },
  "globals": {
    "Promise": true
  }
}


================================================
FILE: addons/Dexie.Observable/test/unit/.gitignore
================================================
/bundle.js
/bundle.js.map


================================================
FILE: addons/Dexie.Observable/test/unit/deep-equal.js
================================================
import {equal} from 'QUnit';

// Must use this rather than QUnit's deepEqual() because that one fails on Safari when run via karma-browserstack-launcher
export function deepEqual(a, b, description) {
  if (typeof a === 'object' && typeof b === 'object' && a != null && b != null) {
    equal(JSON.stringify(sortMembers(a), null, 2), JSON.stringify(sortMembers(b), null, 2), description);
  } else {
    equal(JSON.stringify(a, null, 2), JSON.stringify(b, null, 2), description);
  }
}

/**
 * 
 * @param {object} obj 
 */
function sortMembers (obj) {
  return Object.keys(obj).sort().reduce((result, key) => {
    result[key] = obj[key];
    return result;
  }, {});
}


================================================
FILE: addons/Dexie.Observable/test/unit/hooks/tests-creating.js
================================================
import Dexie from 'dexie';
import {module, asyncTest, start, stop, strictEqual, ok} from 'QUnit';
import {deepEqual} from '../deep-equal';
import {resetDatabase} from '../../../../../test/dexie-unittest-utils';
import initCreatingHook from '../../../src/hooks/creating';
import initWakeupObservers from '../../../src/wakeup-observers';
import initOverrideCreateTransaction from '../../../src/override-create-transaction';
import {CREATE} from '../../../src/change_types';

const db = new Dexie('TestDBTable', {addons: []});
db.version(1).stores({
  foo: "id",
  bar: "$$id",
  baz: "++id",
  _changes: "++rev"
});

const wakeupObservers = initWakeupObservers(db, {latestRevision: {}}, self.localStorage);
const overrideCreateTransaction = initOverrideCreateTransaction(db, wakeupObservers);
db._createTransaction = Dexie.override(db._createTransaction, overrideCreateTransaction);

module('creating Hook', {
  setup: () => {
    stop();
    // Do a full DB reset to clean _changes table
    db._hasBeenCreated = false;
    resetDatabase(db).catch(function (e) {
      ok(false, "Error resetting database: " + e.stack);
    }).finally(start);
  },
  teardown: () => {
  }
});

asyncTest('should create a UUID key if $$ was given', () => {
  db.bar.schema.primKey.uuid = true;
  db.bar.schema.observable = true;
  const creatingHook = initCreatingHook(db, db.bar);

  db.bar.hook('creating', function(primKey, obj, trans) {
    const ctx = {onsuccess: null, onerror: null};
    const res = creatingHook.call(ctx, primKey, obj, trans);
    // Note that this regex is not spec compliant but should be good enough for this test
    const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$/;
    ok(regex.test(res), 'We got a UUID');

    this.onsuccess = function(resKey) {
      try {
        strictEqual(res, resKey, 'Key from success and hook should match');
        db._changes.toArray((changes) => {
          strictEqual(changes.length, 1, 'We have one change');
          strictEqual(changes[0].key, resKey, 'Key should match');
          strictEqual(changes[0].type, CREATE, 'CREATE type');
          strictEqual(changes[0].table, 'bar', 'bar table');
          // Normally $$ would be removed from the id in overrideParseStoresSpec
          deepEqual(changes[0].obj, {foo: 'bar', $$id: resKey}, 'obj should match');
          strictEqual(changes[0].source, null, 'We have no source');
          ok(typeof trans._lastWrittenRevision !== 'undefined', '_lastWrittenRevision should be defined');
        })
        .catch((e) => {
          ok(false, 'Error: ' + e);
        })
      } catch (e) {
        ok(false, 'Error: ' + e);
      }
    };

    this.onerror = function(e) {
      ok(false, 'Error: ' + e);
    }
  });

  db.bar.add({foo: 'bar'})
      .catch(function(err) {
        ok(false, "Error: " + err);
      })
      .finally(start);
});

asyncTest('should not create a key if one was given', () => {
  db.foo.schema.observable = true;
  const creatingHook = initCreatingHook(db, db.foo);
  const ID = 1;
  const source = 10;

  db.foo.hook('creating', function(primKey, obj, trans) {
    trans.source = source;
    const ctx = {onsuccess: null, onerror: null};
    const res = creatingHook.call(ctx, primKey, obj, trans);
    strictEqual(res, undefined, 'ID was given return undefined');

    this.onsuccess = function(resKey) {
      try {
        strictEqual(resKey, ID, 'We got the given ID');
        db._changes.toArray((changes) => {
          strictEqual(changes.length, 1, 'We have one change');
          strictEqual(changes[0].key, ID, 'Key should match');
          strictEqual(changes[0].type, CREATE, 'CREATE type');
          strictEqual(changes[0].table, 'foo', 'foo table');
          deepEqual(changes[0].obj, {foo: 'bar', id: ID}, 'obj should match');
          strictEqual(changes[0].source, source, 'We have source');
          ok(typeof trans._lastWrittenRevision !== 'undefined', '_lastWrittenRevision should be defined');
        })
            .catch((e) => {
              ok(false, 'Error: ' + e);
            })
      } catch (e) {
        ok(false, 'Error: ' + e);
      }
    };

    this.onerror = function(e) {
      ok(false, 'Error: ' + e);
    }
  });

  db.foo.add({id: ID, foo: 'bar'})
      .catch(function(err) {
        ok(false, "Error: " + err);
      })
      .finally(start);
});

asyncTest('should use the auto-incremented key if ++ was given', () => {
  db.baz.schema.observable = true;
  const creatingHook = initCreatingHook(db, db.baz);
  const ID = 1;

  db.baz.hook('creating', function(primKey, obj, trans) {
    const ctx = {onsuccess: null, onerror: null};
    const res = creatingHook.call(ctx, primKey, obj, trans);
    strictEqual(res, undefined, 'ID was auto-increment return undefined');

    this.onsuccess = function(resKey) {
      try {
        strictEqual(resKey, ID, 'We got the given ID');
        db._changes.toArray((changes) => {
          strictEqual(changes.length, 1, 'We have one change');
          strictEqual(changes[0].key, null, 'Key should be null');
          strictEqual(changes[0].type, CREATE, 'CREATE type');
          strictEqual(changes[0].table, 'baz', 'baz table');
          deepEqual(changes[0].obj, {foo: 'bar'}, 'obj should match');
          strictEqual(changes[0].source, null, 'We have no source');
          ok(typeof trans._lastWrittenRevision !== 'undefined', '_lastWrittenRevision should be defined');
        })
            .catch((e) => {
              ok(false, 'Error: ' + e);
            })
      } catch (e) {
        ok(false, 'Error: ' + e);
      }
    };

    this.onerror = function(e) {
      ok(false, 'Error: ' + e);
    }
  });

  db.baz.add({foo: 'bar'})
      .catch(function(err) {
        ok(false, "Error: " + err);
      })
      .finally(start);
});


================================================
FILE: addons/Dexie.Observable/test/unit/hooks/tests-deleting.js
================================================
import Dexie from 'dexie';
import {module, asyncTest, start, stop, strictEqual, ok} from 'QUnit';
import {deepEqual} from '../deep-equal';
import {resetDatabase} from '../../../../../test/dexie-unittest-utils';
import initDeletingHook from '../../../src/hooks/deleting';
import initWakeupObservers from '../../../src/wakeup-observers';
import initOverrideCreateTransaction from '../../../src/override-create-transaction';
import {DELETE} from '../../../src/change_types';

const db = new Dexie('TestDBTable', {addons: []});
db.version(1).stores({
  foo: "id",
  _changes: "++rev"
});

const wakeupObservers = initWakeupObservers(db, {latestRevision: {}}, self.localStorage);
const overrideCreateTransaction = initOverrideCreateTransaction(db, wakeupObservers);
db._createTransaction = Dexie.override(db._createTransaction, overrideCreateTransaction);

module('deleting Hook', {
  setup: () => {
    stop();
    // Do a full DB reset to clean _changes table
    db._hasBeenCreated = false;
    resetDatabase(db).catch(function (e) {
      ok(false, "Error resetting database: " + e.stack);
    }).finally(start);
  },
  teardown: () => {
  }
});

asyncTest('should create a DELETE change', () => {
  db.foo.schema.observable = true;
  const deletingHook = initDeletingHook(db, db.foo.name);
  const ID = 10;
  const source = 10;

  db.foo.hook('deleting', function(primKey, obj, trans) {
    trans.source = 10;
    const ctx = {onsuccess: null, onerror: null};
    deletingHook.call(ctx, primKey, obj, trans);

    this.onsuccess = function() {
      try {
        db._changes.toArray((changes) => {
          strictEqual(changes.length, 1, 'We have one change');
          strictEqual(changes[0].key, ID, 'Key should match');
          strictEqual(changes[0].type, DELETE, 'DELETE type');
          strictEqual(changes[0].table, 'foo', 'foo table');
          deepEqual(changes[0].oldObj, {foo: 'bar', id: ID}, 'oldObj should match');
          strictEqual(changes[0].source, source, 'We have source');
          ok(typeof trans._lastWrittenRevision !== 'undefined', '_lastWrittenRevision should be defined');
        })
            .catch((e) => {
              ok(false, 'Error: ' + e);
            })
      } catch (e) {
        ok(false, 'Error: ' + e);
      }
    };

    this.onerror = function(e) {
      ok(false, 'Error: ' + e);
    }
  });

  db.foo.add({id: ID, foo: 'bar'})
      .then(() => {
        return db.foo.delete(ID)
      })
      .catch(function(err) {
        ok(false, "Error: " + err);
      })
      .finally(start);
});


================================================
FILE: addons/Dexie.Observable/test/unit/hooks/tests-updating.js
================================================
import Dexie from 'dexie';
import {module, asyncTest, start, stop, strictEqual, ok} from 'QUnit';
import {deepEqual} from '../deep-equal';
import {resetDatabase} from '../../../../../test/dexie-unittest-utils';
import initUpdatingHook from '../../../src/hooks/updating';
import initWakeupObservers from '../../../src/wakeup-observers';
import initOverrideCreateTransaction from '../../../src/override-create-transaction';
import {UPDATE} from '../../../src/change_types';

const db = new Dexie('TestDBTable', {addons: []});
db.version(1).stores({
  foo: "id",
  _changes: "++rev"
});

const wakeupObservers = initWakeupObservers(db, {latestRevision: {}}, self.localStorage);
const overrideCreateTransaction = initOverrideCreateTransaction(db, wakeupObservers);
db._createTransaction = Dexie.override(db._createTransaction, overrideCreateTransaction);

module('updating Hook', {
  setup: () => {
    stop();
    // Do a full DB reset to clean _changes table
    db._hasBeenCreated = false;
    resetDatabase(db).catch(function (e) {
      ok(false, "Error resetting database: " + e.stack);
    }).finally(start);
  },
  teardown: () => {
  }
});

asyncTest('should create an UPDATE change', () => {
  db.foo.schema.observable = true;
  const updatingHook = initUpdatingHook(db, db.foo.name);
  const ID = 1;
  const source = 10;

  db.foo.hook('updating', function hook(mods, primKey, obj, trans) {
    // Remove this hook now otherwise other tests might call it
    db.foo.hook('updating').unsubscribe(hook);

    trans.source = source;
    const ctx = {onsuccess: null, onerror: null};
    updatingHook.call(ctx, mods, primKey, obj, trans);

    this.onsuccess = function() {
      try {
        db._changes.toArray((changes) => {
          strictEqual(changes.length, 1, 'We have one change');
          strictEqual(changes[0].key, ID, 'Key should match');
          strictEqual(changes[0].type, UPDATE, 'UPDATE type');
          strictEqual(changes[0].table, 'foo', 'foo table');
          deepEqual(changes[0].obj, {foo: 'baz', id: ID}, 'obj should match');
          strictEqual(changes[0].source, source, 'We have source');
          ok(typeof trans._lastWrittenRevision !== 'undefined', '_lastWrittenRevision should be defined');
        })
            .catch((e) => {
              ok(false, 'Error: ' + e);
            })
      } catch (e) {
        ok(false, 'Error: ' + e);
      }
    };

    this.onerror = function(e) {
      ok(false, 'Error: ' + e);
    }
  });

  db.foo.add({id: ID, foo: 'bar'})
      .then(() => {
        return db.foo.update(ID, {foo: 'baz'});
      })
      .catch(function(err) {
        ok(false, "Error: " + err);
      })
      .finally(start);
});

asyncTest('should not create an UPDATE change if the mods are already in the old object', () => {
  db.foo.schema.observable = true;
  const updatingHook = initUpdatingHook(db, db.foo.name);
  const ID = 2;
  const source = 10;

  db.foo.hook('updating', function hook(mods, primKey, obj, trans) {
    // Remove this hook now otherwise other tests might call it
    db.foo.hook('updating').unsubscribe(hook);

    trans.source = source;
    const ctx = {onsuccess: null, onerror: null};
    updatingHook.call(ctx, mods, primKey, obj, trans);

    this.onsuccess = function() {
      try {
        db._changes.toArray((changes) => {
          strictEqual(changes.length, 0, 'We have no change');
        })
            .catch((e) => {
              ok(false, 'Error: ' + e);
            })
      } catch (e) {
        ok(false, 'Error: ' + e);
      }
    };

    this.onerror = function(e) {
      ok(false, 'Error: ' + e);
    }
  });

  db.foo.add({id: ID, foo: 'bar'})
      .then(() => {
        return db.foo.update(ID, {foo: 'bar'});
      }).then(()=>{
        return db._changes.toArray((changes) => {
          strictEqual(changes.length, 0, 'We have no change');
        });
      })
      .catch(function(err) {
        ok(false, "Error: " + err);
      })
      .finally(start);
});



================================================
FILE: addons/Dexie.Observable/test/unit/karma.conf.js
================================================
// Include common configuration
const {karmaCommon, getKarmaConfig, defaultBrowserMatrix} = require('../../../../test/karma.common');

module.exports = function (config) {
  const browserMatrixOverrides = {
    // Be fine with testing on local travis firefox + browserstack chrome, latest supported.
    ci: ["remote_chrome"],
    // Safari fails to reply on browserstack. Need to not have it here.
    // Just complement with old chrome browser that is not part of CI test suite.
    pre_npm_publish: [
      "Chrome",
    ]
  };

  const cfg = getKarmaConfig(browserMatrixOverrides, {
    // Base path should point at the root 
    basePath: '../../../../',
    files: karmaCommon.files.concat([
      'dist/dexie.js',
      'addons/Dexie.Observable/dist/dexie-observable.js',
      'addons/Dexie.Observable/test/unit/bundle.js',
      { pattern: 'addons/Dexie.Observable/test/unit/*.map', watched: false, included: false },
      { pattern: 'addons/Dexie.Observable/dist/*.map', watched: false, included: false }
    ])
  });

  config.set(cfg);
}


================================================
FILE: addons/Dexie.Observable/test/unit/run-unit-tests.html
================================================
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Dexie.Observable Unit tests</title>
  <link rel="stylesheet" href="../../../../node_modules/qunitjs/qunit/qunit.css">
</head>
<body>
    <div id="qunit"></div>
    <div id="qunit-fixture"></div>
    <script src="../../../../test/babel-polyfill/polyfill.min.js"></script>
    <script src="../../../../node_modules/qunitjs/qunit/qunit.js"></script>
    <script src="../../../../dist/dexie.js"></script>
    <script src="../../dist/dexie-observable.js"></script>
    <script src="bundle.js"></script>
</body>
</html>


================================================
FILE: addons/Dexie.Observable/test/unit/tests-observable-misc.js
================================================
import {module, asyncTest, equal, strictEqual, ok, start} from 'QUnit';
import {deepEqual} from './deep-equal';
import Dexie from 'dexie';
import 'dexie-observable';

module("tests-observable-misc", {
  setup: function () {
    stop();
    Dexie.delete("ObservableTest").then(function () {
      start();
    }).catch(function (e) {
      ok(false, "Could not delete database");
    });
  },
  teardown: function () {
    stop();
    Dexie.delete("ObservableTest").then(start);
  }
});

function createDB() {
  var db = new Dexie("ObservableTest");
  db.version(1).stores({
    friends: "++id,name,shoeSize",
    CapitalIdTest: "$$Id,name"
    //pets: "++id,name,kind",
    //$emailWords: "",
  });
  return db;
}

// Basically check if Dexie.Observable adds a 'changes' event
// Test works because of the second parameter to asyncTest which expects 4 assertions
asyncTest("changes in on DB instance should trigger a change event in an other instance", 4, function () {
  var db1 = createDB();
  var db2 = createDB();

  db2.on('changes', function (changes, partitial) {
    changes.forEach(function (change) {
      switch (change.type) {
        case 1:
          ok(true, "obj created: " + JSON.stringify(change.obj));
          break;
        case 2:
          ok(true, "obj updated: " + JSON.stringify(change.mods));
          equal(JSON.stringify(change.mods), JSON.stringify({name: "David"}), "Only modifying the name property");
          break;
        case 3:
          ok(true, "obj deleted: " + JSON.stringify(change.oldObj));
          db1.close();
          db2.close();
          start();
          break;
      }
    });
  });

  db1.open();
  db2.open();

  db1.friends.put({name: "Dave", shoeSize: 43}).then(function (id) {
    // Update object:
    return db1.friends.put({id: id, name: "David", shoeSize: 43});
  }).then(function (id) {
    // Delete object:
    return db1.friends.delete(id);
  }).catch(function (e) {
    ok(false, "Error: " + e.stack || e);
    start();
  });
});

// Test UUID primary key
asyncTest("Capital$$Id-test", function () {
  var db = createDB();
  db.open();
  db.CapitalIdTest.put({name: "Hilda"}).then(function () {
    return db.CapitalIdTest.toCollection().first();
  }).then(function (firstItem) {
    ok(firstItem.name == "Hilda", "Got first item");
    ok(firstItem.Id, "First item has a primary key set: " + firstItem.Id);
    // Note that this regex is not spec compliant but should be good enough for this test
    const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$/;
    ok(regex.test(firstItem.Id), 'We got a UUID');
  }).catch(function (e) {
    ok(false, "Error: " + e);
  }).finally(function () {
    db.close();
    start();
  });
});

//
// Test intercomm in same window
//
asyncTest('should receive a message from the first sync node', 4, () => {
  const db1 = createDB();
  const db2 = createDB();
  let senderID;
  let receiverID;
  db2.on('message', (msg) => {
    strictEqual(msg.message, 'foobar', 'We got the correct message');
    strictEqual(msg.sender, senderID, 'We got the right sender ID');
    strictEqual(msg.type, 'request', 'We got the correct type');
    strictEqual(msg.destinationNode, receiverID, 'We got the correct destination node');
    start();
  });

  db1.on('message', () => {
    ok(false, 'We should not receive a message');
  });

  db1._syncNodes.toArray()
      .then((arr) => {
        senderID = arr[0].id;
        return db2._syncNodes.toArray();
      })
      .then((arr) => {
        receiverID = arr.filter((node) => node.id !== senderID)[0].id;
        db1.observable.sendMessage('request', 'foobar', receiverID, {});
      })
      .catch((e) => {
        ok(false, 'Error: ' + e);
      });
});

asyncTest('master node should receive the message if the destination is not present and we want a reply', 5, () => {
  const db1 = createDB();
  let senderID;
  db1.on('message', (msg) => {
    deepEqual(msg.message, {foo: 'foobar'}, 'We got the correct message');
    strictEqual(msg.sender, senderID, 'We got the right sender ID');
    strictEqual(msg.type, 'request', 'We got the correct type');
    strictEqual(msg.destinationNode, senderID, 'We got the correct destination node');
    start();
  });

  db1._syncNodes.toArray()
      .then((arr) => {
        senderID = arr[0].id;
        strictEqual(arr[0].isMaster, 1, 'We are master');
        db1.observable.sendMessage('request', {foo: 'foobar'}, 10, {wantReply: true});
      })
      .catch((e) => {
        ok(false, 'Error: ' + e);
      });
});

asyncTest('sender should react on successful reply', 1, () => {
  const db1 = createDB();
  const db2 = createDB();
  let senderID;
  let receiverID;
  db2.on('message', (msg) => {
    msg.resolve('reply msg');
  });

  db1._syncNodes.toArray()
      .then((arr) => {
        senderID = arr[0].id;
        return db2._syncNodes.toArray();
      })
      .then((arr) => {
        receiverID = arr.filter((node) => node.id !== senderID)[0].id;
        return db1.observable.sendMessage('request', {foo: 'foobar'}, receiverID, {wantReply: true});
      })
      .then((result) => {
        strictEqual(result, 'reply msg', 'We got the correct result msg');
      })
      .catch((e) => {
        ok(false, 'Error: ' + e);
      })
      .finally(start);
});

asyncTest('sender should react on failure reply', 1, () => {
  const db1 = createDB();
  const db2 = createDB();
  let senderID;
  let receiverID;
  db2.on('message', (msg) => {
    msg.reject('error msg');
  });

  db1._syncNodes.toArray()
      .then((arr) => {
        senderID = arr[0].id;
        return db2._syncNodes.toArray();
      })
      .then((arr) => {
        receiverID = arr.filter((node) => node.id !== senderID)[0].id;
        return db1.observable.sendMessage('request', {foo: 'foobar'}, receiverID, {wantReply: true});
      })
      .catch((msg) => {
        strictEqual(msg, 'error msg');
      })
      .finally(start);
});

asyncTest('sync nodes should react on broadcast', 4, () => {
  const db1 = createDB();
  const db2 = createDB();
  let senderID;
  let receiverID;
  db2.on('message', (msg) => {
    deepEqual(msg.message, {foo: 'foobar'}, 'We got the correct message');
    strictEqual(msg.sender, senderID, 'We got the right sender ID');
    strictEqual(msg.type, 'request', 'We got the correct type');
    strictEqual(msg.destinationNode, receiverID, 'We got the correct destination node');
    start();
  });

  db1.on('message', () => {
    ok(false, 'We should not receive a message');
  });

  db1._syncNodes.toArray()
      .then((arr) => {
        senderID = arr[0].id;
        return db2._syncNodes.toArray();
      })
      .then((arr) => {
        receiverID = arr.filter((node) => node.id !== senderID)[0].id;
        db1.observable.broadcastMessage('request', {foo: 'foobar'});
      })
      .catch((e) => {
        ok(false, 'Error: ' + e);
      });
});

asyncTest('sender should be able to react on broadcast if bIncludeSelf is true', 4, () => {
  const db1 = createDB();
  const db2 = createDB();
  let senderID;
  let receiverID;

  db1.on('message', (msg) => {
      deepEqual(msg.message, {foo: 'foobar'}, 'We got the correct message');
      strictEqual(msg.sender, senderID, 'We got the right sender ID');
      strictEqual(msg.type, 'broadcast', 'We got the correct type');
      strictEqual(msg.destinationNode, senderID, 'We got the correct destination node');
      start();
  });

  db1._syncNodes.toArray()
      .then((arr) => {
        senderID = arr[0].id;
        return db2._syncNodes.toArray();
      })
      .then((arr) => {
        receiverID = arr.filter((node) => node.id !== senderID)[0].id;
        const bIncludeSelf = true;
        db1.observable.broadcastMessage('broadcast', {foo: 'foobar'}, bIncludeSelf);
      })
      .catch((e) => {
        ok(false, 'Error: ' + e);
      });
});

// This tests relates to https://github.com/dexie/Dexie.js/issues/429#issuecomment-269793599
// If db2 receives its message multiple times qunit will error as start() is called multiple times
asyncTest('no matter how many times sendMessage is called a receiver should receive its message only once', 4, () => {
  const db1 = createDB();
  const db2 = createDB();
  let senderID;
  let receiverID;
  db2.on('message', (msg) => {
    deepEqual(msg.message, {foo: 'foobar'}, 'We got the correct message');
    strictEqual(msg.sender, senderID, 'We got the right sender ID');
    strictEqual(msg.type, 'request', 'We got the correct type');
    strictEqual(msg.destinationNode, receiverID, 'We got the correct destination node');
    start();
  });

  db1._syncNodes.toArray()
      .then((arr) => {
        senderID = arr[0].id;
        return db2._syncNodes.toArray();
      })
      .then((arr) => {
        receiverID = arr.filter((node) => node.id !== senderID)[0].id;
        db1.observable.sendMessage('request', {foo: 'foobar'}, receiverID, {});
        // Send messages for receivers that don't exist
        db1.observable.sendMessage('request', {foo: 'foobar'}, 'foobar', {});
        db1.observable.sendMessage('request', {foo: 'foobar'}, 'barbaz', {});
      })
      .catch((e) => {
        ok(false, 'Error: ' + e);
      });
});


================================================
FILE: addons/Dexie.Observable/test/unit/tests-override-open.js
================================================
import {module, test, strictEqual, deepEqual, ok} from 'QUnit';
import initOverrideOpen from '../../src/override-open';

module('override-open', {
  setup: () => {
  },
  teardown: () => {
  }
});

test('should call the given original function', () => {
  let wasCalled = false;
  function origFn() {
    wasCalled = true;
  }

  const db = {
    _allTables: {}
  };

  initOverrideOpen(db, function SyncNode() {}, function crudMonitor() {})(origFn)();
  ok(wasCalled);
});

test('should call the crudMonitor function for every observable table', () => {
  const tables = [];
  function crudMonitor(table) {
    tables.push(table);
  }

  const db = {
    _allTables: {
      foo: {
        // TableSchema: for more info see https://github.com/dfahlander/Dexie.js/wiki/TableSchema
        schema: {
          observable: true
        }
      },
      _bar: {
        schema: {}
      }
    }
  };

  initOverrideOpen(db, function SyncNode() {}, crudMonitor)(() => {})();
  deepEqual(tables, [db._allTables.foo]);
});

test('should call mapToClass for the _syncNodes table', () => {
  function SyncNode() {}
  let calledWithClass;
  const db = {
    _allTables: {
      _syncNodes: {
        name: '_syncNodes',
        mapToClass(cls) {
          calledWithClass = cls;
        },
        schema: {}
      }
    }
  };

  initOverrideOpen(db, SyncNode, function crudMonitor(){})(() => {})();
  strictEqual(calledWithClass, SyncNode);
});


================================================
FILE: addons/Dexie.Observable/test/unit/tests-override-parse-stores-spec.js
================================================
import {module, test, strictEqual, deepEqual, ok} from 'QUnit';
import overrideParseStoresSpec from '../../src/override-parse-stores-spec';

module('override-parse-stores', {
  setup: () => {
  },
  teardown: () => {
  }
});

test('should create stores for Dexie.Observable and Dexie.Syncable', () => {
 function origFunc(stores/*, dbSchema*/) {
   ok(typeof stores._changes === 'string', 'Should have _changes store');
   ok(typeof stores._syncNodes === 'string', 'Should have _syncNodes store');
   ok(typeof stores._intercomm === 'string', 'Should have _intercomm store');
   ok(typeof stores._uncommittedChanges === 'string', 'Should have _uncommittedChanges store');
 }

  const stores = {};
  const dbSchema = {};
  overrideParseStoresSpec(origFunc)(stores, dbSchema);
});

test('should add UUID keys to the schema', () => {
 function origFunc(){}

 const stores = {
   foo: '$$id',
 };
 const dbSchema = {
   // TableSchema: for more info see https://github.com/dfahlander/Dexie.js/wiki/TableSchema
   foo: {
     name: 'foo',
     // IndexSpec: for more info see https://github.com/dfahlander/Dexie.js/wiki/IndexSpec
     primKey: {
       name: '$$id',
       keyPath: '$$id'
     }
   }
 };
 overrideParseStoresSpec(origFunc)(stores, dbSchema);

  strictEqual(dbSchema.foo.primKey.name, 'id', 'Should remove $$ from the name');
  strictEqual(dbSchema.foo.primKey.keyPath, 'id', 'Should remove $$ from keyPath');
  strictEqual(dbSchema.foo.primKey.uuid, true, 'uuid should be set to true');
});

test('should observe tables without _ and $', () => {
  function origFunc(){}

  const stores = {
    foo: 'id',
    _foo: 'id',
    $bar: 'id'
  };
  const dbSchema = {
    foo: {primKey: {name: 'id'}},
    _foo: {primKey: {name: 'id'}},
    $bar: {primKey: {name: 'id'}}
  };
  overrideParseStoresSpec(origFunc)(stores, dbSchema);

  strictEqual(dbSchema.foo.observable, true, 'foo should be observed');
  strictEqual(dbSchema._foo.observable, undefined, '_foo should not be observed');
  strictEqual(dbSchema.$bar.observable, undefined, '$bar should not be observed');
});


================================================
FILE: addons/Dexie.Observable/test/unit/unit-tests-all.js
================================================
import './hooks/tests-creating.js';
import './hooks/tests-deleting.js';
import './hooks/tests-updating.js';
import './tests-override-open.js';
import './tests-override-parse-stores-spec.js';
import './tests-observable-misc';


================================================
FILE: addons/Dexie.Observable/tools/build-configs/banner.txt
================================================
/* ========================================================================== 
 *                           dexie-observable.js
 * ==========================================================================
 *
 * Dexie addon for observing database changes not just on local db instance
 * but also on other instances, tabs and windows.
 *
 * Comprises a base framework for dexie-syncable.js
 *
 * By David Fahlander, david.fahlander@gmail.com,
 *    Nikolas Poniros, https://github.com/nponiros
 *
 * ==========================================================================
 *
 * Version {version}, {date}
 *
 * https://dexie.org
 *
 * Apache License Version 2.0, January 2004, http://www.apache.org/licenses/
 * 
 */


================================================
FILE: addons/Dexie.Observable/tools/build-configs/rollup.config.mjs
================================================
import sourcemaps from 'rollup-plugin-sourcemaps';
import {readFileSync} from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const packageJson = JSON.parse(readFileSync(path.resolve(__dirname, '../../package.json'), 'utf-8'));
const version = packageJson.version;

export default {
  input: 'tools/tmp/es5/src/Dexie.Observable.js',
  output: [{
    file: 'dist/dexie-observable.js',
    format: 'umd',
    banner: readFileSync(path.resolve(__dirname, 'banner.txt')),
    globals: {dexie: "Dexie"},
    name: 'Dexie.Observable',
    sourcemap: true
  },{
    file: 'dist/dexie-observable.es.js',
    format: 'es',
    banner: readFileSync(path.resolve(__dirname, 'banner.txt')),
    globals: {dexie: "Dexie"},
    name: 'Dexie.Observable',
    sourcemap: true
  }],
  external: ['dexie'],
  plugins: [ sourcemaps() ]
};


================================================
FILE: addons/Dexie.Observable/tools/build-configs/rollup.tests.config.js
================================================
import sourcemaps from 'rollup-plugin-sourcemaps';
import commonjs from '@rollup/plugin-commonjs';
import nodeResolve from '@rollup/plugin-node-resolve';

const ERRORS_TO_IGNORE = [
  "THIS_IS_UNDEFINED"
];

export default {
  input: 'tools/tmp/es5/test/addons/Dexie.Observable/test/unit/unit-tests-all.js',
  output: {
    file: 'test/unit/bundle.js',
    format: 'umd',
    globals: {dexie: "Dexie", "dexie-observable": "Dexie.Observable", QUnit: "QUnit"},
    sourcemap: true,
    name: 'dexieTests'
  },
  external: ['dexie', 'dexie-observable', 'QUnit'],
  plugins: [
    sourcemaps(),
    nodeResolve({browser: true}),
    commonjs()
  ],
  onwarn ({loc, frame, code, message}) {
    if (ERRORS_TO_IGNORE.includes(code)) return;
    if ( loc ) {
      console.warn( `${loc.file} (${loc.line}:${loc.column}) ${message}` );
      if ( frame ) console.warn( frame );
    } else {
      console.warn(`${code} ${message}`);
    }    
  }
};


================================================
FILE: addons/Dexie.Observable/tools/build-configs/rollup.tests.config.mjs
================================================
import sourcemaps from 'rollup-plugin-sourcemaps';
import commonjs from '@rollup/plugin-commonjs';
import nodeResolve from '@rollup/plugin-node-resolve';

const ERRORS_TO_IGNORE = [
  "THIS_IS_UNDEFINED"
];

export default {
  input: 'tools/tmp/es5/test/addons/Dexie.Observable/test/unit/unit-tests-all.js',
  output: {
    file: 'test/unit/bundle.js',
    format: 'umd',
    globals: {dexie: "Dexie", "dexie-observable": "Dexie.Observable", QUnit: "QUnit"},
    sourcemap: true,
    name: 'dexieTests'
  },
  external: ['dexie', 'dexie-observable', 'QUnit'],
  plugins: [
    sourcemaps(),
    nodeResolve({browser: true}),
    commonjs()
  ],
  onwarn ({loc, frame, code, message}) {
    if (ERRORS_TO_IGNORE.includes(code)) return;
    if ( loc ) {
      console.warn( `${loc.file} (${loc.line}:${loc.column}) ${message}` );
      if ( frame ) console.warn( frame );
    } else {
      console.warn(`${code} ${message}`);
    }    
  }
};


================================================
FILE: addons/Dexie.Observable/tools/build-configs/rollup.tests.unit.config.js
================================================
import sourcemaps from 'rollup-plugin-sourcemaps';
import commonjs from '@rollup/plugin-commonjs';
import nodeResolve from '@rollup/plugin-node-resolve';

const ERRORS_TO_IGNORE = [
  "THIS_IS_UNDEFINED"
];

export default {
  input: 'tools/tmp/es5/test/addons/Dexie.Observable/test/unit/unit-tests-all.js',
  output: {
    file: 'test/unit/bundle.js',
    format: 'umd',
    globals: {dexie: "Dexie", "dexie-observable": "Dexie.Observable", QUnit: "QUnit"},
    sourcemap: true,
    name: 'dexieTests'
  },
  external: ['dexie', 'dexie-observable', 'QUnit'],
  plugins: [
    sourcemaps(),
    nodeResolve({browser: true}),
    commonjs()
  ],
  onwarn ({loc, frame, code, message}) {
    if (ERRORS_TO_IGNORE.includes(code)) return;
    if ( loc ) {
      console.warn( `${loc.file} (${loc.line}:${loc.column}) ${message}` );
      if ( frame ) console.warn( frame );
    } else {
      console.warn(`${code} ${message}`);
    }    
  }
};


================================================
FILE: addons/Dexie.Observable/tools/build-configs/rollup.tests.unit.config.mjs
================================================
import sourcemaps from 'rollup-plugin-sourcemaps';
import commonjs from '@rollup/plugin-commonjs';
import nodeResolve from '@rollup/plugin-node-resolve';

const ERRORS_TO_IGNORE = [
  "THIS_IS_UNDEFINED"
];

export default {
  input: 'tools/tmp/es5/test/addons/Dexie.Observable/test/unit/unit-tests-all.js',
  output: {
    file: 'test/unit/bundle.js',
    format: 'umd',
    globals: {dexie: "Dexie", "dexie-observable": "Dexie.Observable", QUnit: "QUnit"},
    sourcemap: true,
    name: 'dexieTests'
  },
  external: ['dexie', 'dexie-observable', 'QUnit'],
  plugins: [
    sourcemaps(),
    nodeResolve({browser: true}),
    commonjs()
  ],
  onwarn ({loc, frame, code, message}) {
    if (ERRORS_TO_IGNORE.includes(code)) return;
    if ( loc ) {
      console.warn( `${loc.file} (${loc.line}:${loc.column}) ${message}` );
      if ( frame ) console.warn( frame );
    } else {
      console.warn(`${code} ${message}`);
    }    
  }
};


================================================
FILE: addons/Dexie.Observable/tools/replaceVersionAndDate.js
================================================
const fs = require('fs');
const files = process.argv.slice(2);
const version = require('../package.json').version;

files.forEach(file => {
    let fileContent = fs.readFileSync(file, "utf-8");
    fileContent = fileContent
        .replace(/{version}/g, version)
        .replace(/{date}/g, new Date().toDateString());
    fs.writeFileSync(file, fileContent, "utf-8");
});


================================================
FILE: addons/Dexie.Syncable/.gitignore
================================================
dist/*.js
dist/*.map
dist/*.ts
dist/*.gz
.eslintcache
**/tmp/


================================================
FILE: addons/Dexie.Syncable/.npmignore
================================================
tools/
src/
.*
tmp/
**/tmp/
test
*.log


================================================
FILE: addons/Dexie.Syncable/README.md
================================================
# Dexie.Syncable.js

Enables two-way synchronization with remote database.

*NOTE! This package has been unmaintained for a looong time and might be retired. Some people go under the impression that Dexie Cloud would be based on this package, but it's not - it has its own sync system based on middlewares - all source for it is in addons/dexie-cloud.*

### Install
```
npm install dexie --save
npm install dexie-observable --save
npm install dexie-syncable --save
```

### Use
```js
import Dexie from 'dexie';
import 'dexie-syncable'; // will import dexie-observable as well.

// Use Dexie as normally - but you can also register your sync protocols though
// Dexie.Syncable.registerSyncProtocol() api as well as using the db.syncable api
// as documented here.

```

### Dependency Tree

 * **Dexie.Syncable.js**
   * [Dexie.Observable.js](https://dexie.org/docs/Observable/Dexie.Observable.js)
     * [Dexie.js](https://dexie.org/docs/Dexie/Dexie.js)
       * [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)
   * _An implementation of [ISyncProtocol](https://dexie.org/docs/Syncable/Dexie.Syncable.ISyncProtocol)_

### Tutorial

#### 1. Include Required Sources
In your HTML, make sure to include Dexie.js, Dexie.Observable.js, Dexie.Syncable.js and an implementation of [ISyncProtocol](https://dexie.org/docs/Syncable/Dexie.Syncable.ISyncProtocol).

    <html><head>
        <script src="dexie.min.js"></script>
        <script src="dexie-observable.min.js"></script>
        <script src="dexie-syncable.min.js"></script>
        <script src="WebSocketSyncProtocol.js"></script> <!-- Example implementation of ISyncProtocol -->
        ...
    </head><body>
    </body></html>
    
##### Usage with existing DB

In case you want to use Dexie.Syncable with your existing database, but do not want to use UUID based Primary Keys as described below, you will have to do a schema upgrade. Without it Dexie.Syncable will not be able to properly work.

```javascript
import Dexie from 'dexie';
import 'dexie-observable';
import 'dexie-syncable';
import 'your-sync-protocol-implementation';

var db = new Dexie('myExistingDb');
db.version(1).stores(... existing schema ...);

// Now, add another version, just to trigger an upgrade for Dexie.Syncable
db.version(2).stores({}); // No need to add / remove tables. This is just to allow the addon to install its tables.
```

#### 2. Use UUID based Primary Keys ($$)
Two way replication cannot use auto-incremented keys if any sync node should be able to create objects no matter if it is offline or online. Dexie.Syncable comes with a new syntax when defining your store schemas: the double-dollar prefix ($$). Similarly to the ++ prefix in Dexie (meaning auto-incremented primary key), the double-dollar prefix means that the key will be given a universally unique identifier (UUID), in string format (For example "9cc6768c-358b-4d21-ac4d-58cc0fddd2d6").

    var db = new Dexie("MySyncedDB");
    db.version(1).stores({
        friends: "$$oid,name,shoeSize",
        pets: "$$oid,name,kind"
    });

#### 3. Connect to Server
You must specify the URL of the server you want to keep in-sync with. This has to be done once in the entire database life-time, but doing it on every startup is ok as well, since it won't affect already connected URLs.

    // This example uses the WebSocketSyncProtocol included in earlier steps.
    db.syncable.connect ("websocket", "https://syncserver.com/sync");
    db.syncable.on('statusChanged', function (newStatus, url) {
        console.log ("Sync Status changed: " + Dexie.Syncable.StatusTexts[newStatus]);
    });

#### 4. Use Your Database
Query and modify your database as if it was a simple Dexie instance. Any changes will be replicated to the server and changes on the server or an other window will replicate back to you.

    db.transaction('rw', db.friends, function (friends) {
        friends.add({name: "Arne", shoeSize: 47});
        friends.where('shoeSize').above(40).each(function (friend) {
            console.log("Friend with shoeSize over 40: " + friend.name);
        });
    });

_NOTE: Transactions only provide the Atomicity part of the [ACID](http://en.wikipedia.org/wiki/ACID) properties when using 2-way synchronization. This is due to the fact that the syncronization phase may result in another change overwriting the changes. However, it's still meaningful to use the transaction() method for atomicity. Atomicity is guaranteed not only locally but also when synced to the server, meaning that a part of the changes will never commit on the server until all changes from the transaction have been synced. In practice, you cannot increment a counter in the database (for example) and expect it to be consistent, but you can have a guaranteed that if you add a sequence of objects, all or none of them will replicate._

### API Reference

#### Static Members

[Dexie.Syncable.registerSyncProtocol (name, protocolInstance)](https://dexie.org/docs/Syncable/Dexie.Syncable.registerSyncProtocol())
Define how to replicate changes with your type of server.

[Dexie.Syncable.Statuses](https://dexie.org/docs/Syncable/Dexie.Syncable.Statuses)
Enum of possible sync statuses, such as OFFLINE, CONNECTING, ONLINE and ERROR.

[Dexie.Syncable.StatusTexts](https://dexie.org/docs/Syncable/Dexie.Syncable.StatusTexts)
Text lookup for status numbers

#### Non-Static Methods and Events

[db.syncable.connect (protocol, url, options)](https://dexie.org/docs/Syncable/db.syncable.connect())
Create a persistend two-way sync connection with the given URL.

[db.syncable.disconnect (url)](https://dexie.org/docs/Syncable/db.syncable.disconnect())
Stop syncing with the given URL but keep revision states until next connect.

[db.syncable.delete(url)](https://dexie.org/docs/Syncable/db.syncable.delete())
Delete all states and change queue for given URL.

[db.syncable.list()](https://dexie.org/docs/Syncable/db.syncable.list())
List the URLs of each remote node we have a state saved for.

[db.syncable.on('statusChanged')](https://dexie.org/docs/Syncable/db.syncable.on('statusChanged'))
Event triggered when sync status changes.

[db.syncable.setFilter ([criteria], filter)](https://dexie.org/docs/Syncable/db.syncable.setFilter())
Ignore certain objects from being synced defined by the given filter.

[db.syncable.getStatus (url)](https://dexie.org/docs/Syncable/db.syncable.getStatus())
Get sync status for the given URL.

[db.syncable.getOptions (url)](https://dexie.org/docs/Syncable/db.syncable.getOptions())
Get the options object for the given URL.


### Source

[Dexie.Syncable.js](https://github.com/dexie/Dexie.js/blob/master/addons/Dexie.Syncable/src/Dexie.Syncable.js)

### Description

Dexie.Syncable enables synchronization with a remote database (of almost any kind). It has its own API [ISyncProtocol](https://dexie.org/docs/Syncable/Dexie.Syncable.ISyncProtocol).
The [ISyncProtocol](https://dexie.org/docs/Syncable/Dexie.Syncable.ISyncProtocol) is pretty straight-forward to implement.
The implementation of that API defines how client- and server- changes are transported between local and remote nodes. The API support both poll-patterns
(such as ajax calls) and direct reaction pattern (such as WebSocket or long-polling methods). See samples below for each pattern.

### Sample [ISyncProtocol](https://dexie.org/docs/Syncable/Dexie.Syncable.ISyncProtocol) Implementations
 * [https://github.com/nponiros/sync_client](https://github.com/nponiros/sync_client)
 * [AjaxSyncProtocol.js](https://github.com/dfahlander/Dexie.js/blob/master/samples/remote-sync/ajax/AjaxSyncProtocol.js)
 * [WebSocketSyncProtocol.js](https://github.com/dfahlander/Dexie.js/blob/master/samples/remote-sync/websocket/WebSocketSyncProtocol.js)

### Sample Sync Servers
 * [https://github.com/nponiros/sync_server](https://github.com/nponiros/sync_server)
 * [WebSocketSyncServer.js](https://github.com/dfahlander/Dexie.js/blob/master/samples/remote-sync/websocket/WebSocketSyncServer.js)


================================================
FILE: addons/Dexie.Syncable/api.d.ts
================================================
/* dexie-syncable API - an independant syncronization API used by 'dexie-syncable'.
 * Version: 1.1
 * Date: December 2016
 *
 * Some assumptions are made upon how the database is structured though. We assume that:
 *  * Databases has 1..N tables. (For NOSQL databases without tables, this also works since it could be considered a db with a single table.)
 *  * Each table has a primary key.
 *	* The primary key is a UUID of some kind since auto-incremented primary keys are not suitable for syncronization
 *    (auto-incremented key would work but changes of conflicts would increase on create).
 *  * A database record is a JSON compatible object.
 *  * Always assume that the client may send the same set of changes twice. For example if client sent changes that server stored, but network went down before
 *    client got the ack from server, the client may try resending same set of changes again. This means that the same Object Create change may be sent twice etc.
 *    The implementation must not fail if trying to create an object with the same key twice, or delete an object with a key that does not exist.
 *  * Client and server must resolve conflicts in such way that the result on both sides are equal.
 *  * Since a server is the point of the most up-to-date database, conflicts should be resolved by prefering server changes over client changes.
 *    This makes it predestinable for client that the more often the client syncs, the more chance to prohibit conflicts.
 *
 * By separating module 'dexie-syncable' from 'dexie-syncable/api' we
 * distinguish that:
 *
 *   import {...} from 'dexie-syncable/api' is only for getting access to its
 *                                          interfaces and has no side-effects.
 *                                          Typescript-only import.
 *
 *   import 'dexie-syncable' is only for side effects - to extend Dexie with
 *                           functionality of dexie-syncable.
 *                           Javascript / Typescript import.
 *
 */

import {IDatabaseChange} from 'dexie-observable/api';
export {DatabaseChangeType} from 'dexie-observable/api';

/* ISyncProtocol

   Interface to implement for enabling syncronization with a remote database server. The remote database server may be SQL- or NOSQL based
   as long as it is capable of storing JSON compliant objects into some kind of object stores and reference them by a primary key.
   The server must also be revision- and changes aware. This is something that for many databases needs to be implemented by a REST- or
   WebSocket gateway between the client and the backend database. The gateway can act as a controller and make sure any changes
   are registered in the 'changes' table and that the API provides a sync() method to interchange changes between client and server.

   Two examples of a ISyncProtocol instances are found in:
       https://github.com/dfahlander/Dexie.js/tree/master/samples/remote-sync/ajax/AjaxSyncProtocol.js
       https://github.com/dfahlander/Dexie.js/tree/master/samples/remote-sync/websocket/WebSocketSyncProtocol.js

*/

/**
 * The interface to implement to provide sync towards a remote server.
 *
 * Documentation for this interface: https://github.com/dfahlander/Dexie.js/wiki/Dexie.Syncable.ISyncProtocol
 *
 */
export interface ISyncProtocol {
    partialsThreshold?: number;
    sync (
        context: IPersistedContext,
        url: string,
        options: any,
        baseRevision: any,
        syncedRevision: any,
        changes: IDatabaseChange[],
        partial: boolean,
        applyRemoteChanges: ApplyRemoteChangesFunction,
        onChangesAccepted: ()=>void,
        onSuccess: (continuation: PollContinuation | ReactiveContinuation)=>void,
        onError: (error: any, again?: number) => void) : void;
}

/**
 * Documentation for this interface: https://github.com/dfahlander/Dexie.js/wiki/Dexie.Syncable.IPersistedContext
 */
export interface IPersistedContext {
    save() : Promise<void>;
    [customProp: string] : any;
}

/**
 * Documentation for this function: https://github.com/dfahlander/Dexie.js/wiki/Dexie.Syncable.ISyncProtocol
 */
export type ApplyRemoteChangesFunction = (
    changes: IDatabaseChange[],
    lastRevision: any,
    partial?: boolean,
    clear?: boolean)
    => Promise<void>;

/**
 * Provide a poll continuation if your backend is a reqest/response service, such as a REST API.
 */
export interface PollContinuation {
    /** Implementation should return number of milliseconds until you want the framework to call sync() again. */
    again: number
}

/**
 * Provide a reactive continuation if your backend is connected to over WebSocket, socket-io, signalR or such,
 * and may push changes back to the client as they occur.
 */
export interface ReactiveContinuation {
    react (
        /** List of local changes to send to server. */
        changes: IDatabaseChange[],

        /** Server revision that server needs to know in order to apply the changes correcly.  */
        baseRevision: any,

        /** If true, it means that reach() will be called upon again with additional changes once you'version
         * called onChangesAccepted(). An implementation may handle this transactionally, i.e. wait with applying
         * these changes and instead buffer them in a temporary table and the apply everything once reac() is called
         * with partial=false.
         */
        partial: boolean,

        /** Callback to call when the given changes has been acknowledged and persisted at the server side.
         * This will mark the change-set as delivered and the framework wont try resending these changes anymore.
         */
        onChangesAccepted: ()=>void): void;

    /** Implementation should disconned the underlying transport and stop calling applyRemoteChanges(). */
    disconnect(): void;
}

export enum SyncStatus {
    /** An irrepairable error occurred and the sync provider is dead. */
    ERROR = -1,

    /** The sync provider hasnt yet become online, or it has been disconnected. */
    OFFLINE = 0,

    /** Trying to connect to server */
    CONNECTING = 1,

    /** Connected to server and currently in sync with server */
    ONLINE = 2,

    /** Syncing with server. For poll pattern, this is every poll call.
     * For react pattern, this is when local changes are being sent to server. */
    SYNCING = 3,

    /** An error occured such as net down but the sync provider will retry to connect. */
    ERROR_WILL_RETRY = 4
}


================================================
FILE: addons/Dexie.Syncable/api.js
================================================
// This file is deliberatly left empty to allow the api.d.ts to contain the definitions for Dexie.Syncable without generating an error on webpack


================================================
FILE: addons/Dexie.Syncable/dist/README.md
================================================
## Can't find dexie-syncable.js?
Transpiled code (dist version) IS ONLY checked in to
the [releases](https://github.com/dexie/Dexie.js/tree/releases/addons/Dexie.Syncable/dist).
branch.

## Download
[unpkg.com/dexie-syncable/dist/dexie-syncable.js](https://unpkg.com/dexie-syncable/dist/dexie-syncable.js)

[unpkg.com/dexie-syncable/dist/dexie-syncable.min.js](https://unpkg.com/dexie-syncable/dist/dexie-syncable.min.js)

[unpkg.com/dexie-syncable/dist/dexie-syncable.js.map](https://unpkg.com/dexie-syncable/dist/dexie-syncable.js.map)

[unpkg.com/dexie-syncable/dist/dexie-syncable.min.js.map](https://unpkg.com/dexie-syncable/dist/dexie-syncable.min.js.map)

## npm
```
npm install dexie-syncable --save
```
## bower
Since Dexie v1.3.4, addons are included in the dexie bower package. 
```
$ bower install dexie --save
$ ls bower_components/dexie/addons/Dexie.Syncable/dist
dexie-syncable.js  dexie-syncable.js.map  dexie-syncable.min.js  dexie-syncable.min.js.map

```
## Or build them yourself...
Fork Dexie.js, then:
```
git clone https://github.com/YOUR-USERNAME/Dexie.js.git
cd Dexie.js
npm install
cd addons/Dexie.Syncable
npm run build       # or npm run watch

```
If you're on windows, you need to use an elevated command prompt of some reason to get `npm install` to work.


================================================
FILE: addons/Dexie.Syncable/package.json
================================================
{
  "name": "dexie-syncable",
  "version": "4.0.1-beta.13",
  "description": "Addon to Dexie that makes it possible to sync indexeDB with remote databases.",
  "main": "dist/dexie-syncable.js",
  "module": "dist/dexie-syncable.es.js",
  "jsnext:main": "dist/dexie-syncable.es.js",
  "typings": "dist/dexie-syncable.d.ts",
  "jspm": {
    "format": "cjs",
    "ignore": [
      "src/"
    ]
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/dexie/Dexie.js.git"
  },
  "keywords": [
    "indexeddb",
    "dexie",
    "addon",
    "database",
    "sync"
  ],
  "author": "David Fahlander <https://github.com/dfahlander>",
  "contributors": [
    "Nikolas Poniros <https://github.com/nponiros>",
    "Martin Diphoorn <https://github.com/martindiphoorn>"
  ],
  "license": "Apache-2.0",
  "bugs": {
    "url": "https://github.com/dexie/Dexie.js/issues"
  },
  "scripts": {
    "build": "just-build",
    "watch": "just-build --watch",
    "test": "pnpm run build && pnpm run test:typings && pnpm run test:unit && pnpm run test:integration",
    "test:unit": "karma start test/unit/karma.conf.js --single-run",
    "test:integration": "karma start test/integration/karma.conf.js --single-run",
    "test:typings": "tsc -p test/test-typings/",
    "test:unit:debug": "karma start test/unit/karma.conf.js --log-level debug",
    "test:integration:debug": "karma start test/integrations/karma.conf.js --log-level debug",
    "test:ltcloud": "cross-env LAMBDATEST=true pnpm run test:ltTunnel & sleep 10 && pnpm run test:unit; UNIT_STATUS=$?; exit $UNIT_STATUS",
    "test:ltTunnel": "node ../../test/lt-local",
    "test:ltcloud:integration": "cross-env LAMBDATEST=true pnpm run test:integration; UNIT_STATUS=$?; kill $(cat tunnel.pid); exit $UNIT_STATUS"
  },
  "just-build": {
    "default": [
      "just-build release"
    ],
    "dev": [
      "just-build dexie-syncable"
    ],
    "dexie-syncable": [
      "# Build UMD module and the tests (two bundles)",
      "tsc --allowJs --moduleResolution node --lib es2020,dom -t es5 -m es2015 --outDir tools/tmp/es5 --rootDir ../.. --sourceMap src/Dexie.Syncable.js test/unit/unit-tests-all.js [--watch 'Compilation complete.']",
      "rollup -c tools/build-configs/rollup.config.mjs",
      "rollup -c tools/build-configs/rollup.tests.config.mjs",
      "node tools/replaceVersionAndDate.js dist/dexie-syncable.js",
      "node tools/replaceVersionAndDate.js test/unit/bundle.js",
      "# eslint ",
      "eslint src --cache"
    ],
    "release": [
      "just-build dexie-syncable",
      "# Copy Dexie.Syncable.d.ts to dist and replace version in it",
      "node -e \"fs.writeFileSync('dist/dexie-syncable.d.ts', fs.readFileSync('src/Dexie.Syncable.d.ts'))\"",
      "node tools/replaceVersionAndDate.js dist/dexie-syncable.d.ts",
      "# Minify the default ES5 UMD module",
      "cd dist",
      "uglifyjs dexie-syncable.js -m -c negate_iife=0 -o dexie-syncable.min.js --source-map"
    ]
  },
  "homepage": "https://dexie.org",
  "peerDependencies": {
    "dexie": "workspace:^",
    "dexie-observable": "workspace:^"
  },
  "devDependencies": {
    "dexie": "workspace:^",
    "dexie-observable": "workspace:^",
    "eslint": "^5.16.0",
    "just-build": "^0.9.24",
    "qunit": "2.10.0",
    "qunitjs": "1.23.1",
    "typescript": "^5.3.3",
    "uglify-js": "^3.5.6"
  }
}


================================================
FILE: addons/Dexie.Syncable/src/.eslintrc.json
================================================
{
  "extends": "eslint:recommended",
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
    }
  },
  "rules": {
    "no-undef": ["error"],
    "no-unused-vars": 1,
    "no-console": 0,
    "no-empty": 0
  },
  "globals": {
    "indexedDB": false,
    "IDBKeyRange": false,
    "setTimeout": false,
    "clearTimeout": false,
    "Symbol": false,
    "setImmediate": false,
    "console": false,
    "self": false,
    "window": false,
    "global": false,
    "navigator": false,
    "location": false,
    "chrome": false,
    "document": false,
    "MutationObserver": false,
    "CustomEvent": false,
    "dispatchEvent": false,
    "localStorage": false
  }
}


================================================
FILE: addons/Dexie.Syncable/src/Dexie.Syncable.d.ts
================================================
// Type definitions for dexie-syncable v{version}
// Project: https://github.com/dfahlander/Dexie.js/tree/master/addons/Dexie.Syncable
// Definitions by: David Fahlander <http://github.com/dfahlander>

import Dexie, { DexieEventSet } from 'dexie';
import 'dexie-observable';
import { ISyncProtocol, SyncStatus } from '../api';
import {IDatabaseChange} from 'dexie-observable/api';


export interface SyncableEventSet extends DexieEventSet {
    (eventName: 'statusChanged', subscriber: (status: number, url: string) => void): void;
}

//
// Extend Dexie interface
//
declare module 'dexie' {
    interface Dexie {
        syncable: {
            version: string;
            /**
             * Connect to given URL using given protocol and options. See documentation at:
             * https://github.com/dfahlander/Dexie.js/wiki/db.syncable.connect()
             */
            connect(protocol: string, url: string, options?: any): Dexie.Promise<void>;

            /**
             * Stop syncing with given url.. See docs at:
             * https://github.com/dfahlander/Dexie.js/wiki/db.syncable.disconnect()
             */
            disconnect(url: string): Dexie.Promise<void>;

            /**
             * Stop syncing and delete all sync state for given URL. See docs at:
             * https://github.com/dfahlander/Dexie.js/wiki/db.syncable.delete()
             */
            delete(url: string): Dexie.Promise<void>;

            /**
             * List remote URLs. See docs at:
             * https://github.com/dfahlander/Dexie.js/wiki/db.syncable.list()
             */
            list (): Dexie.Promise<string[]>;

            /**
             * Get sync status for given URL. See docs at:
             * https://github.com/dfahlander/Dexie.js/wiki/db.syncable.getStatus()
             */
            getStatus(url: string): Dexie.Promise<SyncStatus>;

            /**
             * Syncable events. See docs at:
             * https://github.com/dfahlander/Dexie.js/wiki/db.syncable.on('statusChanged')
             */
            on: SyncableEventSet;
        }

        /**
         * Table used for storing uncommitted changes when downloading partial change sets from
         * a sync server.
         *
         * Each change is bound to a node id (represents the remote server that the change was
         * downloaded from)
         */
        _uncommittedChanges: Dexie.Table<IDatabaseChange & {id: number, node: number}, number>;
    }

    interface DexieConstructor {
        Syncable: {
            (db: Dexie) : void;

            version: string;

            /**
             * See documentation at:
             * https://dexie.org/docs/Syncable/Dexie.Syncable.registerSyncProtocol()
             */
            registerSyncProtocol: (name: string, prototocolInstance: ISyncProtocol) => void;

            /** Translates a sync status number into a string "ERROR_WILL_RETRY", "ERROR", etc */
            StatusTexts: {[syncStatus:number]: string};
        }
    }
}

//
// Extend dexie-observable interfaces
//
declare module "dexie-observable" {
    // Extend SyncNode interface from Dexie.Observable to
    // allow storing remote nodes in table _syncNodes.
    interface SyncNode {
        url: string, // Only applicable for "remote" nodes. Only used in Dexie.Syncable.
        syncProtocol: string, // Tells which implementation of ISyncProtocol to use for remote syncing.
        syncContext: any,
        syncOptions: any,
        status: number,
        appliedRemoteRevision: any,
        remoteBaseRevisions: { local: number, remote: any }[],
        dbUploadState: {
            tablesToUpload: string[],
            currentTable: string,
            currentKey: any,
            localBaseRevision: number
        }
    }
}

export default Dexie.Syncable;



================================================
FILE: addons/Dexie.Syncable/src/Dexie.Syncable.js
================================================
/* ========================================================================== 
 *                           dexie-syncable.js
 * ==========================================================================
 *
 * Dexie addon for syncing indexedDB with remote endpoints.
 *
 * By David Fahlander, david.fahlander@gmail.com,
 *    Nikolas Poniros, https://github.com/nponiros
 *
 * ==========================================================================
 *
 * Version {version}, {date}
 *
 * https://dexie.org
 *
 * Apache License Version 2.0, January 2004, http://www.apache.org/licenses/
 * 
 */

import Dexie from "dexie";
// Depend on 'dexie-observable'
// To support both ES6,AMD,CJS and UMD (plain script), we just import it and then access it as "Dexie.Observable".
// That way, our plugin works in all UMD cases.
// If target platform would only be module based (ES6/AMD/CJS), we could have done 'import Observable from "dexie-observable"'.
import "dexie-observable";

import initSyncableConnect from './syncable-connect';
import initConnectFn from './connect-fn';
import {Statuses, StatusTexts} from './statuses';

var override = Dexie.override,
    Promise = Dexie.Promise,
    Observable = Dexie.Observable;

/** Dexie addon for remote database sync.
 * 
 * @param {Dexie} db 
 */
function Syncable (db) {
    if (!/^(3|4)\./.test(Dexie.version))
        throw new Error(`Missing dexie version 3.x or 4.x`);
    if (!db.observable || (db.observable.version !== "{version}" && !/^(3|4)\./.test(db.observable.version)))
        throw new Error(`Missing dexie-observable version 3.x or 4.x`);
    if (db.syncable) {
        if (db.syncable.version !== "{version}") throw new Error(`Mixed versions of dexie-syncable: "{version}" vs "${db.syncable.version}"`);
        return; // Addon already active.
    }

    var activePeers = [];

    const connectFn = initConnectFn(db, activePeers);
    const syncableConnect = initSyncableConnect(db, connectFn);

    db.on('message', function(msg) {
        // Message from other local node arrives...
        Dexie.vip(function() {
            if (msg.type === 'connect') {
                // We are master node and another non-master node wants us to do the connect.
                db.syncable.connect(msg.message.protocolName, msg.message.url, msg.message.options).then(msg.resolve, msg.reject);
            } else if (msg.type === 'disconnect') {
                db.syncable.disconnect(msg.message.url).then(msg.resolve, msg.reject);
            } else if (msg.type === 'syncStatusChanged') {
                // We are client and a master node informs us about syncStatus change.
                // Lookup the connectedProvider and call its event
                db.syncable.on.statusChanged.fire(msg.message.newStatus, msg.message.url);
            }
        });
    });

    db.on('cleanup', function(weBecameMaster) {
        // A cleanup (done in Dexie.Observable) may result in that a master node is removed and we become master.
        if (weBecameMaster) {
            // We took over the master role in Observable's cleanup method.
            // We should connect to remote servers now.
            // At this point, also reconnect servers with status ERROR_WILL_RETRY as well as plain ERROR.
            // Reason to reconnect to those with plain "ERROR" is that the ERROR state may occur when a database
            // connection has been closed. The new master would then be expected to reconnect.
            // Also, this is not an infinite poll(). This is rare event that a new browser tab takes over from
            // an old closed one. 
            Dexie.ignoreTransaction(()=>Dexie.vip(()=>{
                return db._syncNodes.where({type: 'remote'})
                    .filter(node => node.status !== Statuses.OFFLINE)
                    .toArray(connectedRemoteNodes => Promise.all(connectedRemoteNodes.map(node => 
                        db.syncable.connect(node.syncProtocol, node.url, node.syncOptions).catch(e => {
                            console.warn(`Dexie.Syncable: Could not connect to ${node.url}. ${e.stack || e}`);
                        })
                    )));
            })).catch('DatabaseClosedError', ()=>{});
        }
    });

    // "ready" subscriber for the master node that makes sure it will always connect to sync server
    // when the database opens. It will not wait for the connection to complete, just initiate the
    // connection so that it will continue syncing as long as the database is open.

    // Dexie.Observable's 'ready' subscriber will have been invoked prior to this, making sure
    // that db._localSyncNode exists and persisted before this subscriber kicks in.
    db.on('ready', function onReady() {
        // Again, in onReady: If we ARE master, make sure to connect to remote servers that is in a connected state.
        if (db._localSyncNode && db._localSyncNode.isMaster) {
            // Make sure to connect to remote servers that is in a connected state (NOT OFFLINE or ERROR!)
            // This "ready" subscriber will never be the one performing the initial sync request, because
            // even after calling db.syncable.connect(), there won't exist any "remote" sync node yet.
            // Instead, db.syncable.connect() will subscribe to "ready" also, and that subscriber will be
            // called after this one. There, in that subscriber, the initial sync request will take place
            // and the "remote" node will be created so that this "ready" subscriber can auto-connect the
            // next time this database is opened.
            // CONCLUSION: We can always assume that the local DB has been in sync with the server at least
            // once in the past for each "connectedRemoteNode" we find in query below.

            // Don't halt db.ready while connecting (i.e. we do not return a promise here!)
            db._syncNodes
                .where('type').equals('remote')
                .and(node => node.status !== Statuses.OFFLINE)
                .toArray(connectedRemoteNodes => {
                    // There are connected remote nodes that we must manage (or take over to manage)
                    connectedRemoteNodes.forEach(
                            node => db.syncable.connect(
                                node.syncProtocol,
                                node.url,
                                node.syncOptions)     
                            .catch (()=>{}) // A failure will be triggered in on('statusChanged'). We can ignore.
                    );
                }).catch('DatabaseClosedError', ()=>{});
        }
    }, true); // True means the ready event will survive a db reopen - db.close()/db.open()

    db.syncable = {
        version: "{version}"
    };

    db.syncable.getStatus = function(url, cb) {
        if (db.isOpen()) {
            return Dexie.vip(function() {
                return db._syncNodes.where('url').equals(url).first(function(node) {
                    return node ? node.status : Statuses.OFFLINE;
                });
            }).then(cb);
        } else {
            return Promise.resolve(Syncable.Statuses.OFFLINE).then(cb);
        }
    };

    db.syncable.getOptions = function(url, cb) {
        return db.transaction('r?', db._syncNodes, () => {
            return db._syncNodes.where('url').equals(url).first(function(node) {
                return node.syncOptions;
            }).then(cb);
        });
    };

    db.syncable.list = function() {
        return db.transaction('r?', db._syncNodes, ()=>{
            return db._syncNodes.where('type').equals('remote').toArray(function(a) {
                return a.map(function(node) { return node.url; });
            });
        });
    };

    db.syncable.on = Dexie.Events(db, { statusChanged: "asap" });

    db.syncable.disconnect = function(url) {
        return Dexie.ignoreTransaction(()=>{
            return Promise.resolve().then(()=>{
                if (db._localSyncNode && db._localSyncNode.isMaster) {
                    return Promise.all(activePeers.filter(peer => peer.url === url).map(peer => {
                        return peer.disconnect(Statuses.OFFLINE);
                    }));
                } else {
                    return db._syncNodes.where('isMaster').above(0).first(masterNode => {
                        return db.observable.sendMessage('disconnect', { url: url }, masterNode.id, {wantReply: true});
                    });
                }
            }).then(()=>{
                return db._syncNodes.where("url").equals(url).modify(node => {
                    node.status = Statuses.OFFLINE;
                });
            });
        });
    };

    db.syncable.connect = function(protocolName, url, options) {
        options = options || {}; // Make sure options is always an object because 1) Provider expects it to be. 2) We'll be persisting it and you cannot persist undefined.
        var protocolInstance = Syncable.registeredProtocols[protocolName];
        if (protocolInstance) {
            return syncableConnect(protocolInstance, protocolName, url, options);
        } else {
            return Promise.reject(
                new Error("ISyncProtocol '" + protocolName + "' is not registered in Dexie.Syncable.registerSyncProtocol()")
            );
        }
    };

    db.syncable.delete = function(url) {
        return db.syncable.disconnect(url).then(()=>{
            return db.transaction('rw!', db._syncNodes, db._changes, db._uncommittedChanges, ()=>{
                // Find the node(s)
                // Several can be found, as detected by @martindiphoorn,
                // let's delete them and cleanup _uncommittedChanges and _changes 
                // accordingly.
                let nodeIDsToDelete;
                return db._syncNodes
                    .where("url").equals(url)
                    .toArray(nodes => nodes.map(node => node.id))
                    .then(nodeIDs => {
                        nodeIDsToDelete = nodeIDs;
                        // Delete the syncNode that represents the remote endpoint.
                        return db._syncNodes.where('id').anyOf(nodeIDs).delete()
                    })
                    .then (() =>
                        // In case there were uncommittedChanges belonging to this, delete them as well
                        db._uncommittedChanges.where('node').anyOf(nodeIDsToDelete).delete());
            }).then(()=> {
                // Spawn background job to delete old changes, now that a node has been deleted,
                // there might be changes in _changes table that is not needed to keep anymore.
                // This is done in its own transaction, or possible several transaction to prohibit
                // starvation
                Observable.deleteOldChanges(db);
            });
        });
    };

    db.syncable.unsyncedChanges = function(url) {
        return db._syncNodes.where("url").equals(url).first(function(node) {
            return db._changes.where('rev').above(node.myRevision).toArray();
        });
    };

    db.close = override(db.close, function(origClose) {
        return function() {
            activePeers.forEach(function(peer) {
                peer.disconnect();
            });
            return origClose.apply(this, arguments);
        };
    });

    Object.defineProperty(
        db.observable.SyncNode.prototype,
        'save', {
            enumerable: false,
            configurable: true,
            writable: true,
            value() {
                return db.transaction('rw?', db._syncNodes, () => {
                    return db._syncNodes.put(this);
            });
        }
     });
}

Syncable.version = "{version}";

Syncable.Statuses = Statuses;

Syncable.StatusTexts = StatusTexts;

Syncable.registeredProtocols = {}; // Map<String,ISyncProviderFactory> when key is the provider name.

Syncable.registerSyncProtocol = function(name, protocolInstance) {
    /// <summary>
    ///    Register a synchronization protocol that can synchronize databases with remote servers.
    /// </summary>
    /// <param name="name" type="String">Provider name</param>
    /// <param name="protocolInstance" type="ISyncProtocol">Implementation of ISyncProtocol</param>
    const partialsThreshold = protocolInstance.partialsThreshold;
    if (typeof partialsThreshold === 'number') {
        // Don't allow NaN or negative threshold
        if (isNaN(partialsThreshold) || partialsThreshold < 0) {
            throw new Error('The given number for the threshold is not supported');
        }
        // If the threshold is 0 we will not send any client changes but will get server changes
    } else {
        // Use Infinity as the default so simple protocols don't have to care about partial synchronization
        protocolInstance.partialsThreshold = Infinity;
    }
    Syncable.registeredProtocols[name] = protocolInstance;
};

if (Dexie.Syncable) {
    if (Dexie.Syncable.version !== "{version}") {
        throw new Error (`Mixed versions of dexie-syncable: "{version}" vs "${Dexie.Syncable.version}"`);
    }
} else {
    // Register addon in Dexie:
    Dexie.Syncable = Syncable;
    Dexie.addons.push(Syncable);
}

export default Dexie.Syncable;


================================================
FILE: addons/Dexie.Syncable/src/PersistedContext.js
================================================
import Dexie from 'dexie';

export default function initPersistedContext(node) {
  //
  // PersistedContext : IPersistedContext
  //
  return class PersistedContext {
    constructor(nodeID, otherProps) {
      this.nodeID = nodeID;
      if (otherProps) Dexie.extend(this, otherProps);
    }

    save() {
      // Store this instance in the syncContext property of the node it belongs to.
      return Dexie.vip(() => {
        return node.save();
      });
    }
  }
}


================================================
FILE: addons/Dexie.Syncable/src/apply-changes.js
================================================
import { CREATE, DELETE, UPDATE } from './change_types';
import bulkUpdate from './bulk-update';

export default function initApplyChanges(db) {
  return function applyChanges(changes) {
    let collectedChanges = {};
    changes.forEach((change) => {
      if (!collectedChanges.hasOwnProperty(change.table)) {
        collectedChanges[change.table] = { [CREATE]: [], [DELETE]: [], [UPDATE]: [] };
      }
      collectedChanges[change.table][change.type].push(change);
    });
    let table_names = Object.keys(collectedChanges);
    let tables = table_names.map((table) => db.table(table));

    return db.transaction("rw", tables, () => {
      table_names.forEach((table_name) => {
        const table = db.table(table_name);
        const specifyKeys = !table.schema.primKey.keyPath;
        const createChangesToApply = collectedChanges[table_name][CREATE];
        const deleteChangesToApply = collectedChanges[table_name][DELETE];
        const updateChangesToApply = collectedChanges[table_name][UPDATE];
        if (createChangesToApply.length > 0)
          table.bulkPut(createChangesToApply.map(c => c.obj), specifyKeys ?
            createChangesToApply.map(c => c.key) : undefined);
        if (updateChangesToApply.length > 0)
          bulkUpdate(table, updateChangesToApply);
        if (deleteChangesToApply.length > 0)
          table.bulkDelete(deleteChangesToApply.map(c => c.key));
      });
    });
  };
}


================================================
FILE: addons/Dexie.Syncable/src/bulk-update.js
================================================
import Dexie from 'dexie';

export default function bulkUpdate(table, changes) {
  let keys = changes.map(c => c.key);
  let map = {};
  // Retrieve current object of each change to update and map each
  // found object's primary key to the existing object:
  return table.where(':id').anyOf(keys).raw().each((obj, cursor) => {
    map[cursor.primaryKey+''] = obj;
  }).then(()=>{
    // Filter away changes whose key wasn't found in the local database
    // (we can't update them if we do not know the existing values)
    let updatesThatApply = changes.filter(c => map.hasOwnProperty(c.key+''));
    // Apply modifications onto each existing object (in memory)
    // and generate array of resulting objects to put using bulkPut():
    let objsToPut = updatesThatApply.map (c => {
      let curr = map[c.key+''];
      Object.keys(c.mods).forEach(keyPath => {
        Dexie.setByKeyPath(curr, keyPath, c.mods[keyPath]);
      });
      return curr;
    });
    return table.bulkPut(objsToPut);
  });
}


================================================
FILE: addons/Dexie.Syncable/src/change_types.js
================================================
// Change Types
export const CREATE = 1;
export const UPDATE = 2;
export const DELETE = 3;


================================================
FILE: addons/Dexie.Syncable/src/combine-create-and-update.js
================================================
import Dexie from 'dexie';

export default function combineCreateAndUpdate(prevChange, nextChange) {
  var clonedChange = Dexie.deepClone(prevChange); // Clone object before modifying since the earlier change in db.changes[] would otherwise be altered.
  Object.keys(nextChange.mods).forEach(function (keyPath) {
    Dexie.setByKeyPath(clonedChange.obj, keyPath, nextChange.mods[keyPath]);
  });
  return clonedChange;
}


================================================
FILE: addons/Dexie.Syncable/src/combine-update-and-update.js
================================================
import Dexie from 'dexie';

export default function combineUpdateAndUpdate(prevChange, nextChange) {
  var clonedChange = Dexie.deepClone(prevChange); // Clone object before modifying since the earlier change in db.changes[] would otherwise be altered.
  Object.keys(nextChange.mods).forEach(function (keyPath) {
    // If prev-change was changing a parent path of this keyPath, we must update the parent path rather than adding this keyPath
    var hadParentPath = false;
    Object.keys(prevChange.mods).filter(function (parentPath) { return keyPath.indexOf(parentPath + '.') === 0; }).forEach(function (parentPath) {
      Dexie.setByKeyPath(clonedChange.mods[parentPath], keyPath.substr(parentPath.length + 1), nextChange.mods[keyPath]);
      hadParentPath = true;
    });
    if (!hadParentPath) {
      // Add or replace this keyPath and its new value
      clonedChange.mods[keyPath] = nextChange.mods[keyPath];
    }
    // In case prevChange contained sub-paths to the new keyPath, we must make sure that those sub-paths are removed since
    // we must mimic what would happen if applying the two changes after each other:
    Object.keys(prevChange.mods).filter(function (subPath) { return subPath.indexOf(keyPath + '.') === 0; }).forEach(function (subPath) {
      delete clonedChange.mods[subPath];
    });
  });
  return clonedChange;
}


================================================
FILE: addons/Dexie.Syncable/src/connect-fn.js
================================================
import Dexie from 'dexie';

import initGetOrCreateSyncNode from './get-or-create-sync-node';
import initConnectProtocol from './connect-protocol';
import {Statuses} from './statuses';

export default function initConnectFn(db, activePeers) {
  return function connect(protocolInstance, protocolName, url, options, dbAliveID) {
    /// <param name="protocolInstance" type="ISyncProtocol"></param>
    var existingPeer = activePeers.filter(function (peer) {
      return peer.url === url;
    });
    if (existingPeer.length > 0) {
      const activePeer = existingPeer[0];
      const diffObject = {};
      Dexie.getObjectDiff(activePeer.syncOptions, options, diffObject);
      // Options have been changed
      // We need to disconnect and reconnect
      if (Object.keys(diffObject).length !== 0) {
        return db.syncable.disconnect(url)
          .then(() => {
            return execConnect();
          })
      } else {
        // Never create multiple syncNodes with same protocolName and url. Instead, let the next call to connect() return the same promise that
        // have already been started and eventually also resolved. If promise has already resolved (node connected), calling existing promise.then() will give a callback directly.
        return existingPeer[0].connectPromise;
      }
    }

    function execConnect() {
      // Use an object otherwise we wouldn't be able to get the reject promise from
      // connectProtocol
      var rejectConnectPromise = {p: null};
      const connectProtocol = initConnectProtocol(db, protocolInstance, dbAliveID, options, rejectConnectPromise);
      const getOrCreateSyncNode = initGetOrCreateSyncNode(db, protocolName, url);
      var connectPromise = getOrCreateSyncNode(options).then(function (node) {
        return connectProtocol(node, activePeer);
      });

      var disconnected = false;
      var activePeer = {
        url: url,
        status: Statuses.OFFLINE,
        connectPromise: connectPromise,
        syncOptions: options,
        on: Dexie.Events(null, "disconnect"),
        disconnect: function (newStatus, error) {
          var pos = activePeers.indexOf(activePeer);
          if (pos >= 0) activePeers.splice(pos, 1);
          if (error && rejectConnectPromise.p) rejectConnectPromise.p(error);
          if (!disconnected) {
            activePeer.on.disconnect.fire(newStatus, error);
          }
          disconnected = true;
        }
      };
      activePeers.push(activePeer);

      return connectPromise;
    }

    return execConnect();
  };
}


================================================
FILE: addons/Dexie.Syncable/src/connect-protocol.js
================================================
import Dexie from 'dexie';

import initEnqueue from './enqueue';
import initSaveToUncommittedChanges from './save-to-uncommitted-changes';
import initFinallyCommitAllChanges from './finally-commit-all-changes';
import initGetLocalChangesForNode from './get-local-changes-for-node/get-local-changes-for-node';
import {Statuses} from './statuses';

const Promise = Dexie.Promise;

export default function initConnectProtocol(db, protocolInstance, dbAliveID, options, rejectConnectPromise) {
  const enqueue = initEnqueue(db);
  var hasMoreToGive = {hasMoreToGive: true};

  function stillAlive() {
    // A better method than doing db.isOpen() because the same db instance may have been reopened, but then this sync call should be dead
    // because the new instance should be considered a fresh instance and will have another local node.
    return db._localSyncNode && db._localSyncNode.id === dbAliveID;
  }

  return function connectProtocol(node, activePeer) {
    /// <param name="node" type="db.observable.SyncNode"></param>
    const getLocalChangesForNode = initGetLocalChangesForNode(db, hasMoreToGive, protocolInstance.partialsThreshold);

    const url = activePeer.url;

    function changeStatusTo(newStatus) {
      if (node.status !== newStatus) {
        node.status = newStatus;
        node.save().then(()=> {
          db.syncable.on.statusChanged.fire(newStatus, url);
          // Also broadcast message to other nodes about the status
          db.observable.broadcastMessage("syncStatusChanged", {newStatus: newStatus, url: url}, false);
        }).catch('DatabaseClosedError', ()=> {
        });
      }
    }

    activePeer.on('disconnect', function (newStatus) {
      if (!isNaN(newStatus)) changeStatusTo(newStatus);
    });

    var connectedContinuation;
    changeStatusTo(Statuses.CONNECTING);
    return doSync();

    function doSync() {
      // Use enqueue() to ensure only a single promise execution at a time.
      return enqueue(doSync, function () {
        // By returning the Promise returned by getLocalChangesForNode() a final catch() on the sync() method will also catch error occurring in entire sequence.
        return getLocalChangesForNode_autoAckIfEmpty(node, sendChangesToProvider);
      }, dbAliveID);
    }

    function sendChangesToProvider(changes, remoteBaseRevision, partial, nodeModificationsOnAck) {
      // Create a final Promise for the entire sync() operation that will resolve when provider calls onSuccess().
      // By creating finalPromise before calling protocolInstance.sync() it is possible for provider to call onError() immediately if it wants.
      var finalSyncPromise = new Promise(function (resolve, reject) {
        rejectConnectPromise.p = function (err) {
          reject(err);
        };
        Dexie.asap(function () {
          try {
            protocolInstance.sync(
                node.syncContext,
                url,
                options,
                remoteBaseRevision,
                node.appliedRemoteRevision,
                changes,
                partial,
                applyRemoteChanges,
                onChangesAccepted,
                function (continuation) {
                  resolve(continuation);
                },
                onError);
          } catch (ex) {
            onError(ex, Infinity);
          }

          function onError(error, again) {
            reject(error);
            if (stillAlive()) {
              if (!isNaN(again) && again < Infinity) {
                setTimeout(function () {
                  if (stillAlive()) {
                    changeStatusTo(Statuses.SYNCING);
                    doSync().catch('DatabaseClosedError', abortTheProvider);
                  }
                }, again);
                changeStatusTo(Statuses.ERROR_WILL_RETRY, error);
                if (connectedContinuation && connectedContinuation.disconnect) connectedContinuation.disconnect();
                connectedContinuation = null;
              } else {
                abortTheProvider(error); // Will fire ERROR on statusChanged event.
              }
            }
          }
        });
      });

      return finalSyncPromise.then(function () {
        // Resolve caller of db.syncable.connect() with undefined. Not with continuation!
        return undefined;
      }).finally(()=> {
        // In case error happens after connect, don't try reject the connect promise anymore.
        // This is important. A Dexie unit test that verifies unhandled rejections will fail when Dexie.Syncable addon
        // is active and this happens. It would fire unhandledrejection but that we do not want.
        rejectConnectPromise.p = null;
      });

      function onChangesAccepted() {
        Object.keys(nodeModificationsOnAck).forEach(function (keyPath) {
          Dexie.setByKeyPath(node, keyPath, nodeModificationsOnAck[keyPath]);
        });
        // We dont know if onSuccess() was called by provider yet. If it's already called, finalPromise.then() will execute immediately,
        // otherwise it will execute when finalSyncPromise resolves.
        finalSyncPromise.then(continueSendingChanges);
        return node.save();
      }
    }

    function abortTheProvider(error) {
      activePeer.disconnect(Statuses.ERROR, error);
    }

    function getLocalChangesForNode_autoAckIfEmpty(node, cb) {
      return getLocalChangesForNode(node, function autoAck(changes, remoteBaseRevision, partial, nodeModificationsOnAck) {
        if (changes.length === 0 && 'myRevision' in nodeModificationsOnAck && nodeModificationsOnAck.myRevision !== node.myRevision) {
          Object.keys(nodeModificationsOnAck).forEach(function (keyPath) {
            Dexie.setByKeyPath(node, keyPath, nodeModificationsOnAck[keyPath]);
          });
          node.save().catch('Da
Download .txt
gitextract_2syan8s_/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── dexie-cloud-common.yml
│       └── main.yml
├── .gitignore
├── .npmignore
├── .npmrc
├── .prettierrc
├── .prettierrc.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── NOTICE
├── README.md
├── SECURITY.md
├── addons/
│   ├── Dexie.Observable/
│   │   ├── .gitignore
│   │   ├── .npmignore
│   │   ├── README.md
│   │   ├── api.d.ts
│   │   ├── api.js
│   │   ├── dist/
│   │   │   └── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── .eslintrc.json
│   │   │   ├── Dexie.Observable.d.ts
│   │   │   ├── Dexie.Observable.js
│   │   │   ├── change_types.js
│   │   │   ├── delete-old-changes.js
│   │   │   ├── hooks/
│   │   │   │   ├── creating.js
│   │   │   │   ├── crud-monitor.js
│   │   │   │   ├── deleting.js
│   │   │   │   └── updating.js
│   │   │   ├── intercomm.js
│   │   │   ├── on-storage.js
│   │   │   ├── override-create-transaction.js
│   │   │   ├── override-open.js
│   │   │   ├── override-parse-stores-spec.js
│   │   │   ├── utils.js
│   │   │   └── wakeup-observers.js
│   │   ├── test/
│   │   │   ├── gh-actions.sh
│   │   │   ├── integration/
│   │   │   │   ├── karma-env.js
│   │   │   │   ├── karma.conf.js
│   │   │   │   └── test-observable-dexie-tests.html
│   │   │   ├── typings/
│   │   │   │   ├── test-typings.ts
│   │   │   │   └── tsconfig.json
│   │   │   └── unit/
│   │   │       ├── .eslintrc.json
│   │   │       ├── .gitignore
│   │   │       ├── deep-equal.js
│   │   │       ├── hooks/
│   │   │       │   ├── tests-creating.js
│   │   │       │   ├── tests-deleting.js
│   │   │       │   └── tests-updating.js
│   │   │       ├── karma.conf.js
│   │   │       ├── run-unit-tests.html
│   │   │       ├── tests-observable-misc.js
│   │   │       ├── tests-override-open.js
│   │   │       ├── tests-override-parse-stores-spec.js
│   │   │       └── unit-tests-all.js
│   │   └── tools/
│   │       ├── build-configs/
│   │       │   ├── banner.txt
│   │       │   ├── rollup.config.mjs
│   │       │   ├── rollup.tests.config.js
│   │       │   ├── rollup.tests.config.mjs
│   │       │   ├── rollup.tests.unit.config.js
│   │       │   └── rollup.tests.unit.config.mjs
│   │       └── replaceVersionAndDate.js
│   ├── Dexie.Syncable/
│   │   ├── .gitignore
│   │   ├── .npmignore
│   │   ├── README.md
│   │   ├── api.d.ts
│   │   ├── api.js
│   │   ├── dist/
│   │   │   └── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── .eslintrc.json
│   │   │   ├── Dexie.Syncable.d.ts
│   │   │   ├── Dexie.Syncable.js
│   │   │   ├── PersistedContext.js
│   │   │   ├── apply-changes.js
│   │   │   ├── bulk-update.js
│   │   │   ├── change_types.js
│   │   │   ├── combine-create-and-update.js
│   │   │   ├── combine-update-and-update.js
│   │   │   ├── connect-fn.js
│   │   │   ├── connect-protocol.js
│   │   │   ├── enqueue.js
│   │   │   ├── finally-commit-all-changes.js
│   │   │   ├── get-local-changes-for-node/
│   │   │   │   ├── get-base-revision-and-max-client-revision.js
│   │   │   │   ├── get-changes-since-revision.js
│   │   │   │   ├── get-local-changes-for-node.js
│   │   │   │   └── get-table-objects-as-changes.js
│   │   │   ├── get-or-create-sync-node.js
│   │   │   ├── merge-change.js
│   │   │   ├── save-to-uncommitted-changes.js
│   │   │   ├── statuses.js
│   │   │   └── syncable-connect.js
│   │   ├── test/
│   │   │   ├── gh-actions.sh
│   │   │   ├── integration/
│   │   │   │   ├── dummy-sync-protocol.js
│   │   │   │   ├── karma-env.js
│   │   │   │   ├── karma.conf.js
│   │   │   │   └── test-syncable-dexie-tests.html
│   │   │   ├── test-typings/
│   │   │   │   ├── test-typings.ts
│   │   │   │   └── tsconfig.json
│   │   │   └── unit/
│   │   │       ├── .eslintrc.json
│   │   │       ├── .gitignore
│   │   │       ├── get-local-changes-for-node/
│   │   │       │   ├── tests-get-base-revision-and-max-client-revision.js
│   │   │       │   ├── tests-get-changes-since-revision.js
│   │   │       │   └── tests-get-local-changes-for-node.js
│   │   │       ├── karma-env.js
│   │   │       ├── karma.conf.js
│   │   │       ├── run-unit-tests.html
│   │   │       ├── tests-PersistedContext.js
│   │   │       ├── tests-WebSocketSyncServer.js
│   │   │       ├── tests-apply-changes.js
│   │   │       ├── tests-bulk-update.js
│   │   │       ├── tests-changing-options.js
│   │   │       ├── tests-combine-create-and-update.js
│   │   │       ├── tests-combine-update-and-update.js
│   │   │       ├── tests-finally-commit-all-changes.js
│   │   │       ├── tests-get-or-create-sync-node.js
│   │   │       ├── tests-merge-change.js
│   │   │       ├── tests-register-sync-protocol.js
│   │   │       ├── tests-save-to-uncommitted-changes.js
│   │   │       ├── tests-syncable-partials.js
│   │   │       ├── tests-syncable.js
│   │   │       ├── tests-syncprovider.js
│   │   │       └── unit-tests-all.js
│   │   └── tools/
│   │       ├── build-configs/
│   │       │   ├── banner.txt
│   │       │   ├── rollup.config.mjs
│   │       │   ├── rollup.tests.config.js
│   │       │   └── rollup.tests.config.mjs
│   │       └── replaceVersionAndDate.js
│   ├── dexie-cloud/
│   │   ├── .gitignore
│   │   ├── .npmignore
│   │   ├── .vscode/
│   │   │   └── settings.json
│   │   ├── README.md
│   │   ├── TODO-SOCIALAUTH.md
│   │   ├── dexie-cloud-import.json
│   │   ├── oauth_flow.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── DISABLE_SERVICEWORKER_STRATEGY.ts
│   │   │   ├── DXCWebSocketStatus.ts
│   │   │   ├── DexieCloudAPI.ts
│   │   │   ├── DexieCloudOptions.ts
│   │   │   ├── DexieCloudSyncOptions.ts
│   │   │   ├── DexieCloudTable.ts
│   │   │   ├── InvalidLicenseError.ts
│   │   │   ├── Invite.ts
│   │   │   ├── PermissionChecker.ts
│   │   │   ├── TSON.ts
│   │   │   ├── WSObservable.ts
│   │   │   ├── associate.ts
│   │   │   ├── authentication/
│   │   │   │   ├── AuthPersistedContext.ts
│   │   │   │   ├── TokenErrorResponseError.ts
│   │   │   │   ├── TokenExpiredError.ts
│   │   │   │   ├── UNAUTHORIZED_USER.ts
│   │   │   │   ├── authenticate.ts
│   │   │   │   ├── currentUserObservable.ts
│   │   │   │   ├── exchangeOAuthCode.ts
│   │   │   │   ├── fetchAuthProviders.ts
│   │   │   │   ├── handleOAuthCallback.ts
│   │   │   │   ├── interactWithUser.ts
│   │   │   │   ├── login.ts
│   │   │   │   ├── logout.ts
│   │   │   │   ├── oauthLogin.ts
│   │   │   │   ├── otpFetchTokenCallback.ts
│   │   │   │   ├── setCurrentUser.ts
│   │   │   │   └── waitUntil.ts
│   │   │   ├── computeSyncState.ts
│   │   │   ├── createSharedValueObservable.ts
│   │   │   ├── currentUserEmitter.ts
│   │   │   ├── db/
│   │   │   │   ├── DexieCloudDB.ts
│   │   │   │   └── entities/
│   │   │   │       ├── BaseRevisionMapEntry.ts
│   │   │   │       ├── EntityCommon.ts
│   │   │   │       ├── GuardedJob.ts
│   │   │   │       ├── Member.ts
│   │   │   │       ├── PersistedSyncState.ts
│   │   │   │       ├── Realm.ts
│   │   │   │       ├── Role.ts
│   │   │   │       └── UserLogin.ts
│   │   │   ├── default-ui/
│   │   │   │   ├── Dialog.tsx
│   │   │   │   ├── LoginDialog.tsx
│   │   │   │   ├── OptionButton.tsx
│   │   │   │   ├── Styles.ts
│   │   │   │   └── index.tsx
│   │   │   ├── define-ydoc-trigger.ts
│   │   │   ├── dexie-cloud-addon.ts
│   │   │   ├── dexie-cloud-client.ts
│   │   │   ├── errors/
│   │   │   │   ├── HttpError.ts
│   │   │   │   ├── OAuthError.ts
│   │   │   │   └── OAuthRedirectError.ts
│   │   │   ├── extend-dexie-interface.ts
│   │   │   ├── getGlobalRolesObservable.ts
│   │   │   ├── getInternalAccessControlObservable.ts
│   │   │   ├── getInvitesObservable.ts
│   │   │   ├── getPermissionsLookupObservable.ts
│   │   │   ├── getTiedRealmId.ts
│   │   │   ├── helpers/
│   │   │   │   ├── BroadcastedAndLocalEvent.ts
│   │   │   │   ├── CancelToken.ts
│   │   │   │   ├── IS_SERVICE_WORKER.ts
│   │   │   │   ├── SWBroadcastChannel.ts
│   │   │   │   ├── allSettled.ts
│   │   │   │   ├── bulkUpdate.ts
│   │   │   │   ├── computeRealmSetHash.ts
│   │   │   │   ├── date-constants.ts
│   │   │   │   ├── flatten.ts
│   │   │   │   ├── getMutationTable.ts
│   │   │   │   ├── getSyncableTables.ts
│   │   │   │   ├── getTableFromMutationTable.ts
│   │   │   │   ├── makeArray.ts
│   │   │   │   ├── randomString.ts
│   │   │   │   ├── resolveText.ts
│   │   │   │   ├── throwVersionIncrementNeeded.ts
│   │   │   │   └── visibilityState.ts
│   │   │   ├── isEagerSyncDisabled.ts
│   │   │   ├── isFirefox.ts
│   │   │   ├── isSafari.ts
│   │   │   ├── mapValueObservable.ts
│   │   │   ├── mergePermissions.ts
│   │   │   ├── middleware-helpers/
│   │   │   │   ├── guardedTable.ts
│   │   │   │   └── idGenerationHelpers.ts
│   │   │   ├── middlewares/
│   │   │   │   ├── blobResolveMiddleware.ts
│   │   │   │   ├── createIdGenerationMiddleware.ts
│   │   │   │   ├── createImplicitPropSetterMiddleware.ts
│   │   │   │   ├── createMutationTrackingMiddleware.ts
│   │   │   │   └── outstandingTransaction.ts
│   │   │   ├── overrideParseStoresSpec.ts
│   │   │   ├── performInitialSync.ts
│   │   │   ├── permissions.ts
│   │   │   ├── prodLog.ts
│   │   │   ├── service-worker.ts
│   │   │   ├── sync/
│   │   │   │   ├── BLOB_TODO.md
│   │   │   │   ├── BlobDownloadTracker.ts
│   │   │   │   ├── BlobSavingQueue.ts
│   │   │   │   ├── DEXIE_CLOUD_SYNCER_ID.ts
│   │   │   │   ├── LocalSyncWorker.ts
│   │   │   │   ├── SyncRequiredError.ts
│   │   │   │   ├── applyServerChanges.ts
│   │   │   │   ├── blobOffloading.test.ts
│   │   │   │   ├── blobOffloading.ts
│   │   │   │   ├── blobProgress.ts
│   │   │   │   ├── blobResolve.ts
│   │   │   │   ├── connectWebSocket.ts
│   │   │   │   ├── eagerBlobDownloader.ts
│   │   │   │   ├── encodeIdsForServer.ts
│   │   │   │   ├── extractRealm.ts
│   │   │   │   ├── getLatestRevisionsPerTable.ts
│   │   │   │   ├── getTablesToSyncify.ts
│   │   │   │   ├── isOnline.ts
│   │   │   │   ├── isSyncNeeded.ts
│   │   │   │   ├── listClientChanges.ts
│   │   │   │   ├── listSyncifiedChanges.ts
│   │   │   │   ├── loadCachedAccessToken.ts
│   │   │   │   ├── messageConsumerIsReady.ts
│   │   │   │   ├── messagesFromServerQueue.ts
│   │   │   │   ├── modifyLocalObjectsWithNewUserId.ts
│   │   │   │   ├── myId.ts
│   │   │   │   ├── numUnsyncedMutations.ts
│   │   │   │   ├── old_startSyncingClientChanges.ts
│   │   │   │   ├── performGuardedJob.ts
│   │   │   │   ├── ratelimit.ts
│   │   │   │   ├── registerSyncEvent.ts
│   │   │   │   ├── sync.ts
│   │   │   │   ├── syncIfPossible.ts
│   │   │   │   ├── syncWithServer.ts
│   │   │   │   ├── triggerSync.ts
│   │   │   │   └── updateBaseRevs.ts
│   │   │   ├── tsconfig.json
│   │   │   ├── types/
│   │   │   │   ├── DXCAlert.ts
│   │   │   │   ├── DXCInputField.ts
│   │   │   │   ├── DXCUserInteraction.ts
│   │   │   │   ├── NewIdOptions.ts
│   │   │   │   ├── SWMessageEvent.ts
│   │   │   │   ├── SWSyncEvent.ts
│   │   │   │   ├── SyncState.ts
│   │   │   │   └── TXExpandos.ts
│   │   │   ├── updateSchemaFromOptions.ts
│   │   │   ├── userIsActive.ts
│   │   │   ├── verifyConfig.ts
│   │   │   ├── verifySchema.ts
│   │   │   └── yjs/
│   │   │       ├── YDexieCloudSyncState.ts
│   │   │       ├── YTable.ts
│   │   │       ├── applyYMessages.ts
│   │   │       ├── awareness.ts
│   │   │       ├── createYClientUpdateObservable.ts
│   │   │       ├── createYHandler.ts
│   │   │       ├── downloadYDocsFromServer.ts
│   │   │       ├── getUpdatesTable.ts
│   │   │       ├── listUpdatesSince.ts
│   │   │       ├── listYClientMessagesAndStateVector.ts
│   │   │       ├── reopenDocSignal.ts
│   │   │       └── updateYSyncStates.ts
│   │   ├── test/
│   │   │   ├── promisedTest.ts
│   │   │   ├── qunit.d.ts
│   │   │   ├── tsconfig.json
│   │   │   └── unit/
│   │   │       ├── index.ts
│   │   │       ├── karma-env.js
│   │   │       ├── karma.conf.cjs
│   │   │       ├── run-unit-tests.html
│   │   │       ├── test-dexie-cloud-client.ts
│   │   │       ├── tests-github-issues.ts
│   │   │       └── tests-migrate-to-cloud.ts
│   │   └── tools/
│   │       ├── build-configs/
│   │       │   ├── banner.txt
│   │       │   ├── rollup.config.mjs
│   │       │   └── rollup.test.unit.config.js
│   │       ├── release-dexie-cloud-addon.sh
│   │       └── replaceVersionAndDate.cjs
│   ├── dexie-export-import/
│   │   ├── .gitignore
│   │   ├── .npmignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── dexie-export-import.ts
│   │   │   ├── export.ts
│   │   │   ├── helpers.ts
│   │   │   ├── import.ts
│   │   │   ├── index.ts
│   │   │   ├── json-stream.ts
│   │   │   ├── json-structure.ts
│   │   │   ├── tsconfig.json
│   │   │   ├── tson-arraybuffer.ts
│   │   │   ├── tson-typed-array.ts
│   │   │   └── tson.ts
│   │   ├── test/
│   │   │   ├── .gitignore
│   │   │   ├── basic-tests.ts
│   │   │   ├── edge-cases.ts
│   │   │   ├── gh-actions.sh
│   │   │   ├── index.html
│   │   │   ├── index.ts
│   │   │   ├── karma.conf.js
│   │   │   ├── qunit.d.ts
│   │   │   ├── test-data.ts
│   │   │   ├── tools.ts
│   │   │   └── tsconfig.json
│   │   └── tools/
│   │       └── build-configs/
│   │           ├── banner.txt
│   │           ├── fake-stream.js
│   │           ├── rollup.config.mjs
│   │           └── rollup.tests.config.mjs
│   └── y-dexie/
│       ├── .gitignore
│       ├── .npmignore
│       ├── README.md
│       ├── package.json
│       ├── src/
│       │   ├── DexieYProvider.ts
│       │   ├── TODO.md
│       │   ├── compressYDocs.ts
│       │   ├── createYDocProperty.ts
│       │   ├── createYjsMiddleware.ts
│       │   ├── currentUpdateRow.ts
│       │   ├── docCache.ts
│       │   ├── getOrCreateDocument.ts
│       │   ├── helpers/
│       │   │   ├── Disposable.ts
│       │   │   ├── hasOwn.ts
│       │   │   ├── nonStoppableEventChain.ts
│       │   │   ├── nop.ts
│       │   │   └── promisableChain.ts
│       │   ├── observeYDocUpdates.ts
│       │   ├── periodicGC.ts
│       │   ├── tsconfig.json
│       │   ├── types/
│       │   │   ├── DexieYDocMeta.ts
│       │   │   ├── YDocCache.ts
│       │   │   ├── YLastCompressed.ts
│       │   │   ├── YSyncState.ts
│       │   │   ├── YUpdateRow.ts
│       │   │   └── index.ts
│       │   └── y-dexie.ts
│       ├── test/
│       │   ├── gh-actions.sh
│       │   ├── promisedTest.ts
│       │   ├── qunit.d.ts
│       │   ├── tsconfig.json
│       │   └── unit/
│       │       ├── dexie-unittest-utils.js
│       │       ├── index.ts
│       │       ├── karma-env.js
│       │       ├── karma.conf.cjs
│       │       ├── run-unit-tests.html
│       │       ├── tests-dummy.ts
│       │       └── tests-yjs.ts
│       └── tools/
│           ├── build-configs/
│           │   ├── banner.txt
│           │   ├── rollup.config.mjs
│           │   └── rollup.test.unit.config.js
│           ├── release-y-dexie.sh
│           └── replaceVersionAndDate.cjs
├── dist/
│   └── README.md
├── import-wrapper-prod.d.mts
├── import-wrapper-prod.mjs
├── import-wrapper.d.mts
├── import-wrapper.mjs
├── libs/
│   ├── dexie-cloud-common/
│   │   ├── .gitignore
│   │   ├── .npmignore
│   │   ├── jest.config.js
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── AuthProvidersResponse.ts
│   │   │   ├── AuthorizationCodeTokenRequest.ts
│   │   │   ├── BaseRevisionMapEntry.ts
│   │   │   ├── DBOperation.ts
│   │   │   ├── DBOperationsSet.ts
│   │   │   ├── DBPermissionSet.ts
│   │   │   ├── DexieCloudSchema.ts
│   │   │   ├── OAuthProviderInfo.ts
│   │   │   ├── SyncChange.ts
│   │   │   ├── SyncChangeSet.ts
│   │   │   ├── SyncRequest.ts
│   │   │   ├── SyncResponse.ts
│   │   │   ├── async-generators/
│   │   │   │   ├── asyncIterablePipeline.ts
│   │   │   │   ├── consumeChunkedBinaryStream.test.ts
│   │   │   │   ├── consumeChunkedBinaryStream.ts
│   │   │   │   ├── getFetchResponseBodyGenerator.ts
│   │   │   │   └── produceChunkedBinaryStream.ts
│   │   │   ├── change-processing/
│   │   │   │   ├── DBKeyMutation.ts
│   │   │   │   ├── DBKeyMutationSet.ts
│   │   │   │   ├── applyOperation.ts
│   │   │   │   ├── applyOperations.ts
│   │   │   │   ├── subtractChanges.ts
│   │   │   │   ├── toDBOperationSet.ts
│   │   │   │   └── toSyncChangeSet.ts
│   │   │   ├── common/
│   │   │   │   ├── _global.ts
│   │   │   │   ├── b64lex.ts
│   │   │   │   ├── base64.ts
│   │   │   │   └── bigint-conversion.ts
│   │   │   ├── entities/
│   │   │   │   ├── DBRealm.ts
│   │   │   │   ├── DBRealmMember.ts
│   │   │   │   ├── DBRealmRole.ts
│   │   │   │   └── DBSyncedObject.ts
│   │   │   ├── getDbNameFromDbUrl.ts
│   │   │   ├── index.ts
│   │   │   ├── newId.ts
│   │   │   ├── tson/
│   │   │   │   ├── FakeBlob.ts
│   │   │   │   ├── FakeFile.ts
│   │   │   │   ├── StreamingSyncProcessor.ts
│   │   │   │   ├── TSONRef.ts
│   │   │   │   ├── TypeDef.ts
│   │   │   │   ├── TypeDefSet.ts
│   │   │   │   ├── TypesonSimplified.ts
│   │   │   │   ├── __tests__/
│   │   │   │   │   ├── TSONRef.test.ts
│   │   │   │   │   ├── TypesonSimplified.test.ts
│   │   │   │   │   ├── encoding.test.ts
│   │   │   │   │   ├── newId.test.ts
│   │   │   │   │   └── undefined.test.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── presets/
│   │   │   │   │   └── builtin.ts
│   │   │   │   ├── readBlobSync.ts
│   │   │   │   ├── readableStreamIterator.ts
│   │   │   │   ├── string2ArrayBuffer.ts
│   │   │   │   └── types/
│   │   │   │       ├── ArrayBuffer.ts
│   │   │   │       ├── Blob.ts
│   │   │   │       ├── BlobRef.ts
│   │   │   │       ├── Date.ts
│   │   │   │       ├── FakeBlob.ts
│   │   │   │       ├── FakeFile.ts
│   │   │   │       ├── File.ts
│   │   │   │       ├── Map.ts
│   │   │   │       ├── Set.ts
│   │   │   │       ├── TypedArray.ts
│   │   │   │       ├── bigint.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── number.ts
│   │   │   │       └── undefined.ts
│   │   │   ├── types.ts
│   │   │   ├── typings/
│   │   │   │   └── TypedArray.ts
│   │   │   ├── utils.ts
│   │   │   ├── validation/
│   │   │   │   ├── isValidSyncableID.ts
│   │   │   │   └── toStringTag.ts
│   │   │   └── yjs/
│   │   │       ├── YMessage.ts
│   │   │       ├── decoding.ts
│   │   │       └── encoding.ts
│   │   └── tsconfig.json
│   ├── dexie-react-hooks/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── rollup.config.mjs
│   │   ├── src/
│   │   │   ├── dexie-react-hooks.ts
│   │   │   ├── index.ts
│   │   │   ├── types/
│   │   │   │   ├── y-dexie.d.ts
│   │   │   │   └── yjs.d.ts
│   │   │   ├── useDocument.ts
│   │   │   ├── useLiveQuery.ts
│   │   │   ├── useObservable.ts
│   │   │   ├── usePermissions.ts
│   │   │   ├── usePromise.ts
│   │   │   ├── useSuspendingLiveQuery.ts
│   │   │   └── useSuspendingObservable.ts
│   │   ├── test/
│   │   │   ├── components/
│   │   │   │   ├── App.tsx
│   │   │   │   ├── ErrorBoundrary.tsx
│   │   │   │   ├── ItemComponent.tsx
│   │   │   │   ├── ItemListComponent.tsx
│   │   │   │   └── ItemLoaderComponent.tsx
│   │   │   ├── db/
│   │   │   │   └── index.ts
│   │   │   ├── gh-actions.sh
│   │   │   ├── index.html
│   │   │   ├── index.ts
│   │   │   ├── karma.conf.js
│   │   │   ├── models/
│   │   │   │   └── Item.ts
│   │   │   ├── tsconfig.json
│   │   │   ├── utils/
│   │   │   │   ├── BinarySemaphore.ts
│   │   │   │   ├── closest.ts
│   │   │   │   ├── sleep.ts
│   │   │   │   ├── timeout.ts
│   │   │   │   ├── waitTilEqual.ts
│   │   │   │   └── waitTilOk.ts
│   │   │   └── webpack.config.js
│   │   ├── tsconfig.json
│   │   └── webpack.config.js
│   └── dexie-svelte-query/
│       ├── .gitignore
│       ├── .npmrc
│       ├── README.md
│       ├── package.json
│       ├── src/
│       │   └── lib/
│       │       ├── index.ts
│       │       └── stateQuery.svelte.ts
│       └── tsconfig.json
├── package.json
├── pnpm-workspace.yaml
├── samples/
│   ├── angular/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── angular.json
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── app.component.ts
│   │   │   │   ├── db.ts
│   │   │   │   └── item-list.component.ts
│   │   │   ├── index.html
│   │   │   └── main.ts
│   │   └── tsconfig.json
│   ├── dexie-cloud-todo-app/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── components.json
│   │   ├── configure-app.sh
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── postcss.config.js
│   │   ├── public/
│   │   │   └── robots.txt
│   │   ├── src/
│   │   │   ├── App.test.tsx
│   │   │   ├── App.tsx
│   │   │   ├── components/
│   │   │   │   ├── AddTodoItem.tsx
│   │   │   │   ├── AddTodoList.tsx
│   │   │   │   ├── ResetDatabaseButton.tsx
│   │   │   │   ├── TodoItemView.tsx
│   │   │   │   ├── TodoListView.tsx
│   │   │   │   ├── TodoLists.tsx
│   │   │   │   ├── access-control/
│   │   │   │   │   ├── EditMember.tsx
│   │   │   │   │   ├── EditMemberAccess.tsx
│   │   │   │   │   ├── Invites.tsx
│   │   │   │   │   └── SharingForm.tsx
│   │   │   │   ├── navbar/
│   │   │   │   │   ├── NavBar.tsx
│   │   │   │   │   └── SyncStatusIcon.tsx
│   │   │   │   └── ui/
│   │   │   │       ├── CheckedSign.tsx
│   │   │   │       ├── button.tsx
│   │   │   │       ├── card.tsx
│   │   │   │       ├── checkbox.tsx
│   │   │   │       ├── dropdown-menu.tsx
│   │   │   │       └── input.tsx
│   │   │   ├── data/
│   │   │   │   ├── demoUsers.json
│   │   │   │   └── roles.json
│   │   │   ├── db/
│   │   │   │   ├── TodoDB.ts
│   │   │   │   ├── TodoItem.ts
│   │   │   │   ├── TodoList.ts
│   │   │   │   ├── db.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── logout.ts
│   │   │   ├── helpers/
│   │   │   │   ├── handleError.ts
│   │   │   │   ├── simplify-debugging.ts
│   │   │   │   └── usePersistedOpenState.ts
│   │   │   ├── index.css
│   │   │   ├── index.tsx
│   │   │   ├── lib/
│   │   │   │   └── utils.ts
│   │   │   ├── serviceWorkerRegistration.ts
│   │   │   ├── setupTests.ts
│   │   │   ├── sw.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tailwind.config.js
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   ├── vite.config.ts
│   │   └── vitest.config.ts
│   ├── full-text-search/
│   │   └── FullTextSearch.js
│   ├── liveQuery/
│   │   └── liveQuery.html
│   ├── open-existing-db/
│   │   └── dump-databases.html
│   ├── react/
│   │   └── README.md
│   ├── remote-sync/
│   │   ├── ajax/
│   │   │   ├── AjaxSyncProtocol.js
│   │   │   └── jquery-2.1.0.js
│   │   └── websocket/
│   │       ├── WebSocketSyncProtocol.js
│   │       ├── WebSocketSyncServer.js
│   │       └── websocketserver-shim.js
│   ├── svelte/
│   │   └── README.md
│   ├── vanilla-js/
│   │   ├── hello-world-modern.html
│   │   └── hello-world.html
│   └── vue/
│       ├── .gitignore
│       ├── README.md
│       ├── index.html
│       ├── package.json
│       ├── public/
│       │   └── index.html
│       ├── src/
│       │   ├── App.vue
│       │   ├── components/
│       │   │   ├── AddTodo.vue
│       │   │   ├── Todo.vue
│       │   │   └── TodoList.vue
│       │   ├── database.js
│       │   └── main.js
│       └── vite.config.js
├── src/
│   ├── classes/
│   │   ├── collection/
│   │   │   ├── collection-constructor.ts
│   │   │   ├── collection-helpers.ts
│   │   │   ├── collection.ts
│   │   │   └── index.ts
│   │   ├── dexie/
│   │   │   ├── dexie-dom-dependencies.ts
│   │   │   ├── dexie-open.ts
│   │   │   ├── dexie-static-props.ts
│   │   │   ├── dexie.ts
│   │   │   ├── generate-middleware-stacks.ts
│   │   │   ├── index.ts
│   │   │   ├── transaction-helpers.ts
│   │   │   └── vip.ts
│   │   ├── entity/
│   │   │   └── Entity.ts
│   │   ├── observable/
│   │   │   └── observable.ts
│   │   ├── table/
│   │   │   ├── index.ts
│   │   │   ├── table-constructor.ts
│   │   │   ├── table-helpers.ts
│   │   │   └── table.ts
│   │   ├── transaction/
│   │   │   ├── index.ts
│   │   │   ├── transaction-constructor.ts
│   │   │   └── transaction.ts
│   │   ├── version/
│   │   │   ├── schema-helpers.ts
│   │   │   ├── version-constructor.ts
│   │   │   └── version.ts
│   │   └── where-clause/
│   │       ├── where-clause-constructor.ts
│   │       ├── where-clause-helpers.ts
│   │       └── where-clause.ts
│   ├── dbcore/
│   │   ├── cache-existing-values-middleware.ts
│   │   ├── dbcore-indexeddb.ts
│   │   ├── get-effective-keys.ts
│   │   ├── get-key-extractor.ts
│   │   ├── keyrange.ts
│   │   ├── proxy-cursor.ts
│   │   └── virtual-index-middleware.ts
│   ├── errors/
│   │   ├── errors.d.ts
│   │   ├── errors.js
│   │   └── index.ts
│   ├── functions/
│   │   ├── apply-update-spec.ts
│   │   ├── bulk-delete.ts
│   │   ├── chaining-functions.js
│   │   ├── cmp.ts
│   │   ├── combine.ts
│   │   ├── compare-functions.ts
│   │   ├── event-wrappers.ts
│   │   ├── get-object-diff.ts
│   │   ├── is-promise-like.ts
│   │   ├── make-class-constructor.ts
│   │   ├── propmods/
│   │   │   ├── add.ts
│   │   │   ├── index.ts
│   │   │   ├── remove.ts
│   │   │   └── replace-prefix.ts
│   │   ├── quirks.ts
│   │   ├── stringify-key.d.ts
│   │   ├── stringify-key.js
│   │   ├── temp-transaction.ts
│   │   ├── utils.ts
│   │   └── workaround-undefined-primkey.ts
│   ├── globals/
│   │   ├── connections.ts
│   │   ├── constants.ts
│   │   ├── global-events.ts
│   │   └── global.ts
│   ├── helpers/
│   │   ├── Events.js
│   │   ├── database-enumerator.ts
│   │   ├── debug.ts
│   │   ├── index-spec.ts
│   │   ├── promise.d.ts
│   │   ├── promise.js
│   │   ├── prop-modification.ts
│   │   ├── rangeset.ts
│   │   ├── table-schema.ts
│   │   ├── vipify.ts
│   │   └── yield-support.ts
│   ├── hooks/
│   │   └── hooks-middleware.ts
│   ├── index-umd.ts
│   ├── index.ts
│   ├── live-query/
│   │   ├── cache/
│   │   │   ├── adjust-optimistic-request-from-failures.ts
│   │   │   ├── apply-optimistic-ops.ts
│   │   │   ├── are-ranges-equal.ts
│   │   │   ├── cache-middleware.ts
│   │   │   ├── cache.ts
│   │   │   ├── does-ranges-overlap.ts
│   │   │   ├── find-compatible-query.ts
│   │   │   ├── is-cachable-context.ts
│   │   │   ├── is-cachable-request.ts
│   │   │   ├── is-super-range.ts
│   │   │   ├── is-within-range.ts
│   │   │   ├── signalSubscribers.ts
│   │   │   └── subscribe-cachentry.ts
│   │   ├── enable-broadcast.ts
│   │   ├── extend-observability-set.ts
│   │   ├── index.ts
│   │   ├── live-query.ts
│   │   ├── obs-sets-overlap.ts
│   │   ├── observability-middleware.ts
│   │   └── propagate-locally.ts
│   ├── public/
│   │   ├── index.d.ts
│   │   └── types/
│   │       ├── _insert-type.d.ts
│   │       ├── cache.d.ts
│   │       ├── collection.d.ts
│   │       ├── db-events.d.ts
│   │       ├── db-schema.d.ts
│   │       ├── dbcore.d.ts
│   │       ├── dbquerycore.d.ts
│   │       ├── dexie-constructor.d.ts
│   │       ├── dexie-dom-dependencies.d.ts
│   │       ├── dexie-event-set.d.ts
│   │       ├── dexie-event.d.ts
│   │       ├── dexie.d.ts
│   │       ├── entity-table.d.ts
│   │       ├── entity.d.ts
│   │       ├── errors.d.ts
│   │       ├── global.d.ts
│   │       ├── index-spec.d.ts
│   │       ├── indexable-type.d.ts
│   │       ├── insert-type.d.ts
│   │       ├── is-strictly-any.d.ts
│   │       ├── keypaths.d.ts
│   │       ├── middleware.d.ts
│   │       ├── observable.d.ts
│   │       ├── promise-extended.d.ts
│   │       ├── prop-modification.d.ts
│   │       ├── rangeset.d.ts
│   │       ├── table-hooks.d.ts
│   │       ├── table-schema.d.ts
│   │       ├── table.d.ts
│   │       ├── then-shortcut.d.ts
│   │       ├── transaction-events.d.ts
│   │       ├── transaction-mode.d.ts
│   │       ├── transaction.d.ts
│   │       ├── update-spec.d.ts
│   │       ├── version.d.ts
│   │       └── where-clause.d.ts
│   ├── support-bfcache.ts
│   └── tsconfig.json
├── test/
│   ├── .eslintrc.json
│   ├── .gitignore
│   ├── data.json
│   ├── deepEqual.js
│   ├── dexie-unittest-utils.js
│   ├── gh-actions.sh
│   ├── integrations/
│   │   └── test-dexie-relationships/
│   │       ├── basic-tests.js
│   │       ├── gh-actions.sh
│   │       ├── index.js
│   │       ├── karma.conf.js
│   │       ├── package.json
│   │       └── webpack.config.js
│   ├── is-idb-and-promise-compatible.js
│   ├── karma-env.js
│   ├── karma.browsers.matrix.d.ts
│   ├── karma.browsers.matrix.js
│   ├── karma.common.d.ts
│   ├── karma.common.js
│   ├── karma.conf.js
│   ├── karma.lambdatest.d.ts
│   ├── karma.lambdatest.js
│   ├── lt-local.js
│   ├── rebalance.md
│   ├── run-unit-tests.html
│   ├── tests-all.js
│   ├── tests-asyncawait.js
│   ├── tests-binarykeys.js
│   ├── tests-blobs.js
│   ├── tests-chrome-transaction-durability.js
│   ├── tests-cmp.js
│   ├── tests-collection.js
│   ├── tests-crud-hooks.js
│   ├── tests-exception-handling.js
│   ├── tests-extendability.js
│   ├── tests-idb30.js
│   ├── tests-live-query.js
│   ├── tests-max-connections.js
│   ├── tests-misc.js
│   ├── tests-open.js
│   ├── tests-performance.js
│   ├── tests-promise.js
│   ├── tests-rangeset.js
│   ├── tests-table.js
│   ├── tests-transaction.js
│   ├── tests-upgrading.js
│   ├── tests-whereclause.js
│   ├── tests-yield.js
│   ├── tsconfig.json
│   ├── typings-test/
│   │   ├── test-extend-dexie.ts
│   │   ├── test-misc.ts
│   │   ├── test-typings.ts
│   │   ├── test-updatespec.ts
│   │   └── tsconfig.json
│   └── worker.js
├── tools/
│   ├── .eslintrc.json
│   ├── build-configs/
│   │   ├── banner.txt
│   │   ├── rollup.config.js
│   │   ├── rollup.config.mjs
│   │   ├── rollup.modern.config.js
│   │   ├── rollup.modern.config.mjs
│   │   ├── rollup.tests.config.js
│   │   ├── rollup.tests.config.mjs
│   │   ├── rollup.umd.config.js
│   │   └── rollup.umd.config.mjs
│   ├── fix-dts-duplicates.js
│   ├── prepend.js
│   ├── release.sh
│   └── replaceVersionAndDate.js
└── tsconfig.json
Download .txt
SYMBOL INDEX (1558 symbols across 496 files)

FILE: addons/Dexie.Observable/api.d.ts
  type DatabaseChangeType (line 18) | const enum DatabaseChangeType {
  type ICreateChange (line 24) | interface ICreateChange {
  type IUpdateChange (line 32) | interface IUpdateChange {
  type IDeleteChange (line 42) | interface IDeleteChange {
  type IDatabaseChange (line 50) | type IDatabaseChange = ICreateChange | IUpdateChange | IDeleteChange;

FILE: addons/Dexie.Observable/src/Dexie.Observable.d.ts
  type SyncNodeConstructor (line 8) | interface SyncNodeConstructor {
  type SyncNode (line 25) | interface SyncNode {
  type ObservableEventSet (line 34) | interface ObservableEventSet extends DexieEventSet {
  type MessageEvent (line 42) | interface MessageEvent {
  type Dexie (line 57) | interface Dexie {
  type DbEvents (line 87) | interface DbEvents {
  type IndexSpec (line 94) | interface IndexSpec {
  type DexieConstructor (line 98) | interface DexieConstructor {

FILE: addons/Dexie.Observable/src/Dexie.Observable.js
  function Observable (line 62) | function Observable(db) {

FILE: addons/Dexie.Observable/src/change_types.js
  constant CREATE (line 2) | const CREATE = 1;
  constant UPDATE (line 3) | const UPDATE = 2;
  constant DELETE (line 4) | const DELETE = 3;

FILE: addons/Dexie.Observable/src/delete-old-changes.js
  function deleteOldChanges (line 3) | function deleteOldChanges(db) {

FILE: addons/Dexie.Observable/src/hooks/creating.js
  function initCreatingHook (line 5) | function initCreatingHook(db, table) {

FILE: addons/Dexie.Observable/src/hooks/crud-monitor.js
  function initCrudMonitor (line 5) | function initCrudMonitor(db) {

FILE: addons/Dexie.Observable/src/hooks/deleting.js
  function initDeletingHook (line 3) | function initDeletingHook(db, tableName) {

FILE: addons/Dexie.Observable/src/hooks/updating.js
  function initUpdatingHook (line 5) | function initUpdatingHook(db, tableName) {

FILE: addons/Dexie.Observable/src/intercomm.js
  function initIntercomm (line 5) | function initIntercomm(db, Observable, SyncNode, mySyncNode, localStorag...

FILE: addons/Dexie.Observable/src/on-storage.js
  function initOnStorage (line 3) | function initOnStorage(Observable) {

FILE: addons/Dexie.Observable/src/override-create-transaction.js
  function initOverrideCreateTransaction (line 1) | function initOverrideCreateTransaction(db, wakeupObservers) {

FILE: addons/Dexie.Observable/src/override-open.js
  function initOverrideOpen (line 1) | function initOverrideOpen(db, SyncNode, crudMonitor) {

FILE: addons/Dexie.Observable/src/override-parse-stores-spec.js
  function overrideParseStoresSpec (line 1) | function overrideParseStoresSpec(origFunc) {

FILE: addons/Dexie.Observable/src/utils.js
  function nop (line 1) | function nop() {}
  function promisableChain (line 3) | function promisableChain(f1, f2) {
  function createUUID (line 17) | function createUUID() {

FILE: addons/Dexie.Observable/src/wakeup-observers.js
  function initWakeupObservers (line 3) | function initWakeupObservers(db, Observable, localStorage) {

FILE: addons/Dexie.Observable/test/typings/test-typings.ts
  type Foo (line 7) | interface Foo {
  class MyDb (line 11) | class MyDb extends Dexie {
    method constructor (line 14) | constructor() {

FILE: addons/Dexie.Observable/test/unit/deep-equal.js
  function deepEqual (line 4) | function deepEqual(a, b, description) {
  function sortMembers (line 16) | function sortMembers (obj) {

FILE: addons/Dexie.Observable/test/unit/tests-observable-misc.js
  function createDB (line 21) | function createDB() {

FILE: addons/Dexie.Observable/test/unit/tests-override-open.js
  function origFn (line 13) | function origFn() {
  function crudMonitor (line 27) | function crudMonitor(table) {
  function SyncNode (line 50) | function SyncNode() {}
  method mapToClass (line 56) | mapToClass(cls) {

FILE: addons/Dexie.Observable/test/unit/tests-override-parse-stores-spec.js
  function origFunc (line 12) | function origFunc(stores/*, dbSchema*/) {
  function origFunc (line 25) | function origFunc(){}
  function origFunc (line 49) | function origFunc(){}

FILE: addons/Dexie.Observable/tools/build-configs/rollup.tests.config.js
  constant ERRORS_TO_IGNORE (line 5) | const ERRORS_TO_IGNORE = [
  method onwarn (line 24) | onwarn ({loc, frame, code, message}) {

FILE: addons/Dexie.Observable/tools/build-configs/rollup.tests.config.mjs
  constant ERRORS_TO_IGNORE (line 5) | const ERRORS_TO_IGNORE = [
  method onwarn (line 24) | onwarn ({loc, frame, code, message}) {

FILE: addons/Dexie.Observable/tools/build-configs/rollup.tests.unit.config.js
  constant ERRORS_TO_IGNORE (line 5) | const ERRORS_TO_IGNORE = [
  method onwarn (line 24) | onwarn ({loc, frame, code, message}) {

FILE: addons/Dexie.Observable/tools/build-configs/rollup.tests.unit.config.mjs
  constant ERRORS_TO_IGNORE (line 5) | const ERRORS_TO_IGNORE = [
  method onwarn (line 24) | onwarn ({loc, frame, code, message}) {

FILE: addons/Dexie.Syncable/api.d.ts
  type ISyncProtocol (line 54) | interface ISyncProtocol {
  type IPersistedContext (line 73) | interface IPersistedContext {
  type ApplyRemoteChangesFunction (line 81) | type ApplyRemoteChangesFunction = (
  type PollContinuation (line 91) | interface PollContinuation {
  type ReactiveContinuation (line 100) | interface ReactiveContinuation {
  type SyncStatus (line 124) | enum SyncStatus {

FILE: addons/Dexie.Syncable/src/Dexie.Syncable.d.ts
  type SyncableEventSet (line 11) | interface SyncableEventSet extends DexieEventSet {
  type Dexie (line 19) | interface Dexie {
  type DexieConstructor (line 69) | interface DexieConstructor {
  type SyncNode (line 93) | interface SyncNode {

FILE: addons/Dexie.Syncable/src/Dexie.Syncable.js
  function Syncable (line 39) | function Syncable (db) {

FILE: addons/Dexie.Syncable/src/PersistedContext.js
  function initPersistedContext (line 3) | function initPersistedContext(node) {

FILE: addons/Dexie.Syncable/src/apply-changes.js
  function initApplyChanges (line 4) | function initApplyChanges(db) {

FILE: addons/Dexie.Syncable/src/bulk-update.js
  function bulkUpdate (line 3) | function bulkUpdate(table, changes) {

FILE: addons/Dexie.Syncable/src/change_types.js
  constant CREATE (line 2) | const CREATE = 1;
  constant UPDATE (line 3) | const UPDATE = 2;
  constant DELETE (line 4) | const DELETE = 3;

FILE: addons/Dexie.Syncable/src/combine-create-and-update.js
  function combineCreateAndUpdate (line 3) | function combineCreateAndUpdate(prevChange, nextChange) {

FILE: addons/Dexie.Syncable/src/combine-update-and-update.js
  function combineUpdateAndUpdate (line 3) | function combineUpdateAndUpdate(prevChange, nextChange) {

FILE: addons/Dexie.Syncable/src/connect-fn.js
  function initConnectFn (line 7) | function initConnectFn(db, activePeers) {

FILE: addons/Dexie.Syncable/src/connect-protocol.js
  function initConnectProtocol (line 11) | function initConnectProtocol(db, protocolInstance, dbAliveID, options, r...

FILE: addons/Dexie.Syncable/src/enqueue.js
  function initEnqueue (line 3) | function initEnqueue(db) {

FILE: addons/Dexie.Syncable/src/finally-commit-all-changes.js
  function initFinallyCommitAllChanges (line 4) | function initFinallyCommitAllChanges(db, node) {

FILE: addons/Dexie.Syncable/src/get-local-changes-for-node/get-base-revision-and-max-client-revision.js
  function getBaseRevisionAndMaxClientRevision (line 1) | function getBaseRevisionAndMaxClientRevision(node) {

FILE: addons/Dexie.Syncable/src/get-local-changes-for-node/get-changes-since-revision.js
  function initGetChangesSinceRevision (line 4) | function initGetChangesSinceRevision(db, node, hasMoreToGive) {

FILE: addons/Dexie.Syncable/src/get-local-changes-for-node/get-local-changes-for-node.js
  function initGetLocalChangesForNode (line 7) | function initGetLocalChangesForNode(db, hasMoreToGive, partialsThreshold) {

FILE: addons/Dexie.Syncable/src/get-local-changes-for-node/get-table-objects-as-changes.js
  function initGetTableObjectsAsChanges (line 4) | function initGetTableObjectsAsChanges(db, node, MAX_CHANGES_PER_CHUNK, g...

FILE: addons/Dexie.Syncable/src/get-or-create-sync-node.js
  function initGetOrCreateSyncNode (line 5) | function initGetOrCreateSyncNode(db, protocolName, url) {

FILE: addons/Dexie.Syncable/src/merge-change.js
  function mergeChange (line 5) | function mergeChange(prevChange, nextChange) {

FILE: addons/Dexie.Syncable/src/save-to-uncommitted-changes.js
  function initSaveToUncommittedChanges (line 1) | function initSaveToUncommittedChanges(db, node) {

FILE: addons/Dexie.Syncable/src/syncable-connect.js
  function initSyncableConnect (line 5) | function initSyncableConnect(db, connect) {

FILE: addons/Dexie.Syncable/test/test-typings/test-typings.ts
  method react (line 51) | react (changes, baseRevision, partial, onChangesAccepted) {
  method disconnect (line 57) | disconnect(){}
  class Foo (line 65) | class Foo {
    method bar (line 67) | bar() {}
  class MyDb (line 74) | class MyDb extends Dexie {
    method constructor (line 76) | constructor() {
  function getUrlsAndStatuses (line 112) | async function getUrlsAndStatuses() {
  function statusChanged (line 117) | function statusChanged(status: number, url: string) {

FILE: addons/Dexie.Syncable/test/unit/get-local-changes-for-node/tests-get-changes-since-revision.js
  function cb (line 68) | function cb(changes, partial, revisionObject) {
  function cb (line 132) | function cb(changes/*, partial, revisionObject*/) {
  function cb (line 172) | function cb(changes/*, partial, revisionObject*/) {
  function cb (line 229) | function cb(changes, partial, revisionObject) {
  function cb (line 284) | function cb(changes, partial, revisionObject) {

FILE: addons/Dexie.Syncable/test/unit/get-local-changes-for-node/tests-get-local-changes-for-node.js
  function cb (line 45) | function cb(changes/*, remoteBaseRevision, partial, nodeModificationsOnA...
  function cb (line 86) | function cb(changes/*, remoteBaseRevision, partial, nodeModificationsOnA...
  function cb (line 126) | function cb(changes/*, remoteBaseRevision, partial, nodeModificationsOnA...
  function cb (line 161) | function cb(changes/*, remoteBaseRevision, partial, nodeModificationsOnA...

FILE: addons/Dexie.Syncable/test/unit/tests-finally-commit-all-changes.js
  method catch (line 21) | catch() {}
  method catch (line 41) | catch() {}
  method catch (line 107) | catch() {}

FILE: addons/Dexie.Syncable/test/unit/tests-register-sync-protocol.js
  method sync (line 15) | sync() {}
  method sync (line 24) | sync() {}
  function fn1 (line 34) | function fn1() {
  function fn2 (line 43) | function fn2() {

FILE: addons/Dexie.Syncable/test/unit/tests-save-to-uncommitted-changes.js
  method then (line 16) | then(cb){ cb(); }

FILE: addons/Dexie.Syncable/test/unit/tests-syncable.js
  function reconnect (line 179) | function reconnect() {

FILE: addons/Dexie.Syncable/test/unit/tests-syncprovider.js
  function sendChanges (line 40) | function sendChanges(changes, baseRevision, partial, onChangesAccepted) {
  function waitFor (line 178) | function waitFor(db, params) {

FILE: addons/Dexie.Syncable/tools/build-configs/rollup.tests.config.js
  constant ERRORS_TO_IGNORE (line 5) | const ERRORS_TO_IGNORE = [
  method onwarn (line 23) | onwarn ({loc, frame, code, message}) {

FILE: addons/Dexie.Syncable/tools/build-configs/rollup.tests.config.mjs
  constant ERRORS_TO_IGNORE (line 5) | const ERRORS_TO_IGNORE = [
  method onwarn (line 23) | onwarn ({loc, frame, code, message}) {

FILE: addons/dexie-cloud/src/DISABLE_SERVICEWORKER_STRATEGY.ts
  constant DISABLE_SERVICEWORKER_STRATEGY (line 9) | const DISABLE_SERVICEWORKER_STRATEGY =

FILE: addons/dexie-cloud/src/DXCWebSocketStatus.ts
  type DXCWebSocketStatus (line 1) | type DXCWebSocketStatus = "not-started" | "connecting" | "connected" | "...

FILE: addons/dexie-cloud/src/DexieCloudAPI.ts
  type BlobProgress (line 14) | interface BlobProgress {
  type LoginHints (line 28) | interface LoginHints {
  type DexieCloudAPI (line 42) | interface DexieCloudAPI {

FILE: addons/dexie-cloud/src/DexieCloudOptions.ts
  type PeriodicSyncOptions (line 4) | interface PeriodicSyncOptions {
  type DexieCloudOptions (line 9) | interface DexieCloudOptions {

FILE: addons/dexie-cloud/src/DexieCloudSyncOptions.ts
  type DexieCloudSyncOptions (line 2) | interface DexieCloudSyncOptions {

FILE: addons/dexie-cloud/src/DexieCloudTable.ts
  type DexieCloudEntity (line 3) | interface DexieCloudEntity {
  type WithDexieCloudProps (line 15) | type WithDexieCloudProps<T> = T extends DexieCloudEntity ? T : T & Dexie...
  type DexieCloudTable (line 20) | type DexieCloudTable<T = any, TKeyPropName extends keyof T = never> =

FILE: addons/dexie-cloud/src/InvalidLicenseError.ts
  class InvalidLicenseError (line 1) | class InvalidLicenseError extends Error {
    method constructor (line 4) | constructor(license?: 'expired' | 'deactivated') {

FILE: addons/dexie-cloud/src/Invite.ts
  type Invite (line 3) | interface Invite extends DBRealmMember {

FILE: addons/dexie-cloud/src/PermissionChecker.ts
  type TableName (line 4) | type TableName<T> = T extends {table: ()=>infer TABLE} ? TABLE extends s...
  class PermissionChecker (line 6) | class PermissionChecker<T, TableNames extends string = TableName<T>> {
    method constructor (line 11) | constructor(
    method add (line 21) | add(...tableNames: TableNames[]): boolean {
    method update (line 37) | update(...props: KeyPaths<T>[]): boolean {
    method delete (line 63) | delete(): boolean {

FILE: addons/dexie-cloud/src/TSON.ts
  function getValueOfBigInt (line 34) | function getValueOfBigInt(x: bigint | FakeBigInt | string) {
  function compareBigInts (line 45) | function compareBigInts(
  class FakeBigInt (line 53) | class FakeBigInt {
    method toString (line 55) | toString() {
    method constructor (line 58) | constructor(value: string) {
  constant TSON (line 100) | const TSON = TypesonSimplified(

FILE: addons/dexie-cloud/src/WSObservable.ts
  constant SERVER_PING_TIMEOUT (line 21) | const SERVER_PING_TIMEOUT = 20000;
  constant CLIENT_PING_INTERVAL (line 22) | const CLIENT_PING_INTERVAL = 30000;
  constant FAIL_RETRY_WAIT_TIME (line 23) | const FAIL_RETRY_WAIT_TIME = 60000;
  type WSClientToServerMsg (line 25) | type WSClientToServerMsg = ReadyForChangesMessage | YClientMessage;
  type ReadyForChangesMessage (line 26) | interface ReadyForChangesMessage {
  type WSConnectionMsg (line 32) | type WSConnectionMsg =
  type PingMessage (line 40) | interface PingMessage {
  type PongMessage (line 44) | interface PongMessage {
  type ErrorMessage (line 48) | interface ErrorMessage {
  type ChangesFromServerMessage (line 53) | interface ChangesFromServerMessage {
  type RevisionChangedMessage (line 60) | interface RevisionChangedMessage {
  type RealmAddedMessage (line 65) | interface RealmAddedMessage {
  type RealmAcceptedMessage (line 70) | interface RealmAcceptedMessage {
  type RealmRemovedMessage (line 75) | interface RealmRemovedMessage {
  type RealmsChangedMessage (line 80) | interface RealmsChangedMessage {
  type TokenExpiredMessage (line 84) | interface TokenExpiredMessage {
  class WSObservable (line 88) | class WSObservable extends Observable<WSConnectionMsg> {
    method constructor (line 89) | constructor(
  class WSConnection (line 118) | class WSConnection extends Subscription {
    method constructor (line 139) | constructor(
    method teardown (line 170) | private teardown() {
    method disconnect (line 175) | private disconnect() {
    method reconnect (line 194) | reconnect() {
    method connect (line 205) | async connect() {

FILE: addons/dexie-cloud/src/associate.ts
  function associate (line 1) | function associate<T extends object,M>(factory: (x: T)=>M): (x: T) => M {

FILE: addons/dexie-cloud/src/authentication/AuthPersistedContext.ts
  type AuthPersistedContext (line 4) | interface AuthPersistedContext extends UserLogin {
    method constructor (line 12) | constructor(db: DexieCloudDB, userLogin: UserLogin) {
    method load (line 17) | static load(db: DexieCloudDB, userId: string) {
    method save (line 32) | async save() {
  class AuthPersistedContext (line 11) | class AuthPersistedContext {
    method constructor (line 12) | constructor(db: DexieCloudDB, userLogin: UserLogin) {
    method load (line 17) | static load(db: DexieCloudDB, userId: string) {
    method save (line 32) | async save() {

FILE: addons/dexie-cloud/src/authentication/TokenErrorResponseError.ts
  class TokenErrorResponseError (line 3) | class TokenErrorResponseError extends Error {
    method constructor (line 13) | constructor({

FILE: addons/dexie-cloud/src/authentication/TokenExpiredError.ts
  class TokenExpiredError (line 1) | class TokenExpiredError extends Error {

FILE: addons/dexie-cloud/src/authentication/UNAUTHORIZED_USER.ts
  constant UNAUTHORIZED_USER (line 3) | const UNAUTHORIZED_USER: UserLogin = {

FILE: addons/dexie-cloud/src/authentication/authenticate.ts
  type FetchTokenCallback (line 23) | type FetchTokenCallback = (tokenParams: {
  function loadAccessToken (line 28) | async function loadAccessToken(
  function authenticate (line 65) | async function authenticate(
  function refreshAccessToken (line 88) | async function refreshAccessToken(
  function userAuthenticate (line 151) | async function userAuthenticate(
  function spkiToPEM (line 280) | function spkiToPEM(keydata: ArrayBuffer) {
  function formatAsPem (line 286) | function formatAsPem(str: string) {

FILE: addons/dexie-cloud/src/authentication/exchangeOAuthCode.ts
  type ExchangeOAuthCodeOptions (line 10) | interface ExchangeOAuthCodeOptions {
  function exchangeOAuthCode (line 31) | async function exchangeOAuthCode(

FILE: addons/dexie-cloud/src/authentication/fetchAuthProviders.ts
  constant OTP_ONLY_RESPONSE (line 4) | const OTP_ONLY_RESPONSE: AuthProvidersResponse = {
  function fetchAuthProviders (line 21) | async function fetchAuthProviders(

FILE: addons/dexie-cloud/src/authentication/handleOAuthCallback.ts
  type OAuthCallbackParams (line 4) | interface OAuthCallbackParams {
  type DxcAuthPayload (line 14) | interface DxcAuthPayload {
  function decodeBase64Url (line 25) | function decodeBase64Url(encoded: string): string {
  function parseOAuthCallback (line 44) | function parseOAuthCallback(url?: string): OAuthCallbackParams | null {
  function validateOAuthState (line 96) | function validateOAuthState(receivedState: string): boolean {
  function cleanupOAuthUrl (line 119) | function cleanupOAuthUrl(): void {
  function handleOAuthCallback (line 160) | function handleOAuthCallback(url?: string): OAuthCallbackParams | null {

FILE: addons/dexie-cloud/src/authentication/interactWithUser.ts
  function providerToOption (line 16) | function providerToOption(provider: OAuthProviderInfo): DXCOption {
  type DXCUserInteractionRequest (line 26) | interface DXCUserInteractionRequest {
  function interactWithUser (line 35) | function interactWithUser<T extends DXCUserInteractionRequest>(
  function alertUser (line 75) | function alertUser(
  function promptForEmail (line 90) | async function promptForEmail(
  function promptForOTP (line 144) | async function promptForOTP(
  function confirmLogout (line 175) | async function confirmLogout(
  type ProviderSelectionResult (line 205) | type ProviderSelectionResult =
  function promptForProvider (line 222) | async function promptForProvider(

FILE: addons/dexie-cloud/src/authentication/login.ts
  function login (line 11) | async function login(

FILE: addons/dexie-cloud/src/authentication/logout.ts
  function logout (line 7) | async function logout(db: DexieCloudDB) {
  function _logout (line 24) | async function _logout(db: DexieCloudDB, { deleteUnsyncedData = false } ...

FILE: addons/dexie-cloud/src/authentication/oauthLogin.ts
  type OAuthRedirectOptions (line 4) | interface OAuthRedirectOptions {
  function buildOAuthLoginUrl (line 17) | function buildOAuthLoginUrl(options: OAuthRedirectOptions): string {
  function startOAuthRedirect (line 52) | function startOAuthRedirect(options: OAuthRedirectOptions): void {
  function mapOAuthError (line 62) | function mapOAuthError(error: string): OAuthError['code'] {

FILE: addons/dexie-cloud/src/authentication/otpFetchTokenCallback.ts
  function otpFetchTokenCallback (line 20) | function otpFetchTokenCallback(db: DexieCloudDB): FetchTokenCallback {
  function initiateOAuthRedirect (line 215) | function initiateOAuthRedirect(

FILE: addons/dexie-cloud/src/authentication/setCurrentUser.ts
  function setCurrentUser (line 17) | async function setCurrentUser(

FILE: addons/dexie-cloud/src/authentication/waitUntil.ts
  function waitUntil (line 3) | function waitUntil<T>(

FILE: addons/dexie-cloud/src/computeSyncState.ts
  function computeSyncState (line 9) | function computeSyncState(db: DexieCloudDB): Observable<SyncState> {

FILE: addons/dexie-cloud/src/createSharedValueObservable.ts
  function createSharedValueObservable (line 13) | function createSharedValueObservable<T>(

FILE: addons/dexie-cloud/src/db/DexieCloudDB.ts
  type SyncStateChangedEventData (line 30) | interface SyncStateChangedEventData {
  type SyncStateTable (line 36) | type SyncStateTable = Table<
  type DexieCloudDBBase (line 40) | interface DexieCloudDBBase {
  type DexieCloudDB (line 63) | interface DexieCloudDB extends DexieCloudDBBase {
  constant DEXIE_CLOUD_SCHEMA (line 77) | const DEXIE_CLOUD_SCHEMA = {
  function DexieCloudDB (line 88) | function DexieCloudDB(dx: Dexie): DexieCloudDB {
  function nameFromKeyPath (line 209) | function nameFromKeyPath (keyPath?: string | string[]): string {

FILE: addons/dexie-cloud/src/db/entities/BaseRevisionMapEntry.ts
  type BaseRevisionMapEntry (line 2) | interface BaseRevisionMapEntry {

FILE: addons/dexie-cloud/src/db/entities/EntityCommon.ts
  type EntityCommon (line 1) | interface EntityCommon {

FILE: addons/dexie-cloud/src/db/entities/GuardedJob.ts
  type GuardedJob (line 2) | interface GuardedJob {

FILE: addons/dexie-cloud/src/db/entities/Member.ts
  type Member (line 1) | interface Member {

FILE: addons/dexie-cloud/src/db/entities/PersistedSyncState.ts
  type PersistedSyncState (line 1) | interface PersistedSyncState {

FILE: addons/dexie-cloud/src/db/entities/Realm.ts
  type Realm (line 1) | interface Realm {

FILE: addons/dexie-cloud/src/db/entities/Role.ts
  type Role (line 1) | interface Role {

FILE: addons/dexie-cloud/src/db/entities/UserLogin.ts
  type UserLogin (line 3) | interface UserLogin {

FILE: addons/dexie-cloud/src/default-ui/Dialog.tsx
  function Dialog (line 4) | function Dialog({ children, className }: { children?: ComponentChildren,...

FILE: addons/dexie-cloud/src/default-ui/LoginDialog.tsx
  constant OTP_LENGTH (line 11) | const OTP_LENGTH = 8;
  type LoginDialogProps (line 14) | interface LoginDialogProps {
  function LoginDialog (line 35) | function LoginDialog({
  function valueTransformer (line 177) | function valueTransformer(type: string, value: string) {
  function CopyButton (line 188) | function CopyButton({ text }: { text: string }) {
  function fallbackCopy (line 230) | function fallbackCopy(text: string, onSuccess: () => void) {

FILE: addons/dexie-cloud/src/default-ui/OptionButton.tsx
  type OptionButtonProps (line 5) | interface OptionButtonProps {
  function getOptionStyle (line 11) | function getOptionStyle(styleHint?: string): Record<string, string> {
  function OptionButton (line 42) | function OptionButton({ option, onClick }: OptionButtonProps) {
  function Divider (line 70) | function Divider() {

FILE: addons/dexie-cloud/src/default-ui/index.tsx
  type Props (line 9) | interface Props {
  type State (line 13) | interface State {
  class LoginGui (line 17) | class LoginGui extends Component<Props, State> {
    method constructor (line 21) | constructor(props: Props) {
    method componentDidMount (line 26) | componentDidMount() {
    method componentWillUnmount (line 30) | componentWillUnmount() {
    method render (line 37) | render(props: Props, {userInteraction}: State) {
  function setupDefaultGUI (line 46) | function setupDefaultGUI(db: Dexie) {

FILE: addons/dexie-cloud/src/define-ydoc-trigger.ts
  type TriggerRegistry (line 23) | type TriggerRegistry = Map<
  function TriggerRunner (line 34) | function TriggerRunner(name: string) {
  method mutate (line 150) | mutate(req) {
  function onTransactionCommitted (line 207) | function onTransactionCommitted() {
  function beforeProviderUnload (line 211) | function beforeProviderUnload() {
  function defineYDocTrigger (line 215) | function defineYDocTrigger<T, TKey>(

FILE: addons/dexie-cloud/src/dexie-cloud-client.ts
  constant DEFAULT_OPTIONS (line 81) | const DEFAULT_OPTIONS: Partial<DexieCloudOptions> = {
  function dexieCloud (line 85) | function dexieCloud(dexie: Dexie) {

FILE: addons/dexie-cloud/src/errors/HttpError.ts
  class HttpError (line 1) | class HttpError extends Error {
    method constructor (line 3) | constructor(
    method name (line 11) | get name() {

FILE: addons/dexie-cloud/src/errors/OAuthError.ts
  type OAuthErrorCode (line 2) | type OAuthErrorCode =
  constant ERROR_MESSAGES (line 11) | const ERROR_MESSAGES: Record<OAuthErrorCode, string> = {
  class OAuthError (line 21) | class OAuthError extends Error {
    method constructor (line 25) | constructor(code: OAuthErrorCode, provider?: string, customMessage?: s...
    method userMessage (line 33) | get userMessage(): string {

FILE: addons/dexie-cloud/src/errors/OAuthRedirectError.ts
  class OAuthRedirectError (line 8) | class OAuthRedirectError extends Error {
    method constructor (line 11) | constructor(provider: string) {

FILE: addons/dexie-cloud/src/extend-dexie-interface.ts
  type Optional (line 14) | type Optional<T, Props extends keyof T> = Omit<T, Props> & Partial<T>;
  type Dexie (line 20) | interface Dexie {
  type Table (line 27) | interface Table {
  type DexieConstructor (line 32) | interface DexieConstructor {

FILE: addons/dexie-cloud/src/getInternalAccessControlObservable.ts
  type InternalAccessControlData (line 9) | type InternalAccessControlData = {
  method userId (line 35) | get userId() {

FILE: addons/dexie-cloud/src/getInvitesObservable.ts
  method accept (line 41) | async accept() {
  method reject (line 44) | async reject() {

FILE: addons/dexie-cloud/src/getPermissionsLookupObservable.ts
  type PermissionsLookup (line 14) | type PermissionsLookup = {
  type PermissionsLookupObservable (line 18) | type PermissionsLookupObservable = Observable<PermissionsLookup> & {

FILE: addons/dexie-cloud/src/getTiedRealmId.ts
  function getTiedRealmId (line 2) | function getTiedRealmId(objectId: string) {
  function getTiedObjectId (line 6) | function getTiedObjectId(realmId: string) {

FILE: addons/dexie-cloud/src/helpers/BroadcastedAndLocalEvent.ts
  function addListener (line 7) | function addListener(name: string, listener: (ev: CustomEvent)=>void) {
  function removeListener (line 14) | function removeListener(name: string, listener: (ev: CustomEvent)=>void) {
  function dispatch (line 23) | function dispatch(ev: CustomEvent) {
  class BroadcastedAndLocalEvent (line 35) | class BroadcastedAndLocalEvent<T> extends Observable<T>{
    method constructor (line 39) | constructor(name: string) {
    method next (line 79) | next(message: T) {

FILE: addons/dexie-cloud/src/helpers/CancelToken.ts
  type CancelToken (line 3) | interface CancelToken {
  function throwIfCancelled (line 7) | function throwIfCancelled(cancelToken?: CancelToken) {

FILE: addons/dexie-cloud/src/helpers/IS_SERVICE_WORKER.ts
  constant IS_SERVICE_WORKER (line 1) | const IS_SERVICE_WORKER =

FILE: addons/dexie-cloud/src/helpers/SWBroadcastChannel.ts
  class SWBroadcastChannel (line 26) | class SWBroadcastChannel {
    method constructor (line 28) | constructor(name: string) {
    method subscribe (line 31) | subscribe(listener: (message: any) => void) {
    method postMessage (line 41) | postMessage(message: any) {

FILE: addons/dexie-cloud/src/helpers/allSettled.ts
  function allSettled (line 2) | function allSettled(possiblePromises: any[]) {

FILE: addons/dexie-cloud/src/helpers/bulkUpdate.ts
  function bulkUpdate (line 3) | async function bulkUpdate(

FILE: addons/dexie-cloud/src/helpers/computeRealmSetHash.ts
  function computeRealmSetHash (line 4) | async function computeRealmSetHash({

FILE: addons/dexie-cloud/src/helpers/date-constants.ts
  constant SECONDS (line 1) | const SECONDS = 1000;
  constant MINUTES (line 2) | const MINUTES = 60 * SECONDS;
  constant HOURS (line 3) | const HOURS = 60 * MINUTES;
  constant DAYS (line 4) | const DAYS = 24 * HOURS;
  constant WEEKS (line 5) | const WEEKS = 7 * DAYS;

FILE: addons/dexie-cloud/src/helpers/flatten.ts
  function flatten (line 2) | function flatten<T>(a: (T | T[])[]): T[] {

FILE: addons/dexie-cloud/src/helpers/getMutationTable.ts
  function getMutationTable (line 3) | function getMutationTable(tableName: string) {

FILE: addons/dexie-cloud/src/helpers/getSyncableTables.ts
  function getSyncableTables (line 5) | function getSyncableTables(db: DexieCloudDB): Table<EntityCommon>[] {

FILE: addons/dexie-cloud/src/helpers/getTableFromMutationTable.ts
  function getTableFromMutationTable (line 3) | function getTableFromMutationTable(mutationTable: string) {

FILE: addons/dexie-cloud/src/helpers/makeArray.ts
  function makeArray (line 2) | function makeArray<T>(iterable: Iterable<T>): T[] {

FILE: addons/dexie-cloud/src/helpers/randomString.ts
  function randomString (line 1) | function randomString(bytes: number) {

FILE: addons/dexie-cloud/src/helpers/resolveText.ts
  function resolveText (line 17) | function resolveText({message, messageCode, messageParams}: DXCAlert) {

FILE: addons/dexie-cloud/src/helpers/throwVersionIncrementNeeded.ts
  function throwVersionIncrementNeeded (line 3) | function throwVersionIncrementNeeded() {

FILE: addons/dexie-cloud/src/helpers/visibilityState.ts
  function createVisibilityStateObservable (line 4) | function createVisibilityStateObservable() {

FILE: addons/dexie-cloud/src/isEagerSyncDisabled.ts
  function isEagerSyncDisabled (line 3) | function isEagerSyncDisabled(db: DexieCloudDB) {

FILE: addons/dexie-cloud/src/mapValueObservable.ts
  type ObservableWithCurrentValue (line 3) | interface ObservableWithCurrentValue<T> extends Observable<T> {
  function mapValueObservable (line 7) | function mapValueObservable<T, R>(

FILE: addons/dexie-cloud/src/mergePermissions.ts
  function mergePermissions (line 5) | function mergePermissions(

FILE: addons/dexie-cloud/src/middleware-helpers/guardedTable.ts
  function guardedTable (line 6) | function guardedTable(table: DBCoreTable) {
  function readLock (line 19) | function readLock<TReq extends { trans: DBCoreTransaction }, TRes>(
  function writeLock (line 39) | function writeLock<TReq extends { trans: DBCoreTransaction }, TRes>(

FILE: addons/dexie-cloud/src/middleware-helpers/idGenerationHelpers.ts
  function toStringTag (line 9) | function toStringTag(o: Object) {
  function getEffectiveKeys (line 13) | function getEffectiveKeys(
  function applyToUpperBitFix (line 24) | function applyToUpperBitFix(orig: string, bits: number) {
  function isUpperCase (line 32) | function isUpperCase(ch: string) {
  function generateTablePrefix (line 36) | function generateTablePrefix(
  function generateKey (line 84) | function generateKey(prefix: string, shardKey?: string) {

FILE: addons/dexie-cloud/src/middlewares/blobResolveMiddleware.ts
  function createBlobResolveMiddleware (line 37) | function createBlobResolveMiddleware(db: DexieCloudDB): Middleware<DBCor...
  function createBlobResolvingCursor (line 147) | function createBlobResolvingCursor(
  function resolveAndSave (line 198) | function resolveAndSave(

FILE: addons/dexie-cloud/src/middlewares/createIdGenerationMiddleware.ts
  function createIdGenerationMiddleware (line 18) | function createIdGenerationMiddleware(

FILE: addons/dexie-cloud/src/middlewares/createImplicitPropSetterMiddleware.ts
  function createImplicitPropSetterMiddleware (line 6) | function createImplicitPropSetterMiddleware(

FILE: addons/dexie-cloud/src/middlewares/createMutationTrackingMiddleware.ts
  type MutationTrackingMiddlewareArgs (line 26) | interface MutationTrackingMiddlewareArgs {
  function createMutationTrackingMiddleware (line 39) | function createMutationTrackingMiddleware({

FILE: addons/dexie-cloud/src/overrideParseStoresSpec.ts
  function overrideParseStoresSpec (line 5) | function overrideParseStoresSpec(origFunc: Function, dexie: Dexie) {

FILE: addons/dexie-cloud/src/performInitialSync.ts
  function performInitialSync (line 7) | async function performInitialSync(

FILE: addons/dexie-cloud/src/permissions.ts
  function permissions (line 13) | function permissions(

FILE: addons/dexie-cloud/src/prodLog.ts
  function prodLog (line 9) | function prodLog(level: 'log' | 'warn' | 'error' | 'debug', ...args: any...

FILE: addons/dexie-cloud/src/service-worker.ts
  function getDbNameFromTag (line 13) | function getDbNameFromTag(tag: string) {
  function syncDB (line 19) | function syncDB(dbName: string, purpose: 'push' | 'pull') {
  function sleep (line 137) | function sleep(ms: number) {

FILE: addons/dexie-cloud/src/sync/BlobDownloadTracker.ts
  class BlobDownloadTracker (line 15) | class BlobDownloadTracker {
    method constructor (line 19) | constructor (db: DexieCloudDB) {
    method download (line 29) | download(blobRef: BlobRef, dbUrl: string): Promise<Uint8Array> {
  function downloadBlob (line 51) | async function downloadBlob(

FILE: addons/dexie-cloud/src/sync/BlobSavingQueue.ts
  type QueuedBlob (line 17) | interface QueuedBlob {
  class BlobSavingQueue (line 23) | class BlobSavingQueue {
    method constructor (line 28) | constructor(db: DexieCloudDB) {
    method saveBlobs (line 36) | saveBlobs(tableName: string, primaryKey: any, resolvedBlobs: ResolvedB...
    method startConsumer (line 46) | private startConsumer(): void {
    method processQueue (line 63) | private processQueue(): void {

FILE: addons/dexie-cloud/src/sync/DEXIE_CLOUD_SYNCER_ID.ts
  constant DEXIE_CLOUD_SYNCER_ID (line 2) | const DEXIE_CLOUD_SYNCER_ID = 'dexie-cloud-syncer';

FILE: addons/dexie-cloud/src/sync/LocalSyncWorker.ts
  function LocalSyncWorker (line 8) | function LocalSyncWorker(

FILE: addons/dexie-cloud/src/sync/SyncRequiredError.ts
  class SyncRequiredError (line 1) | class SyncRequiredError extends Error {

FILE: addons/dexie-cloud/src/sync/applyServerChanges.ts
  function markIfHasBlobRefs (line 12) | function markIfHasBlobRefs(obj: unknown): void {
  function applyServerChanges (line 24) | async function applyServerChanges(

FILE: addons/dexie-cloud/src/sync/blobOffloading.test.ts
  function assert (line 6) | function assert(cond: boolean, msg: string) {

FILE: addons/dexie-cloud/src/sync/blobOffloading.ts
  constant BLOB_OFFLOAD_THRESHOLD (line 12) | const BLOB_OFFLOAD_THRESHOLD = 4096;
  constant DEFAULT_MAX_STRING_LENGTH (line 15) | const DEFAULT_MAX_STRING_LENGTH = 32768;
  constant ARRAYBUFFER_VIEW_TAGS (line 41) | const ARRAYBUFFER_VIEW_TAGS = new Set([
  constant BINARY_TYPE_TAGS (line 49) | const BINARY_TYPE_TAGS = new Set([
  function getTypeTag (line 59) | function getTypeTag(value: unknown): string {
  function getOrigType (line 66) | function getOrigType(value: Blob | ArrayBuffer | ArrayBufferView): BlobR...
  function shouldOffloadBlob (line 77) | function shouldOffloadBlob(value: unknown): value is Blob | ArrayBuffer ...
  function uploadBlob (line 107) | async function uploadBlob(
  function offloadBlobsAndMarkDirty (line 181) | async function offloadBlobsAndMarkDirty(
  function offloadBlobs (line 201) | async function offloadBlobs(
  function offloadBlobsInOperations (line 287) | async function offloadBlobsInOperations(
  function offloadBlobsInOperation (line 312) | async function offloadBlobsInOperation(
  function hasLargeBlobsInOperations (line 361) | function hasLargeBlobsInOperations(operations: DBOperationsSet, maxStrin...
  function hasLargeBlobsInOperation (line 372) | function hasLargeBlobsInOperation(op: DBOperation, maxStringLength: numb...
  function hasLargeBlobs (line 386) | function hasLargeBlobs(obj: unknown, maxStringLength: number, visited = ...

FILE: addons/dexie-cloud/src/sync/blobProgress.ts
  type RefInfo (line 21) | interface RefInfo {
  function createDownloadingState (line 29) | function createDownloadingState(): BehaviorSubject<boolean> {
  function setDownloadingState (line 36) | function setDownloadingState(
  function observeBlobProgress (line 51) | function observeBlobProgress(
  function findBlobRefs (line 101) | function findBlobRefs(obj: unknown): RefInfo[] {

FILE: addons/dexie-cloud/src/sync/blobResolve.ts
  type BlobRefOrigType (line 24) | type BlobRefOrigType =
  type BlobRef (line 46) | interface BlobRef {
  type ResolvedBlob (line 56) | interface ResolvedBlob {
  function isBlobRef (line 66) | function isBlobRef(value: unknown): value is BlobRef {
  type SerializedTSONRef (line 80) | interface SerializedTSONRef {
  function isSerializedTSONRef (line 91) | function isSerializedTSONRef(value: unknown): value is SerializedTSONRef {
  function hasBlobRefs (line 105) | function hasBlobRefs(obj: unknown, visited = new WeakSet()): boolean {
  function convertToOriginalType (line 147) | function convertToOriginalType(
  function resolveAllBlobRefs (line 208) | async function resolveAllBlobRefs(
  function hasUnresolvedBlobRefs (line 271) | function hasUnresolvedBlobRefs(obj: unknown): boolean {

FILE: addons/dexie-cloud/src/sync/connectWebSocket.ts
  function sleep (line 32) | function sleep(ms: number) {
  function waitAndReconnectWhenUserDoesSomething (line 36) | async function waitAndReconnectWhenUserDoesSomething(error: Error) {
  function connectWebSocket (line 49) | function connectWebSocket(db: DexieCloudDB) {

FILE: addons/dexie-cloud/src/sync/eagerBlobDownloader.ts
  function downloadUnresolvedBlobs (line 36) | async function downloadUnresolvedBlobs(

FILE: addons/dexie-cloud/src/sync/encodeIdsForServer.ts
  function encodeIdsForServer (line 10) | function encodeIdsForServer(
  function cloneChange (line 76) | function cloneChange(change: DBOperationsSet[number], rewriteValues: boo...

FILE: addons/dexie-cloud/src/sync/extractRealm.ts
  function extractRealm (line 3) | function extractRealm(obj: EntityCommon) {

FILE: addons/dexie-cloud/src/sync/getLatestRevisionsPerTable.ts
  function getLatestRevisionsPerTable (line 3) | function getLatestRevisionsPerTable(

FILE: addons/dexie-cloud/src/sync/getTablesToSyncify.ts
  function getTablesToSyncify (line 5) | function getTablesToSyncify(db: DexieCloudDB, syncState: PersistedSyncSt...

FILE: addons/dexie-cloud/src/sync/isSyncNeeded.ts
  function isSyncNeeded (line 4) | async function isSyncNeeded(db: DexieCloudDB) {

FILE: addons/dexie-cloud/src/sync/listClientChanges.ts
  function listClientChanges (line 7) | async function listClientChanges(
  function removeRedundantUpdateOps (line 71) | function removeRedundantUpdateOps(muts: DBOperation[]) {
  function canonicalizeToUpdateOps (line 128) | function canonicalizeToUpdateOps(muts: DBOperation[]) {

FILE: addons/dexie-cloud/src/sync/listSyncifiedChanges.ts
  function listSyncifiedChanges (line 13) | async function listSyncifiedChanges(

FILE: addons/dexie-cloud/src/sync/loadCachedAccessToken.ts
  function loadCachedAccessToken (line 7) | function loadCachedAccessToken(db: DexieCloudDB): Promise<string | null> {

FILE: addons/dexie-cloud/src/sync/messagesFromServerQueue.ts
  constant LIMIT_NUM_MESSAGES_PER_TIME (line 18) | const LIMIT_NUM_MESSAGES_PER_TIME = 10;
  constant TIME_WINDOW (line 19) | const TIME_WINDOW = 10_000;
  constant PAUSE_PERIOD (line 20) | const PAUSE_PERIOD = 1_000;
  type MessagesFromServerConsumer (line 22) | type MessagesFromServerConsumer = ReturnType<
  function MessagesFromServerConsumer (line 26) | function MessagesFromServerConsumer(db: DexieCloudDB) {

FILE: addons/dexie-cloud/src/sync/modifyLocalObjectsWithNewUserId.ts
  function modifyLocalObjectsWithNewUserId (line 8) | async function modifyLocalObjectsWithNewUserId(

FILE: addons/dexie-cloud/src/sync/numUnsyncedMutations.ts
  function getNumUnsyncedMutationsObservable (line 8) | function getNumUnsyncedMutationsObservable(db: DexieCloudDB) {

FILE: addons/dexie-cloud/src/sync/performGuardedJob.ts
  function performGuardedJob (line 3) | function performGuardedJob<T>(

FILE: addons/dexie-cloud/src/sync/ratelimit.ts
  function checkSyncRateLimitDelay (line 9) | async function checkSyncRateLimitDelay(db: DexieCloudDB) {
  function updateSyncRateLimitDelays (line 17) | function updateSyncRateLimitDelays(db: DexieCloudDB, res: Response) {

FILE: addons/dexie-cloud/src/sync/registerSyncEvent.ts
  function registerSyncEvent (line 6) | async function registerSyncEvent(db: DexieCloudDB, purpose: "push" | "pu...
  function registerPeriodicSyncEvent (line 33) | async function registerPeriodicSyncEvent(db: DexieCloudDB) {

FILE: addons/dexie-cloud/src/sync/sync.ts
  constant CURRENT_SYNC_WORKER (line 37) | const CURRENT_SYNC_WORKER = 'currentSyncWorker';
  type SyncOptions (line 39) | interface SyncOptions {
  function sync (line 47) | function sync(
  function _sync (line 100) | async function _sync(
  function deleteObjectsFromRemovedRealms (line 407) | async function deleteObjectsFromRemovedRealms(
  function filterServerChangesThroughAddedClientChanges (line 473) | function filterServerChangesThroughAddedClientChanges(

FILE: addons/dexie-cloud/src/sync/syncIfPossible.ts
  function syncIfPossible (line 14) | function syncIfPossible(

FILE: addons/dexie-cloud/src/sync/syncWithServer.ts
  function syncWithServer (line 20) | async function syncWithServer(

FILE: addons/dexie-cloud/src/sync/triggerSync.ts
  function triggerSync (line 4) | function triggerSync(db: DexieCloudDB, purpose: "push" | "pull") {

FILE: addons/dexie-cloud/src/sync/updateBaseRevs.ts
  function updateBaseRevs (line 4) | async function updateBaseRevs(db: DexieCloudDB, schema: DexieCloudSchema...

FILE: addons/dexie-cloud/src/types/DXCAlert.ts
  type DXCAlert (line 2) | type DXCAlert = DXCErrorAlert | DXCWarningAlert | DXCInfoAlert;
  type DXCErrorAlert (line 4) | interface DXCErrorAlert {
  type DXCWarningAlert (line 13) | interface DXCWarningAlert {
  type DXCInfoAlert (line 22) | interface DXCInfoAlert {

FILE: addons/dexie-cloud/src/types/DXCInputField.ts
  type DXCInputField (line 2) | type DXCInputField = DXCTextField | DXCPasswordField;
  type DXCTextField (line 4) | interface DXCTextField {
  type DXCPasswordField (line 10) | interface DXCPasswordField {

FILE: addons/dexie-cloud/src/types/DXCUserInteraction.ts
  type DXCUserInteraction (line 4) | type DXCUserInteraction =
  type DXCOption (line 20) | interface DXCOption {
  type DXCGenericUserInteraction (line 33) | interface DXCGenericUserInteraction<Type extends string="generic", TFiel...
  type DXCEmailPrompt (line 53) | interface DXCEmailPrompt {
  type DXCOTPPrompt (line 74) | interface DXCOTPPrompt {
  type DXCMessageAlert (line 91) | interface DXCMessageAlert {
  type DXCLogoutConfirmation (line 107) | interface DXCLogoutConfirmation {

FILE: addons/dexie-cloud/src/types/NewIdOptions.ts
  type NewIdOptions (line 1) | interface NewIdOptions {

FILE: addons/dexie-cloud/src/types/SWMessageEvent.ts
  type SWMessageEvent (line 1) | interface SWMessageEvent extends MessageEvent {

FILE: addons/dexie-cloud/src/types/SWSyncEvent.ts
  type SyncEvent (line 1) | type SyncEvent = Event & {

FILE: addons/dexie-cloud/src/types/SyncState.ts
  type SyncStatePhase (line 1) | type SyncStatePhase = "initial" | "not-in-sync" | "pushing" | "pulling" ...
  type SyncStatus (line 2) | type SyncStatus = "not-started" | "connecting" | "connected" | "disconne...
  type SyncState (line 3) | interface SyncState {

FILE: addons/dexie-cloud/src/types/TXExpandos.ts
  type TXExpandos (line 5) | interface TXExpandos {

FILE: addons/dexie-cloud/src/updateSchemaFromOptions.ts
  function updateSchemaFromOptions (line 4) | function updateSchemaFromOptions(schema?: DexieCloudSchema | null, optio...

FILE: addons/dexie-cloud/src/userIsActive.ts
  constant USER_INACTIVITY_TIMEOUT (line 14) | const USER_INACTIVITY_TIMEOUT = 180_000;
  constant ACTIVE_WAIT_TIME (line 15) | const ACTIVE_WAIT_TIME = 0;
  constant INACTIVE_WAIT_TIME (line 16) | const INACTIVE_WAIT_TIME = 20_000;

FILE: addons/dexie-cloud/src/verifyConfig.ts
  function verifyConfig (line 4) | function verifyConfig({databaseUrl}: DexieCloudOptions = {databaseUrl: "...

FILE: addons/dexie-cloud/src/verifySchema.ts
  function verifySchema (line 4) | function verifySchema(db: DexieCloudDB) {

FILE: addons/dexie-cloud/src/yjs/YDexieCloudSyncState.ts
  type YDexieCloudSyncState (line 2) | interface YDexieCloudSyncState extends YSyncState {

FILE: addons/dexie-cloud/src/yjs/YTable.ts
  type YTable (line 4) | type YTable = EntityTable<YUpdateRow, "i">;

FILE: addons/dexie-cloud/src/yjs/applyYMessages.ts
  function applyYServerMessages (line 8) | async function applyYServerMessages(

FILE: addons/dexie-cloud/src/yjs/createYClientUpdateObservable.ts
  function createYClientUpdateObservable (line 10) | function createYClientUpdateObservable(

FILE: addons/dexie-cloud/src/yjs/createYHandler.ts
  function createYHandler (line 14) | function createYHandler(db: DexieCloudDB) {
  function createAwareness (line 38) | function createAwareness(

FILE: addons/dexie-cloud/src/yjs/downloadYDocsFromServer.ts
  constant BINSTREAM_TYPE_REALMID (line 22) | const BINSTREAM_TYPE_REALMID = 1;
  constant BINSTREAM_TYPE_TABLE_AND_PROP (line 23) | const BINSTREAM_TYPE_TABLE_AND_PROP = 2;
  constant BINSTREAM_TYPE_DOCUMENT (line 24) | const BINSTREAM_TYPE_DOCUMENT = 3;
  function downloadYDocsFromServer (line 26) | async function downloadYDocsFromServer(

FILE: addons/dexie-cloud/src/yjs/getUpdatesTable.ts
  function getUpdatesTable (line 4) | function getUpdatesTable(db: DexieCloudDB, table: string, ydocProp: stri...

FILE: addons/dexie-cloud/src/yjs/listUpdatesSince.ts
  function listUpdatesSince (line 4) | function listUpdatesSince(yTable: Table, sinceIncluding: number): Promis...

FILE: addons/dexie-cloud/src/yjs/listYClientMessagesAndStateVector.ts
  function listYClientMessagesAndStateVector (line 26) | async function listYClientMessagesAndStateVector(

FILE: addons/dexie-cloud/src/yjs/reopenDocSignal.ts
  function getOpenDocSignal (line 13) | function getOpenDocSignal(doc: Y.Doc) {

FILE: addons/dexie-cloud/src/yjs/updateYSyncStates.ts
  function updateYSyncStates (line 7) | async function updateYSyncStates(

FILE: addons/dexie-cloud/test/promisedTest.ts
  function promisedTest (line 3) | function promisedTest(name: string, tester: ()=>Promise<any>) {

FILE: addons/dexie-cloud/test/unit/test-dexie-cloud-client.ts
  constant DATABASE_URL (line 16) | const DATABASE_URL = 'http://localhost:3000/ziud0envo';

FILE: addons/dexie-cloud/test/unit/tests-github-issues.ts
  constant DBURL (line 16) | const DBURL = 'https://zv8n7bwcs.dexie.cloud';
  function strip (line 160) | function strip(...props: string[]) {

FILE: addons/dexie-cloud/test/unit/tests-migrate-to-cloud.ts
  function v1DB (line 27) | function v1DB() {
  function v2DB (line 39) | function v2DB() {
  function cloudDB (line 58) | function cloudDB(
  function stepByStep (line 88) | async function stepByStep() {
  function stepOver2 (line 135) | async function stepOver2() {
  function openLastVersionDirectly (line 166) | async function openLastVersionDirectly() {
  function clearDataOnServer (line 181) | async function clearDataOnServer() {

FILE: addons/dexie-cloud/tools/build-configs/rollup.config.mjs
  function createBanner (line 15) | function createBanner() {
  function createRollupConfigs (line 31) | function createRollupConfigs(entry, outputName) {

FILE: addons/dexie-cloud/tools/build-configs/rollup.test.unit.config.js
  constant ERRORS_TO_IGNORE (line 9) | const ERRORS_TO_IGNORE = [
  method onwarn (line 41) | onwarn ({loc, frame, code, message}) {

FILE: addons/dexie-export-import/src/dexie-export-import.ts
  type Dexie (line 14) | interface Dexie {
  type DexieConstructor (line 18) | interface DexieConstructor {

FILE: addons/dexie-export-import/src/export.ts
  type ExportOptions (line 7) | interface ExportOptions {
  type ExportProgress (line 17) | interface ExportProgress {
  constant DEFAULT_ROWS_PER_CHUNK (line 25) | const DEFAULT_ROWS_PER_CHUNK = 2000;
  function exportDB (line 27) | async function exportDB(db: Dexie, options?: ExportOptions): Promise<Blo...

FILE: addons/dexie-export-import/src/helpers.ts
  function getSchemaString (line 4) | function getSchemaString(table: Dexie.Table<any, any>) {
  function extractDbSchema (line 9) | function extractDbSchema(exportedDb: DexieExportedDatabase) {
  type FileReaderSync (line 21) | interface FileReaderSync {
  type TypeMapper (line 33) | interface TypeMapper {
  function readBlobAsync (line 38) | function readBlobAsync<T extends keyof TypeMapper>(blob: Blob, type: T):...
  function readBlobSync (line 51) | function readBlobSync<T extends keyof TypeMapper>(blob: Blob, type: T): ...

FILE: addons/dexie-export-import/src/import.ts
  type StaticImportOptions (line 7) | interface StaticImportOptions {
  type ImportOptions (line 16) | interface ImportOptions extends StaticImportOptions {
  constant DEFAULT_KILOBYTES_PER_CHUNK (line 31) | const DEFAULT_KILOBYTES_PER_CHUNK = 1024;
  type ImportProgress (line 33) | interface ImportProgress {
  function importDB (line 41) | async function importDB(exportedData: Blob | JsonStream<DexieExportJsonS...
  function peakImportFile (line 52) | async function peakImportFile(exportedData: Blob): Promise<DexieExportJs...
  function importInto (line 65) | async function importInto(db: Dexie, exportedData: Blob | JsonStream<Dex...
  function loadUntilWeGotEnoughData (line 204) | async function loadUntilWeGotEnoughData(exportedData: Blob | JsonStream<...

FILE: addons/dexie-export-import/src/json-stream.ts
  type JsonStream (line 4) | interface JsonStream<T> {
  function JsonStream (line 12) | function JsonStream<T>(blob: Blob):  JsonStream<T> {
  function JsonParser (line 53) | function JsonParser (allowPartial: boolean) {

FILE: addons/dexie-export-import/src/json-structure.ts
  constant VERSION (line 1) | const VERSION = 1;
  type DexieExportJsonMeta (line 4) | interface DexieExportJsonMeta {
  type DexieExportJsonStructure (line 18) | interface DexieExportJsonStructure extends DexieExportJsonMeta {
  type DexieExportedDatabase (line 37) | type DexieExportedDatabase = DexieExportJsonStructure["data"];
  type DexieExportedTable (line 38) | type DexieExportedTable = DexieExportedDatabase["data"][number];

FILE: addons/dexie-export-import/src/tson-arraybuffer.ts
  method test (line 6) | test (x) { return Typeson.toStringTag(x) === 'ArrayBuffer'; }
  method replace (line 7) | replace (b) {
  method revive (line 10) | revive (b64) {

FILE: addons/dexie-export-import/src/tson-typed-array.ts
  method test (line 25) | test (x) { return Typeson.toStringTag(x) === arrType; }
  method replace (line 26) | replace ({buffer, byteOffset, length}) {
  method revive (line 33) | revive (b64Obj) {

FILE: addons/dexie-export-import/src/tson.ts
  constant TSON (line 9) | const TSON = new Typeson().register(StructuredCloning);
  method test (line 24) | test(x) { return Typeson.toStringTag(x) === 'Blob'; }
  method replace (line 25) | replace(b) {
  method finalize (line 46) | finalize(b, ba: ArrayBuffer) {
  method revive (line 49) | revive ({type, data}) {

FILE: addons/dexie-export-import/test/basic-tests.ts
  constant DATABASE_NAME (line 9) | const DATABASE_NAME = "dexie-export-import-basic-tests";
  constant IMPORT_DATA (line 10) | const IMPORT_DATA = getSimpleImportData(DATABASE_NAME);

FILE: addons/dexie-export-import/test/edge-cases.ts
  constant DATABASE_NAME (line 10) | const DATABASE_NAME = "dexie-export-import-edge-cases";
  constant IMPORT_DATA (line 11) | const IMPORT_DATA = getSimpleImportData(DATABASE_NAME);

FILE: addons/dexie-export-import/test/test-data.ts
  function getSimpleImportData (line 3) | function getSimpleImportData(databaseName: string): DexieExportJsonStruc...

FILE: addons/dexie-export-import/test/tools.ts
  function promisedTest (line 3) | function promisedTest(name: string, tester: ()=>Promise<any>) {
  function readBlob (line 19) | function readBlob(blob: Blob): Promise<string> {
  function readBlobBinary (line 23) | function readBlobBinary(blob: Blob): Promise<ArrayBuffer> {
  function deepEqual (line 28) | function deepEqual(a: any, b: any, description: string) {

FILE: addons/dexie-export-import/tools/build-configs/rollup.config.mjs
  constant ERRORS_TO_IGNORE (line 17) | const ERRORS_TO_IGNORE = [
  method onwarn (line 53) | onwarn ({loc, frame, code, message}) {

FILE: addons/dexie-export-import/tools/build-configs/rollup.tests.config.mjs
  constant ERRORS_TO_IGNORE (line 12) | const ERRORS_TO_IGNORE = [
  method onwarn (line 40) | onwarn ({loc, frame, code, message}) {

FILE: addons/y-dexie/src/DexieYProvider.ts
  function createEvents (line 13) | function createEvents() {
  type ReleaseOptions (line 17) | interface ReleaseOptions {
  class DexieYProvider (line 21) | class DexieYProvider
    method getOrCreateDocument (line 48) | static getOrCreateDocument(db: Dexie, table: string, prop: string, id:...
    method load (line 60) | static load(
    method release (line 85) | static release(doc: Y.Doc) {
    method _release (line 113) | private _release() {
    method for (line 133) | static for(doc: Y.Doc): DexieYProvider | undefined {
    method currentUpdateRow (line 137) | static get currentUpdateRow() {
    method whenLoaded (line 142) | get whenLoaded(): Promise<void> {
    method whenSynced (line 166) | get whenSynced(): Promise<void> {
    method constructor (line 189) | constructor(doc: Y.Doc) {
    method destroy (line 230) | destroy() {
    method addCleanupHandler (line 241) | addCleanupHandler(cleanupHandler: (() => void) | Unsubscribable) {
  type DexieYProvider (line 255) | interface DexieYProvider extends Disposable {}
    method getOrCreateDocument (line 48) | static getOrCreateDocument(db: Dexie, table: string, prop: string, id:...
    method load (line 60) | static load(
    method release (line 85) | static release(doc: Y.Doc) {
    method _release (line 113) | private _release() {
    method for (line 133) | static for(doc: Y.Doc): DexieYProvider | undefined {
    method currentUpdateRow (line 137) | static get currentUpdateRow() {
    method whenLoaded (line 142) | get whenLoaded(): Promise<void> {
    method whenSynced (line 166) | get whenSynced(): Promise<void> {
    method constructor (line 189) | constructor(doc: Y.Doc) {
    method destroy (line 230) | destroy() {
    method addCleanupHandler (line 241) | addCleanupHandler(cleanupHandler: (() => void) | Unsubscribable) {

FILE: addons/y-dexie/src/compressYDocs.ts
  function compressYDocs (line 12) | function compressYDocs(db: Dexie, skipIfRecentlyDoneMillisec?: number) {
  function compressYDocsTable (line 23) | function compressYDocsTable(
  function compressUpdatesForDoc (line 123) | function compressUpdatesForDoc(

FILE: addons/y-dexie/src/createYDocProperty.ts
  function createYDocProperty (line 7) | function createYDocProperty(

FILE: addons/y-dexie/src/createYjsMiddleware.ts
  constant EMPTY_ARRAY (line 7) | const EMPTY_ARRAY = [] as const;
  function createYjsMiddleware (line 9) | function createYjsMiddleware(dbSchema: DbSchema) {

FILE: addons/y-dexie/src/currentUpdateRow.ts
  function setCurrentUpdateRow (line 5) | function setCurrentUpdateRow(row: YUpdateRow | null) {

FILE: addons/y-dexie/src/docCache.ts
  function getDocCache (line 12) | function getDocCache(db: Dexie): YDocCache {
  function throwIfDestroyed (line 50) | function throwIfDestroyed(doc: any) {
  function getYDocCacheKey (line 55) | function getYDocCacheKey(table: string, primaryKey: any, ydocProp: strin...

FILE: addons/y-dexie/src/getOrCreateDocument.ts
  function getOrCreateDocument (line 7) | function getOrCreateDocument(

FILE: addons/y-dexie/src/helpers/Disposable.ts
  type Disposable (line 1) | type Disposable = typeof Symbol extends {

FILE: addons/y-dexie/src/helpers/nonStoppableEventChain.ts
  function nonStoppableEventChain (line 3) | function nonStoppableEventChain(f1: Function, f2: Function) {

FILE: addons/y-dexie/src/helpers/nop.ts
  function nop (line 1) | function nop() {}

FILE: addons/y-dexie/src/helpers/promisableChain.ts
  function promisableChain (line 3) | function promisableChain(f1, f2) {

FILE: addons/y-dexie/src/observeYDocUpdates.ts
  function observeYDocUpdates (line 11) | function observeYDocUpdates(

FILE: addons/y-dexie/src/periodicGC.ts
  constant GC_DELAY (line 4) | const GC_DELAY = 10_000;
  constant GC_INTERVAL (line 5) | const GC_INTERVAL = 300_000;
  function periodicGC (line 7) | function periodicGC(db: Dexie) {

FILE: addons/y-dexie/src/types/DexieYDocMeta.ts
  type DexieYDocMeta (line 3) | interface DexieYDocMeta {

FILE: addons/y-dexie/src/types/YDocCache.ts
  type YDocCache (line 3) | interface YDocCache {

FILE: addons/y-dexie/src/types/YLastCompressed.ts
  type YLastCompressed (line 7) | interface YLastCompressed {

FILE: addons/y-dexie/src/types/YSyncState.ts
  type YSyncState (line 6) | interface YSyncState {

FILE: addons/y-dexie/src/types/YUpdateRow.ts
  type YUpdateRow (line 6) | interface YUpdateRow {

FILE: addons/y-dexie/src/y-dexie.ts
  constant YJS_MIDDLEWARE_NAME (line 6) | const YJS_MIDDLEWARE_NAME = 'yjsMiddleware';
  type YDexieOptions (line 8) | interface YDexieOptions {
  function yDexie (line 16) | function yDexie(dbOrOptions: Dexie | YDexieOptions) {
  function configurableYDexie (line 32) | function configurableYDexie(db: Dexie, options: YDexieOptions) {

FILE: addons/y-dexie/test/promisedTest.ts
  function promisedTest (line 3) | function promisedTest(name: string, tester: ()=>Promise<any>) {

FILE: addons/y-dexie/test/qunit.d.ts
  type Assert (line 2) | interface Assert {

FILE: addons/y-dexie/test/unit/dexie-unittest-utils.js
  function stringify (line 26) | function stringify (idbKey) {
  function resetDatabase (line 32) | function resetDatabase(db) {
  function deleteDatabase (line 103) | function deleteDatabase(db) {
  function supports (line 136) | function supports (features) {
  function spawnedTest (line 163) | function spawnedTest (name, num, promiseGenerator) {
  function promisedTest (line 182) | function promisedTest (name, num, asyncFunction) {

FILE: addons/y-dexie/tools/build-configs/rollup.config.mjs
  function createBanner (line 15) | function createBanner() {
  function createRollupConfig (line 31) | function createRollupConfig(entry, outputName) {

FILE: addons/y-dexie/tools/build-configs/rollup.test.unit.config.js
  constant ERRORS_TO_IGNORE (line 9) | const ERRORS_TO_IGNORE = [
  method onwarn (line 38) | onwarn ({loc, frame, code, message}) {

FILE: libs/dexie-cloud-common/src/AuthProvidersResponse.ts
  type AuthProvidersResponse (line 4) | interface AuthProvidersResponse {

FILE: libs/dexie-cloud-common/src/AuthorizationCodeTokenRequest.ts
  type AuthorizationCodeTokenRequest (line 2) | interface AuthorizationCodeTokenRequest {

FILE: libs/dexie-cloud-common/src/BaseRevisionMapEntry.ts
  type BaseRevisionMapEntry (line 1) | interface BaseRevisionMapEntry {

FILE: libs/dexie-cloud-common/src/DBOperation.ts
  type DBOpPrimaryKey (line 2) | type DBOpPrimaryKey = string | (string | number)[];
  type DBCoreRangeType (line 4) | const enum DBCoreRangeType {
  type DBCoreKeyRange (line 15) | interface DBCoreKeyRange {
  type DBOperation (line 23) | type DBOperation<PK=DBOpPrimaryKey> =
  type DBOperationCommon (line 30) | interface DBOperationCommon<PK=DBOpPrimaryKey> {
  type DBInsertOperation (line 39) | interface DBInsertOperation<PK=DBOpPrimaryKey> extends DBOperationCommon...
  type DBUpsertOperation (line 44) | interface DBUpsertOperation<PK=DBOpPrimaryKey> extends DBOperationCommon...
  type DBUpdateOperation (line 50) | interface DBUpdateOperation<PK=DBOpPrimaryKey> extends DBOperationCommon...
  type DBModifyOperation (line 55) | interface DBModifyOperation<PK=DBOpPrimaryKey> extends DBOperationCommon...
  type DBDeleteOperation (line 65) | interface DBDeleteOperation<PK=DBOpPrimaryKey> extends DBOperationCommon...

FILE: libs/dexie-cloud-common/src/DBOperationsSet.ts
  type DBOperationsSet (line 3) | type DBOperationsSet<PK=DBOpPrimaryKey> = Array<{ table: string; muts: D...

FILE: libs/dexie-cloud-common/src/DBPermissionSet.ts
  type DBPermissionSet (line 4) | interface DBPermissionSet {

FILE: libs/dexie-cloud-common/src/DexieCloudSchema.ts
  type DexieCloudSchema (line 1) | type DexieCloudSchema = {

FILE: libs/dexie-cloud-common/src/OAuthProviderInfo.ts
  type OAuthProviderInfo (line 2) | interface OAuthProviderInfo {

FILE: libs/dexie-cloud-common/src/SyncChange.ts
  type SyncChange (line 1) | type SyncChange = UpsertSyncChange | UpdateSyncChange | DeleteSyncChange;
  type UpsertSyncChange (line 3) | interface UpsertSyncChange {
  type UpdateSyncChange (line 10) | interface UpdateSyncChange {
  type DeleteSyncChange (line 17) | interface DeleteSyncChange {

FILE: libs/dexie-cloud-common/src/SyncChangeSet.ts
  type SyncChangeSet (line 1) | type SyncChangeSet = {

FILE: libs/dexie-cloud-common/src/SyncRequest.ts
  type SyncRequest (line 6) | interface SyncRequest {

FILE: libs/dexie-cloud-common/src/SyncResponse.ts
  type SyncResponse (line 5) | interface SyncResponse {

FILE: libs/dexie-cloud-common/src/async-generators/asyncIterablePipeline.ts
  type AsyncSourceGeneratorFn (line 18) | type AsyncSourceGeneratorFn<Output> = () => AsyncGenerator<Output>;
  type AsyncGeneratorFn (line 19) | type AsyncGeneratorFn<Input, Output> = (input: AsyncGenerator<Input>) =>...
  function asyncIterablePipeline (line 20) | async function asyncIterablePipeline(source: AsyncSourceGeneratorFn<any>...

FILE: libs/dexie-cloud-common/src/async-generators/consumeChunkedBinaryStream.test.ts
  function generateInputData (line 7) | function generateInputData(chunkSize: number, numChunks = 4) {

FILE: libs/dexie-cloud-common/src/async-generators/getFetchResponseBodyGenerator.ts
  function getFetchResponseBodyGenerator (line 2) | function getFetchResponseBodyGenerator(res: Response) {

FILE: libs/dexie-cloud-common/src/change-processing/DBKeyMutation.ts
  type DBKeyMutation (line 1) | type DBKeyMutation =
  type DBKeyUpsert (line 6) | interface DBKeyUpsert {
  type DBKeyUpdate (line 11) | interface DBKeyUpdate {
  type DBKeyDelete (line 16) | interface DBKeyDelete {

FILE: libs/dexie-cloud-common/src/change-processing/DBKeyMutationSet.ts
  type DBKeyMutationSet (line 3) | type DBKeyMutationSet = {

FILE: libs/dexie-cloud-common/src/change-processing/applyOperation.ts
  function applyOperation (line 7) | function applyOperation(

FILE: libs/dexie-cloud-common/src/change-processing/applyOperations.ts
  function applyOperations (line 5) | function applyOperations(target: DBKeyMutationSet, ops: DBOperationsSet) {

FILE: libs/dexie-cloud-common/src/change-processing/subtractChanges.ts
  function subtractChanges (line 4) | function subtractChanges(

FILE: libs/dexie-cloud-common/src/change-processing/toDBOperationSet.ts
  function toDBOperationSet (line 11) | function toDBOperationSet(inSet: DBKeyMutationSet, txid?: string): DBOpe...

FILE: libs/dexie-cloud-common/src/change-processing/toSyncChangeSet.ts
  function toSyncChangeSet (line 12) | function toSyncChangeSet(inSet: DBKeyMutationSet): SyncChangeSet {

FILE: libs/dexie-cloud-common/src/common/b64lex.ts
  function b64LexEncode (line 3) | function b64LexEncode(b: Uint8Array | Buffer | ArrayBuffer): string {
  function b64LexDecode (line 7) | function b64LexDecode(b64Lex: string): Uint8Array {
  function b64ToLex (line 11) | function b64ToLex(base64: string): string {
  function lexToB64 (line 19) | function lexToB64(base64lex: string): string {
  constant DECODE_TABLE (line 33) | const DECODE_TABLE = {
  constant ENCODE_TABLE (line 101) | const ENCODE_TABLE = {};

FILE: libs/dexie-cloud-common/src/common/bigint-conversion.ts
  constant HEX_PARSER_REGEXP (line 4) | const HEX_PARSER_REGEXP = /[\da-f]{2}/gi;
  function buf2bigint (line 6) | function buf2bigint(buf: TypedArray | ArrayBuffer): bigint {
  function bigint2Buf (line 23) | function bigint2Buf(bi: bigint): Uint8Array {
  function bigint2B64 (line 33) | function bigint2B64(bi: bigint): string {
  function b64ToBigInt (line 37) | function b64ToBigInt(base64: string): bigint {

FILE: libs/dexie-cloud-common/src/entities/DBRealm.ts
  type DBRealm (line 3) | interface DBRealm extends DBSyncedObject {

FILE: libs/dexie-cloud-common/src/entities/DBRealmMember.ts
  type DBRealmMember (line 4) | interface DBRealmMember extends DBSyncedObject {

FILE: libs/dexie-cloud-common/src/entities/DBRealmRole.ts
  type DBRealmRole (line 4) | interface DBRealmRole extends DBSyncedObject {

FILE: libs/dexie-cloud-common/src/entities/DBSyncedObject.ts
  type DBSyncedObject (line 1) | interface DBSyncedObject {

FILE: libs/dexie-cloud-common/src/getDbNameFromDbUrl.ts
  function getDbNameFromDbUrl (line 1) | function getDbNameFromDbUrl(

FILE: libs/dexie-cloud-common/src/newId.ts
  function newId (line 38) | function newId(): string {

FILE: libs/dexie-cloud-common/src/tson/FakeBlob.ts
  class FakeBlob (line 1) | class FakeBlob {
    method constructor (line 2) | constructor(public buf: ArrayBuffer, public type?: string) {}

FILE: libs/dexie-cloud-common/src/tson/FakeFile.ts
  class FakeFile (line 6) | class FakeFile {
    method constructor (line 10) | constructor(blob: FakeBlob, name: string, lastModified: Date) {

FILE: libs/dexie-cloud-common/src/tson/StreamingSyncProcessor.ts
  type StreamSyncHeader (line 20) | interface StreamSyncHeader {
  type StreamSyncChanges (line 28) | interface StreamSyncChanges {
  type StreamSyncRealmComplete (line 42) | interface StreamSyncRealmComplete {
  type StreamSyncFooter (line 48) | interface StreamSyncFooter {
  type StreamSyncMessage (line 62) | type StreamSyncMessage =
  type StreamSyncProgress (line 75) | interface StreamSyncProgress {
  type BlobResolutionOptions (line 97) | interface BlobResolutionOptions {
  type StreamingSyncCallbacks (line 114) | interface StreamingSyncCallbacks {
  function isBlobRef (line 134) | function isBlobRef(value: unknown): value is TSONRef | TSONRefData {
  function collectBlobRefs (line 141) | function collectBlobRefs(obj: unknown, refs: TSONRef[] = []): TSONRef[] {
  function resolveAllBlobRefs (line 173) | async function resolveAllBlobRefs(
  function shouldSkipChunk (line 185) | function shouldSkipChunk(
  function processStreamingSync (line 220) | async function processStreamingSync(
  function buildSyncAcceptHeader (line 344) | function buildSyncAcceptHeader(supportsStreaming: boolean): string {
  function isStreamingResponse (line 354) | function isStreamingResponse(response: Response): boolean {

FILE: libs/dexie-cloud-common/src/tson/TSONRef.ts
  type TSONRefData (line 22) | interface TSONRefData {
  type TSONRefResolver (line 34) | type TSONRefResolver = (ref: TSONRef) => Promise<ArrayBuffer>;
  constant TSON_REF_SYMBOL (line 37) | const TSON_REF_SYMBOL = Symbol.for('TSONRef');
  class TSONRef (line 42) | class TSONRef<T extends ArrayBuffer | Blob | Uint8Array = ArrayBuffer> {
    method constructor (line 52) | constructor(
    method resolve (line 69) | async resolve(): Promise<T> {
    method reconstruct (line 86) | reconstruct(data: ArrayBuffer): ArrayBuffer | Blob | Uint8Array {
    method isTSONRef (line 145) | static isTSONRef(value: unknown): value is TSONRef {
    method isTSONRefData (line 157) | static isTSONRefData(value: unknown): value is TSONRefData {
    method fromData (line 170) | static fromData(data: TSONRefData): TSONRef {
    method toJSON (line 177) | toJSON(): TSONRefData {
  function hasTSONRefs (line 197) | function hasTSONRefs(obj: unknown): boolean {
  function collectTSONRefs (line 215) | function collectTSONRefs(obj: unknown, refs: TSONRef[] = []): TSONRef[] {
  function replaceTSONRefs (line 255) | async function replaceTSONRefs(
  function replaceRefsInPlace (line 293) | function replaceRefsInPlace(
  function resolveAllRefs (line 343) | async function resolveAllRefs(obj: unknown, concurrency = 5): Promise<vo...

FILE: libs/dexie-cloud-common/src/tson/TypeDef.ts
  type TypeDef (line 3) | interface TypeDef<T = unknown, TReplaced = unknown> {

FILE: libs/dexie-cloud-common/src/tson/TypeDefSet.ts
  type TypeDefSet (line 3) | type TypeDefSet = {

FILE: libs/dexie-cloud-common/src/tson/TypesonSimplified.ts
  function getToStringTag (line 5) | function getToStringTag(val: any) {
  function escapeDollarProps (line 9) | function escapeDollarProps(value: any) {
  function TypesonSimplified (line 33) | function TypesonSimplified(...typeDefsInputs: TypeDefSet[]) {

FILE: libs/dexie-cloud-common/src/tson/readBlobSync.ts
  function readBlobSync (line 1) | function readBlobSync(b: Blob): string {

FILE: libs/dexie-cloud-common/src/tson/readableStreamIterator.ts
  function fill (line 23) | async function fill() {
  function bytesLeft (line 32) | function bytesLeft() {
  function read (line 36) | function read(num: number): Blob {

FILE: libs/dexie-cloud-common/src/tson/string2ArrayBuffer.ts
  function string2ArrayBuffer (line 1) | function string2ArrayBuffer(str: string): ArrayBuffer {
  function arrayBuffer2String (line 9) | function arrayBuffer2String(buf: ArrayBuffer): string {

FILE: libs/dexie-cloud-common/src/tson/types/BlobRef.ts
  constant BLOB_THRESHOLD (line 13) | const BLOB_THRESHOLD = 4 * 1024;
  type BlobStore (line 18) | interface BlobStore {
  type BlobRefContext (line 26) | interface BlobRefContext {
  function createBlobRefContext (line 40) | function createBlobRefContext(

FILE: libs/dexie-cloud-common/src/types.ts
  type TokenRequest (line 3) | type TokenRequest =
  type OTPTokenRequest (line 11) | type OTPTokenRequest = OTPTokenRequest1 | OTPTokenRequest2;
  type OTPTokenRequest1 (line 12) | interface OTPTokenRequest1 {
  type OTPTokenRequest2 (line 18) | interface OTPTokenRequest2 {
  type ClientCredentialsTokenRequest (line 26) | interface ClientCredentialsTokenRequest {
  type RefreshTokenRequest (line 42) | interface RefreshTokenRequest {
  type DemoTokenRequest (line 52) | interface DemoTokenRequest {
  type TokenFinalResponse (line 59) | interface TokenFinalResponse {
  type TokenOtpSentResponse (line 82) | interface TokenOtpSentResponse {
  type TokenOtpDetailsResponse (line 86) | interface TokenOtpDetailsResponse {
  type TokenErrorResponse (line 93) | interface TokenErrorResponse {
  type TokenResponseInvalidTimestamp (line 110) | interface TokenResponseInvalidTimestamp {
  type TokenResponse (line 116) | type TokenResponse =
  type CreateDbResponse (line 123) | interface CreateDbResponse {
  type WhitelistRequest (line 129) | interface WhitelistRequest {
  type WhitelistResponse (line 134) | type WhitelistResponse = number | string[];
  type ClientsResponse (line 136) | type ClientsResponse = DXCClient[];
  type DXCClient (line 138) | interface DXCClient {

FILE: libs/dexie-cloud-common/src/typings/TypedArray.ts
  type TypedArray (line 1) | type TypedArray =

FILE: libs/dexie-cloud-common/src/utils.ts
  function assert (line 1) | function assert(b: boolean): asserts b is true {
  function hasOwn (line 6) | function hasOwn(obj, prop) {
  type SetByKeyPathTarget (line 10) | type SetByKeyPathTarget =
  function setByKeyPath (line 14) | function setByKeyPath(
  function simpleRandomFill (line 71) | function simpleRandomFill(buf: Uint8Array) {

FILE: libs/dexie-cloud-common/src/validation/isValidSyncableID.ts
  function isValidSyncableID (line 18) | function isValidSyncableID(id: any) {
  function isValidSyncableIDPart (line 33) | function isValidSyncableIDPart(part: any) {
  function isValidAtID (line 37) | function isValidAtID(id: any, idPrefix?: string): id is string {

FILE: libs/dexie-cloud-common/src/validation/toStringTag.ts
  function toStringTag (line 2) | function toStringTag(o: Object) {

FILE: libs/dexie-cloud-common/src/yjs/YMessage.ts
  type YMessage (line 1) | type YMessage = YClientMessage | YServerMessage;
  type YClientMessage (line 3) | type YClientMessage =
  type YServerMessage (line 10) | type YServerMessage =
  type YUpdateFromClientRequest (line 20) | interface YUpdateFromClientRequest {
  type YDocumentOpen (line 29) | interface YDocumentOpen {
  type YStateVector (line 38) | interface YStateVector {
  type YDocumentClose (line 46) | interface YDocumentClose {
  type YUpdateFromClientAck (line 53) | interface YUpdateFromClientAck {
  type YUpdateFromClientReject (line 60) | interface YUpdateFromClientReject {
  type YUpdateFromServerMessage (line 67) | interface YUpdateFromServerMessage {
  type YAwarenessUpdate (line 76) | interface YAwarenessUpdate {
  type YInSyncMessage (line 84) | interface YInSyncMessage {
  type YCompleteSyncDone (line 91) | interface YCompleteSyncDone {
  type YOutdatedServerRevNotice (line 96) | interface YOutdatedServerRevNotice {

FILE: libs/dexie-cloud-common/src/yjs/decoding.ts
  function decodeYMessage (line 10) | function decodeYMessage(a: Uint8Array): YMessage {

FILE: libs/dexie-cloud-common/src/yjs/encoding.ts
  function encodeYMessage (line 11) | function encodeYMessage(msg: YMessage): Uint8Array {

FILE: libs/dexie-react-hooks/rollup.config.mjs
  constant ERRORS_TO_IGNORE (line 9) | const ERRORS_TO_IGNORE = [
  method onwarn (line 39) | onwarn ({loc, frame, code, message}) {

FILE: libs/dexie-react-hooks/src/types/y-dexie.d.ts
  type YDoc (line 5) | type YDoc = {
  type DexieYProvider (line 10) | type DexieYProvider = {
  type YUpdateRow (line 22) | type YUpdateRow = any;
  type YSyncState (line 23) | type YSyncState = any;

FILE: libs/dexie-react-hooks/src/types/yjs.d.ts
  type Doc (line 3) | type Doc = {

FILE: libs/dexie-react-hooks/src/useDocument.ts
  type DexieYProvider (line 9) | type DexieYProvider = import('y-dexie').DexieYProvider;
  type DexieYProviderConstructor (line 10) | type DexieYProviderConstructor = typeof import('y-dexie').DexieYProvider;
  type YDoc (line 11) | type YDoc = import('yjs').Doc;
  function useDocument (line 21) | function useDocument(

FILE: libs/dexie-react-hooks/src/useLiveQuery.ts
  function useLiveQuery (line 13) | function useLiveQuery<T, TDefault>(

FILE: libs/dexie-react-hooks/src/useObservable.ts
  type InteropableObservable (line 2) | interface InteropableObservable<T> {
  type AnySubscription (line 11) | type AnySubscription = { unsubscribe(): any } | (() => any);
  function useObservable (line 29) | function useObservable<T, TDefault>(

FILE: libs/dexie-react-hooks/src/usePermissions.ts
  type KeyPaths (line 5) | type KeyPaths<T> = {
  type TableProp (line 19) | type TableProp<DX extends Dexie> = {
  type DexieCloudEntity (line 24) | interface DexieCloudEntity {
  type PermissionChecker (line 30) | interface PermissionChecker<T, TableName extends string> {
  function usePermissions (line 46) | function usePermissions(

FILE: libs/dexie-react-hooks/src/usePromise.ts
  function fallbackUsePromise (line 10) | function fallbackUsePromise<T>(promise: PromiseLike<T>): T {
  constant PROMISE_STATE_MAP (line 36) | const PROMISE_STATE_MAP = new WeakMap<

FILE: libs/dexie-react-hooks/src/useSuspendingLiveQuery.ts
  function useSuspendingLiveQuery (line 11) | function useSuspendingLiveQuery<T>(

FILE: libs/dexie-react-hooks/src/useSuspendingObservable.ts
  constant CLEANUP_DELAY (line 9) | const CLEANUP_DELAY = 3000;
  function useSuspendingObservable (line 18) | function useSuspendingObservable<T>(

FILE: libs/dexie-react-hooks/test/components/App.tsx
  function App (line 7) | function App() {

FILE: libs/dexie-react-hooks/test/components/ErrorBoundrary.tsx
  class ErrorBoundary (line 3) | class ErrorBoundary extends Component<React.PropsWithChildren<{}>, { err...
    method constructor (line 4) | constructor(props: React.PropsWithChildren<{}>) {
    method getDerivedStateFromError (line 9) | static getDerivedStateFromError(error: any) {
    method componentDidCatch (line 14) | componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    method render (line 18) | render() {

FILE: libs/dexie-react-hooks/test/components/ItemComponent.tsx
  type Props (line 4) | interface Props {
  function ItemComponent (line 8) | function ItemComponent({ item: {id, name }}: Props) {

FILE: libs/dexie-react-hooks/test/components/ItemListComponent.tsx
  type Props (line 6) | interface Props {
  function ItemListComponent (line 10) | function ItemListComponent({ loadItems }: Props) {

FILE: libs/dexie-react-hooks/test/components/ItemLoaderComponent.tsx
  type Props (line 6) | interface Props {
  function ItemLoaderComponent (line 11) | function ItemLoaderComponent({ id, loadItem }: Props) {

FILE: libs/dexie-react-hooks/test/db/index.ts
  class TestUseLiveQueryDB (line 4) | class TestUseLiveQueryDB extends Dexie {
    method constructor (line 7) | constructor() {

FILE: libs/dexie-react-hooks/test/index.ts
  method beforeEach (line 18) | async beforeEach(assert) {

FILE: libs/dexie-react-hooks/test/models/Item.ts
  type Item (line 1) | interface Item {

FILE: libs/dexie-react-hooks/test/utils/BinarySemaphore.ts
  class BinarySemaphore (line 1) | class BinarySemaphore {
    method constructor (line 2) | constructor() {
    method reset (line 7) | reset() {
    method init (line 11) | private init() {

FILE: libs/dexie-react-hooks/test/utils/closest.ts
  function closest (line 1) | function closest(node: Node, selector: string) {

FILE: libs/dexie-react-hooks/test/utils/sleep.ts
  function sleep (line 1) | function sleep(ms: number, signal?: AbortSignal) {

FILE: libs/dexie-react-hooks/test/utils/timeout.ts
  function timeout (line 1) | function timeout(ms): AbortSignal {

FILE: libs/dexie-react-hooks/test/utils/waitTilEqual.ts
  function waitTilEqual (line 3) | function waitTilEqual(

FILE: libs/dexie-react-hooks/test/utils/waitTilOk.ts
  function waitTilOk (line 3) | function waitTilOk(

FILE: libs/dexie-svelte-query/src/lib/stateQuery.svelte.ts
  function stateQuery (line 3) | function stateQuery<T>(querier: () => T | Promise<T>, dependencies?: () ...

FILE: samples/angular/src/app/app.component.ts
  class AppComponent (line 71) | class AppComponent {
    method addNewList (line 80) | async addNewList() {

FILE: samples/angular/src/app/db.ts
  type TodoList (line 5) | interface TodoList {
  type TodoItem (line 10) | interface TodoItem {

FILE: samples/angular/src/app/item-list.component.ts
  class ItemListComponent (line 126) | class ItemListComponent {
    method addItem (line 145) | async addItem() {
    method toggleItem (line 156) | async toggleItem(item: TodoItem) {
    method deleteItem (line 160) | async deleteItem(id: number) {
    method deleteList (line 164) | async deleteList() {

FILE: samples/dexie-cloud-todo-app/src/App.tsx
  function App (line 12) | function App() {
  function LicenseAdvertiseExample (line 33) | function LicenseAdvertiseExample() {
  function deleteUserAccount (line 110) | async function deleteUserAccount(user: UserLogin) {

FILE: samples/dexie-cloud-todo-app/src/components/AddTodoItem.tsx
  type Props (line 9) | interface Props {
  function AddTodoItem (line 14) | function AddTodoItem({ todoList, autoFocus }: Props) {

FILE: samples/dexie-cloud-todo-app/src/components/AddTodoList.tsx
  function AddTodoList (line 9) | function AddTodoList() {

FILE: samples/dexie-cloud-todo-app/src/components/ResetDatabaseButton.tsx
  function ResetDatabaseButton (line 5) | function ResetDatabaseButton() {

FILE: samples/dexie-cloud-todo-app/src/components/TodoItemView.tsx
  type Props (line 11) | interface Props {
  function TodoItemView (line 15) | function TodoItemView({ item }: Props) {

FILE: samples/dexie-cloud-todo-app/src/components/TodoListView.tsx
  type Props (line 14) | interface Props {
  function TodoListView (line 19) | function TodoListView({ todoList, autoFocus }: Props) {

FILE: samples/dexie-cloud-todo-app/src/components/TodoLists.tsx
  function TodoLists (line 5) | function TodoLists() {

FILE: samples/dexie-cloud-todo-app/src/components/access-control/EditMember.tsx
  type Props (line 7) | interface Props {
  function EditMember (line 12) | function EditMember({ member, todoList }: Props) {

FILE: samples/dexie-cloud-todo-app/src/components/access-control/EditMemberAccess.tsx
  type Props (line 5) | interface Props {
  function EditMemberAccess (line 11) | function EditMemberAccess({ todoList, member, access }: Props) {
  function changeAccess (line 36) | async function changeAccess(

FILE: samples/dexie-cloud-todo-app/src/components/access-control/Invites.tsx
  function Invites (line 7) | function Invites() {

FILE: samples/dexie-cloud-todo-app/src/components/access-control/SharingForm.tsx
  type Props (line 12) | interface Props {
  function SharingForm (line 16) | function SharingForm({ todoList }: Props) {
  function MemberRow (line 134) | function MemberRow({

FILE: samples/dexie-cloud-todo-app/src/components/navbar/NavBar.tsx
  function NavBar (line 19) | function NavBar() {

FILE: samples/dexie-cloud-todo-app/src/components/navbar/SyncStatusIcon.tsx
  type Props (line 13) | interface Props {
  function SyncStatusIcon (line 17) | function SyncStatusIcon({ className }: Props) {

FILE: samples/dexie-cloud-todo-app/src/components/ui/CheckedSign.tsx
  type CheckedSignProps (line 3) | interface CheckedSignProps {
  function CheckedSign (line 7) | function CheckedSign({ className }: CheckedSignProps) {

FILE: samples/dexie-cloud-todo-app/src/components/ui/button.tsx
  type ButtonProps (line 36) | interface ButtonProps

FILE: samples/dexie-cloud-todo-app/src/components/ui/checkbox.tsx
  type CheckboxProps (line 5) | interface CheckboxProps

FILE: samples/dexie-cloud-todo-app/src/components/ui/input.tsx
  type InputProps (line 5) | interface InputProps

FILE: samples/dexie-cloud-todo-app/src/db/TodoDB.ts
  class TodoDB (line 6) | class TodoDB extends Dexie {
    method constructor (line 11) | constructor() {

FILE: samples/dexie-cloud-todo-app/src/db/TodoItem.ts
  type TodoItem (line 1) | interface TodoItem {

FILE: samples/dexie-cloud-todo-app/src/db/TodoList.ts
  class TodoList (line 16) | class TodoList extends Entity<TodoDB> {
    method isSharable (line 30) | isSharable() {
    method makeSharable (line 48) | async makeSharable() {
    method makePrivate (line 89) | async makePrivate() {
    method shareWith (line 138) | async shareWith(
    method unshareWith (line 182) | async unshareWith(member: DBRealmMember) {
    method leaveList (line 194) | async leaveList() {
    method deleteList (line 213) | async deleteList() {
    method changeOwner (line 264) | async changeOwner(userId: string) {
    method changeMemberRole (line 292) | async changeMemberRole(member: DBRealmMember, role: string) {

FILE: samples/dexie-cloud-todo-app/src/db/logout.ts
  function logout (line 3) | function logout() {

FILE: samples/dexie-cloud-todo-app/src/helpers/handleError.ts
  function handleError (line 1) | function handleError<TArgs extends any[], TResult>(

FILE: samples/dexie-cloud-todo-app/src/helpers/usePersistedOpenState.ts
  function usePersistedOpenState (line 4) | function usePersistedOpenState(

FILE: samples/dexie-cloud-todo-app/src/lib/utils.ts
  function cn (line 4) | function cn(...inputs: ClassValue[]) {

FILE: samples/dexie-cloud-todo-app/src/serviceWorkerRegistration.ts
  type Config (line 4) | type Config = {
  function register (line 11) | function register(config?: Config) {
  function unregister (line 68) | function unregister() {

FILE: samples/dexie-cloud-todo-app/src/vite-env.d.ts
  type ImportMetaEnv (line 6) | interface ImportMetaEnv {
  type ImportMeta (line 12) | interface ImportMeta {

FILE: samples/full-text-search/FullTextSearch.js
  function getAllWords (line 29) | function getAllWords(text) {

FILE: samples/remote-sync/ajax/jquery-2.1.0.js
  function isArraylike (line 537) | function isArraylike( obj ) {
  function Sizzle (line 732) | function Sizzle( selector, context, results, seed ) {
  function createCache (line 847) | function createCache() {
  function markFunction (line 865) | function markFunction( fn ) {
  function assert (line 874) | function assert( fn ) {
  function addHandle (line 896) | function addHandle( attrs, handler ) {
  function siblingCheck (line 911) | function siblingCheck( a, b ) {
  function createInputPseudo (line 938) | function createInputPseudo( type ) {
  function createButtonPseudo (line 949) | function createButtonPseudo( type ) {
  function createPositionalPseudo (line 960) | function createPositionalPseudo( fn ) {
  function testContext (line 983) | function testContext( context ) {
  function setFilters (line 1977) | function setFilters() {}
  function tokenize (line 1981) | function tokenize( selector, parseOnly ) {
  function toSelector (line 2048) | function toSelector( tokens ) {
  function addCombinator (line 2058) | function addCombinator( matcher, combinator, base ) {
  function elementMatcher (line 2111) | function elementMatcher( matchers ) {
  function condense (line 2125) | function condense( unmatched, map, filter, context, xml ) {
  function setMatcher (line 2146) | function setMatcher( preFilter, selector, matcher, postFilter, postFinde...
  function matcherFromTokens (line 2239) | function matcherFromTokens( tokens ) {
  function matcherFromGroupMatchers (line 2294) | function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
  function multipleContexts (line 2420) | function multipleContexts( selector, contexts, results ) {
  function select (line 2429) | function select( selector, context, results, seed ) {
  function winnow (line 2581) | function winnow( elements, qualifier, not ) {
  function sibling (line 2906) | function sibling( cur, dir ) {
  function createOptions (line 2984) | function createOptions( options ) {
  function completed (line 3377) | function completed() {
  function Data (line 3482) | function Data() {
  function dataAttr (line 3674) | function dataAttr( elem, key, data ) {
  function returnTrue (line 4002) | function returnTrue() {
  function returnFalse (line 4006) | function returnFalse() {
  function safeActiveElement (line 4010) | function safeActiveElement() {
  function manipulationTarget (line 4873) | function manipulationTarget( elem, content ) {
  function disableScript (line 4883) | function disableScript( elem ) {
  function restoreScript (line 4887) | function restoreScript( elem ) {
  function setGlobalEval (line 4900) | function setGlobalEval( elems, refElements ) {
  function cloneCopyEvent (line 4911) | function cloneCopyEvent( src, dest ) {
  function getAll (line 4945) | function getAll( context, tag ) {
  function fixInput (line 4956) | function fixInput( src, dest ) {
  function actualDisplay (line 5414) | function actualDisplay( name, doc ) {
  function defaultDisplay (line 5435) | function defaultDisplay( nodeName ) {
  function curCSS (line 5475) | function curCSS( elem, name, computed ) {
  function addGetHookIf (line 5523) | function addGetHookIf( conditionFn, hookFn ) {
  function computePixelPositionAndBoxSizingReliable (line 5562) | function computePixelPositionAndBoxSizingReliable() {
  function vendorPropName (line 5657) | function vendorPropName( style, name ) {
  function setPositiveNumber (line 5679) | function setPositiveNumber( elem, value, subtract ) {
  function augmentWidthOrHeight (line 5687) | function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
  function getWidthOrHeight (line 5726) | function getWidthOrHeight( elem, name, extra ) {
  function showHide (line 5770) | function showHide( elements, show ) {
  function Tween (line 6073) | function Tween( elem, options, prop, end, easing ) {
  function createFxNow (line 6242) | function createFxNow() {
  function genFx (line 6250) | function genFx( type, includeWidth ) {
  function createTween (line 6270) | function createTween( value, prop, animation ) {
  function defaultPrefilter (line 6284) | function defaultPrefilter( elem, props, opts ) {
  function propFilter (line 6411) | function propFilter( props, specialEasing ) {
  function Animation (line 6448) | function Animation( elem, properties, options ) {
  function addToPrefiltersOrTransports (line 7505) | function addToPrefiltersOrTransports( structure ) {
  function inspectPrefiltersOrTransports (line 7537) | function inspectPrefiltersOrTransports( structure, options, originalOpti...
  function ajaxExtend (line 7564) | function ajaxExtend( target, src ) {
  function ajaxHandleResponses (line 7584) | function ajaxHandleResponses( s, jqXHR, responses ) {
  function ajaxConvert (line 7640) | function ajaxConvert( s, response, jqXHR, isSuccess ) {
  function done (line 8097) | function done( status, nativeStatusText, responses, headers ) {
  function buildParams (line 8349) | function buildParams( prefix, obj, traditional, add ) {
  function getWindow (line 8827) | function getWindow( elem ) {

FILE: samples/remote-sync/websocket/WebSocketSyncProtocol.js
  function sendChanges (line 29) | function sendChanges(changes, baseRevision, partial, onChangesAccepted) {

FILE: samples/remote-sync/websocket/WebSocketSyncServer.js
  function SyncServer (line 24) | function SyncServer(port) {
  function reduceChanges (line 289) | function reduceChanges(changes) {
  function resolveConflicts (line 330) | function resolveConflicts(clientChanges, serverChangeSet) {
  function deepClone (line 374) | function deepClone(obj) {
  function applyModifications (line 378) | function applyModifications(obj, modifications) {
  function combineCreateAndUpdate (line 385) | function combineCreateAndUpdate(prevChange, nextChange) {
  function combineUpdateAndUpdate (line 391) | function combineUpdateAndUpdate(prevChange, nextChange) {
  function setByKeyPath (line 413) | function setByKeyPath(obj, keyPath, value) {

FILE: samples/remote-sync/websocket/websocketserver-shim.js
  function EmulatedWebSocketServerFactory (line 15) | function EmulatedWebSocketServerFactory() {
  function EmulatedWebSocket (line 61) | function EmulatedWebSocket(url) {
  function parseURL (line 110) | function parseURL(url) {
  function override (line 138) | function override(origFunc, overridedFactory) {

FILE: samples/vue/src/database.js
  class Database (line 9) | class Database extends Dexie {
    method constructor (line 10) | constructor() {
    method getTodos (line 35) | async getTodos(order) {
    method setTodoDone (line 69) | setTodoDone(id, done) {
    method addTodo (line 75) | addTodo(text) {
    method deleteTodo (line 82) | deleteTodo(todoID) {

FILE: src/classes/collection/collection-constructor.ts
  type CollectionConstructor (line 10) | interface CollectionConstructor {
  function createCollectionConstructor (line 21) | function createCollectionConstructor(db: Dexie) {

FILE: src/classes/collection/collection-helpers.ts
  type CollectionContext (line 9) | type CollectionContext = Collection["_ctx"];
  function isPlainKeyRange (line 11) | function isPlainKeyRange (ctx: CollectionContext, ignoreLimitFilter?: bo...
  function addFilter (line 16) | function addFilter(ctx: CollectionContext, fn: Function) {
  function addReplayFilter (line 20) | function addReplayFilter (ctx: CollectionContext, factory, isLimitFilter...
  function addMatchFilter (line 26) | function addMatchFilter(ctx: CollectionContext, fn) {
  function getIndexOrStore (line 30) | function getIndexOrStore(ctx: CollectionContext, coreSchema: DBCoreTable...
  function openCursor (line 39) | function openCursor(ctx: CollectionContext, coreTable: DBCoreTable, tran...
  function iter (line 53) | function iter (
  function iterate (line 86) | function iterate(cursorPromise: Promise<DBCoreCursor>, filter, fn, value...

FILE: src/classes/collection/collection.ts
  class Collection (line 24) | class Collection implements ICollection {
    method _read (line 48) | _read<T>(fn: (idbtrans: IDBTransaction, dxTrans: Transaction) => Promi...
    method _write (line 55) | _write<T>(fn: (idbtrans: IDBTransaction, dxTrans: Transaction) => Prom...
    method _addAlgorithm (line 62) | _addAlgorithm(fn) {
    method _iterate (line 67) | _iterate(
    method clone (line 79) | clone(props?): this {
    method raw (line 92) | raw(): this {
    method each (line 102) | each(fn: (obj, cursor: DBCoreCursor) => any): PromiseExtended<void> {
    method count (line 113) | count(cb?) {
    method sortBy (line 142) | sortBy(keyPath: string, cb?: ThenShortcut<any[], any>) {
    method toArray (line 167) | toArray(cb?): PromiseExtended<any[]> {
    method offset (line 198) | offset(offset: number) : Collection{
    method limit (line 229) | limit(numRows: number) : Collection {
    method until (line 246) | until(filterFunction: (x) => boolean, bIncludeStopEntry?) {
    method first (line 263) | first(cb?) {
    method last (line 272) | last(cb?) {
    method filter (line 281) | filter(filterFunction: (x) => boolean): Collection {
    method and (line 297) | and(filter: (x) => boolean) {
    method or (line 306) | or(indexName: string) {
    method reverse (line 315) | reverse() {
    method desc (line 326) | desc() {
    method eachKey (line 335) | eachKey(cb?) {
    method eachUniqueKey (line 346) | eachUniqueKey(cb?) {
    method eachPrimaryKey (line 356) | eachPrimaryKey(cb?) {
    method keys (line 367) | keys(cb?) {
    method primaryKeys (line 383) | primaryKeys(cb?) : PromiseExtended<IndexableType[]> {
    method uniqueKeys (line 415) | uniqueKeys(cb?) {
    method firstKey (line 425) | firstKey(cb?) {
    method lastKey (line 434) | lastKey(cb?) {
    method distinct (line 443) | distinct() {
    method modify (line 466) | modify(changes: UpdateSpec<any> | ((obj: any, ctx:{value: any, primKey...
    method delete (line 596) | delete() : PromiseExtended<number> {

FILE: src/classes/dexie/dexie-open.ts
  function dexieOpen (line 21) | function dexieOpen (db: Dexie) {

FILE: src/classes/dexie/dexie-static-props.ts
  method delete (line 54) | delete(databaseName: string) {
  method exists (line 62) | exists(name: string) {
  method getDatabaseNames (line 72) | getDatabaseNames(cb) {
  method defineClass (line 81) | defineClass() {
  method ignoreTransaction (line 88) | ignoreTransaction(scopeFunc) {

FILE: src/classes/dexie/dexie.ts
  type DbReadyState (line 51) | interface DbReadyState {
  class Dexie (line 66) | class Dexie implements IDexie {
    method constructor (line 97) | constructor(name: string, options?: DexieOptions) {
    method version (line 263) | version(versionNumber: number): Version {
    method _whenReady (line 282) | _whenReady<T>(fn: () => Promise<T>): Promise<T> {
    method use (line 300) | use({stack, create, level, name}: Middleware<DBCore>): this {
    method unuse (line 312) | unuse({stack, name, create}: {stack: keyof DexieStacks, name?: string,...
    method open (line 322) | open() {
    method _close (line 329) | _close(): void {
    method close (line 351) | close({disableAutoOpen} = {disableAutoOpen: true}): void {
    method delete (line 370) | delete(closeOptions = {disableAutoOpen: true}): Promise<void> {
    method backendDB (line 395) | backendDB() {
    method isOpen (line 399) | isOpen() {
    method hasBeenClosed (line 403) | hasBeenClosed() {
    method hasFailed (line 408) | hasFailed() {
    method dynamicallyOpened (line 412) | dynamicallyOpened() {
    method tables (line 416) | get tables () {
    method transaction (line 420) | transaction(): Promise {
    method _transaction (line 425) | _transaction(mode: TransactionMode, tables: Array<ITable | string>, sc...
    method table (line 499) | table(tableName: string): Table {

FILE: src/classes/dexie/generate-middleware-stacks.ts
  function createMiddlewareStack (line 8) | function createMiddlewareStack<TStack extends {stack: string}>(
  function createMiddlewareStacks (line 14) | function createMiddlewareStacks(
  function generateMiddlewareStacks (line 32) | function generateMiddlewareStacks(db: Dexie, tmpTrans: IDBTransaction) {

FILE: src/classes/dexie/transaction-helpers.ts
  function extractTransactionArgs (line 15) | function extractTransactionArgs(mode: TransactionMode, _tableArgs_, scop...
  function enterTransactionScope (line 29) | function enterTransactionScope(

FILE: src/classes/dexie/vip.ts
  function vip (line 4) | function vip (fn) {

FILE: src/classes/entity/Entity.ts
  function Entity (line 3) | function Entity(){

FILE: src/classes/observable/observable.ts
  class Observable (line 12) | class Observable<T> implements IObservable<T> {
    method constructor (line 17) | constructor(subscribe: (observer: Observer<T>) => Subscription) {
    method subscribe (line 27) | subscribe(x?: any, error?: any, complete?: any): Subscription {
    method [symbolObservable] (line 33) | [symbolObservable]() {

FILE: src/classes/table/table-constructor.ts
  type TableConstructor (line 10) | interface TableConstructor {
  function createTableConstructor (line 21) | function createTableConstructor (db: Dexie) {

FILE: src/classes/table/table-helpers.ts
  function builtInDeletionTrigger (line 5) | function builtInDeletionTrigger (table: Table, keys: null | readonly any...

FILE: src/classes/table/table.ts
  class Table (line 29) | class Table implements ITable<any, IndexableType> {
    method _trans (line 37) | _trans(
    method get (line 90) | get(keyOrCrit, cb?) {
    method where (line 106) | where(indexOrCrit: string | string[] | { [key: string]: IndexableType ...
    method filter (line 185) | filter(filterFunction: (obj: any) => boolean) {
    method count (line 194) | count(thenShortcut?: any) {
    method offset (line 203) | offset(offset: number) {
    method limit (line 212) | limit(numRows: number) {
    method each (line 221) | each(callback: (obj: any, cursor: { key: IndexableType, primaryKey: In...
    method toArray (line 230) | toArray(thenShortcut?: any) {
    method toCollection (line 239) | toCollection() {
    method orderBy (line 248) | orderBy(index: string | string[]) {
    method reverse (line 260) | reverse(): Collection {
    method mapToClass (line 269) | mapToClass(constructor: Function) {
    method defineClass (line 308) | defineClass() {
    method add (line 320) | add(obj, key?: IndexableType): PromiseExtended<IndexableType> {
    method upsert (line 345) | upsert(key: IndexableType, modifications: { [keyPath: string]: any; })...
    method update (line 369) | update(keyOrObject, modifications: { [keyPath: string]: any; } | ((obj...
    method put (line 404) | put(obj, key?: IndexableType): PromiseExtended<IndexableType> {
    method delete (line 430) | delete(key: IndexableType): PromiseExtended<void> {
    method clear (line 443) | clear() {
    method bulkGet (line 456) | bulkGet(keys: IndexableType[]) {
    method bulkAdd (line 470) | bulkAdd(
    method bulkPut (line 507) | bulkPut(
    method bulkUpdate (line 544) | bulkUpdate(
    method bulkDelete (line 613) | bulkDelete(keys: ReadonlyArray<IndexableType>): PromiseExtended<void> {

FILE: src/classes/transaction/transaction-constructor.ts
  type TransactionConstructor (line 8) | interface TransactionConstructor<T extends Transaction=Transaction> {
  function createTransactionConstructor (line 24) | function createTransactionConstructor(db: Dexie) {

FILE: src/classes/transaction/transaction.ts
  class Transaction (line 20) | class Transaction implements ITransaction {
    method _lock (line 50) | _lock() {
    method _unlock (line 62) | _unlock() {
    method _locked (line 78) | _locked() {
    method create (line 97) | create(idbtrans?: IDBTransaction & {[prop: string]: any}) {
    method _promise (line 148) | _promise(
    method _root (line 192) | _root() {
    method waitFor (line 202) | waitFor(promiseLike: PromiseLike<any>) {
    method abort (line 241) | abort() {
    method table (line 253) | table(tableName: string) {

FILE: src/classes/version/schema-helpers.ts
  function setApiOnPlace (line 17) | function setApiOnPlace(db: Dexie, objs: Object[], tableNames: string[], ...
  function removeTablesApi (line 44) | function removeTablesApi(db: Dexie, objs: Object[]) {
  function lowerVersionFirst (line 52) | function lowerVersionFirst(a: Version, b: Version) {
  function runUpgraders (line 56) | function runUpgraders(db: Dexie, oldVersion: number, idbUpgradeTrans: ID...
  type UpgradeQueueItem (line 86) | type UpgradeQueueItem = (idbtrans: IDBTransaction) => PromiseLike<any> |...
  function patchCurrentVersion (line 88) | function patchCurrentVersion(db: Dexie, idbUpgradeTrans: IDBTransaction) {
  function getExistingVersion (line 113) | function getExistingVersion(db: Dexie, trans: Transaction, oldVersion: n...
  function updateTablesAndIndexes (line 128) | function updateTablesAndIndexes(
  type SchemaDiff (line 269) | interface SchemaDiff {
  type TableSchemaDiff (line 275) | interface TableSchemaDiff {
  function getSchemaDiff (line 283) | function getSchemaDiff(oldSchema: DbSchema, newSchema: DbSchema): Schema...
  function createTable (line 344) | function createTable(
  function createMissingTables (line 360) | function createMissingTables(newSchema: DbSchema, idbtrans: IDBTransacti...
  function deleteRemovedTables (line 369) | function deleteRemovedTables(newSchema: DbSchema, idbtrans: IDBTransacti...
  function addIndex (line 374) | function addIndex(store: IDBObjectStore, idx: IndexSpec) {
  function buildGlobalSchema (line 378) | function buildGlobalSchema(
  function readGlobalSchema (line 417) | function readGlobalSchema(db: Dexie, idbdb: IDBDatabase, tmpTrans: IDBTr...
  function verifyInstalledSchema (line 424) | function verifyInstalledSchema(db: Dexie, tmpTrans: IDBTransaction): boo...
  function adjustToExistingIndexNames (line 430) | function adjustToExistingIndexNames(db: Dexie, schema: DbSchema, idbtran...
  function parseIndexSyntax (line 464) | function parseIndexSyntax(primKeyAndIndexes: string): IndexSpec[] {

FILE: src/classes/version/version-constructor.ts
  type VersionConstructor (line 5) | interface VersionConstructor {
  function createVersionConstructor (line 16) | function createVersionConstructor(db: Dexie) {

FILE: src/classes/version/version.ts
  class Version (line 17) | class Version implements IVersion {
    method _createTableSchema (line 27) | _createTableSchema(
    method _parseIndexSyntax (line 35) | _parseIndexSyntax(primKeyAndIndexes: string): IndexSpec[] {
    method _parseStoresSpec (line 39) | _parseStoresSpec(
    method stores (line 78) | stores(stores: { [key: string]: string | null }): this {
    method upgrade (line 108) | upgrade(

FILE: src/classes/where-clause/where-clause-constructor.ts
  type WhereClauseConstructor (line 9) | interface WhereClauseConstructor {
  function createWhereClauseConstructor (line 20) | function createWhereClauseConstructor(db: Dexie) {

FILE: src/classes/where-clause/where-clause-helpers.ts
  function fail (line 8) | function fail(collectionOrWhereClause: Collection | WhereClause, err, T?) {
  function emptyCollection (line 17) | function emptyCollection(whereClause: WhereClause) {
  function upperFactory (line 21) | function upperFactory(dir: 'next' | 'prev') {
  function lowerFactory (line 27) | function lowerFactory(dir: 'next' | 'prev') {
  function nextCasing (line 33) | function nextCasing(key, lowerKey, upperNeedle, lowerNeedle, cmp, dir) {
  function addIgnoreCaseAlgorithm (line 51) | function addIgnoreCaseAlgorithm(whereClause: WhereClause, match, needles...
  function createRange (line 116) | function createRange (lower: IndexableType, upper: IndexableType, lowerO...
  function rangeEqual (line 126) | function rangeEqual (value: IndexableType) : DBCoreKeyRange {

FILE: src/classes/where-clause/where-clause.ts
  class WhereClause (line 16) | class WhereClause implements IWhereClause {
    method Collection (line 30) | get Collection() {
    method between (line 39) | between(lower: IndexableType, upper: IndexableType, includeLower?: boo...
    method equals (line 57) | equals(value: IndexableType) {
    method above (line 67) | above(value: IndexableType) {
    method aboveOrEqual (line 77) | aboveOrEqual(value: IndexableType) {
    method below (line 87) | below(value: IndexableType) {
    method belowOrEqual (line 97) | belowOrEqual(value: IndexableType) {
    method startsWith (line 107) | startsWith(str: string) {
    method startsWithIgnoreCase (line 117) | startsWithIgnoreCase(str: string) {
    method equalsIgnoreCase (line 127) | equalsIgnoreCase(str: string) {
    method anyOfIgnoreCase (line 138) | anyOfIgnoreCase() {
    method startsWithAnyOfIgnoreCase (line 151) | startsWithAnyOfIgnoreCase() {
    method anyOf (line 164) | anyOf() {
    method notEqual (line 207) | notEqual(value: IndexableType) {
    method noneOf (line 218) | noneOf() {
    method inAnyRange (line 237) | inAnyRange(
    method startsWithAnyOf (line 354) | startsWithAnyOf() {

FILE: src/dbcore/cache-existing-values-middleware.ts
  function getFromTransactionCache (line 7) | function getFromTransactionCache(

FILE: src/dbcore/dbcore-indexeddb.ts
  function arrayify (line 21) | function arrayify<T>(arrayLike: {length: number, [index: number]: T}): T...
  function pick (line 24) | function pick<T,Prop extends keyof T>(obj: T, props: Prop[]): Pick<T, Pr...
  function getKeyPathAlias (line 32) | function getKeyPathAlias(keyPath: null | string | string[]) {
  function createDBCore (line 40) | function createDBCore (

FILE: src/dbcore/get-effective-keys.ts
  function getEffectiveKeys (line 9) | function getEffectiveKeys (

FILE: src/dbcore/get-key-extractor.ts
  function getKeyExtractor (line 3) | function getKeyExtractor (keyPath: null | string | string[]) : (a: any) ...
  function getSinglePathKeyExtractor (line 13) | function getSinglePathKeyExtractor(keyPath: string) {

FILE: src/dbcore/proxy-cursor.ts
  type ProxyCursorHooks (line 3) | interface ProxyCursorHooks {
  function ProxyCursor (line 12) | function ProxyCursor (

FILE: src/dbcore/virtual-index-middleware.ts
  type VirtualIndex (line 17) | interface VirtualIndex extends DBCoreIndex {
  function pad (line 37) | function pad (a: any | any[], value: any, count: number) {
  function createVirtualIndexMiddleware (line 44) | function createVirtualIndexMiddleware (down: DBCore) : DBCore {

FILE: src/errors/errors.js
  function DexieError (line 52) | function DexieError (name, msg) {
  function getMultiErrorMessage (line 66) | function getMultiErrorMessage (msg, failures) {
  function ModifyError (line 77) | function ModifyError (msg, failures, successCount, failedKeys) {
  function BulkError (line 85) | function BulkError (msg, failures) {
  function DexieError (line 114) | function DexieError (msgOrInner, inner){
  function mapError (line 142) | function mapError (domError, message) {

FILE: src/functions/apply-update-spec.ts
  function applyUpdateSpec (line 4) | function applyUpdateSpec(

FILE: src/functions/bulk-delete.ts
  function bulkDelete (line 7) | function bulkDelete(

FILE: src/functions/chaining-functions.js
  function nop (line 3) | function nop() { }
  function mirror (line 4) | function mirror(val) { return val; }
  function pureFunctionChain (line 5) | function pureFunctionChain(f1, f2) {
  function callBoth (line 14) | function callBoth(on1, on2) {
  function hookCreatingChain (line 21) | function hookCreatingChain(f1, f2) {
  function hookDeletingChain (line 39) | function hookDeletingChain(f1, f2) {
  function hookUpdatingChain (line 52) | function hookUpdatingChain(f1, f2) {
  function reverseStoppableEventChain (line 70) | function reverseStoppableEventChain(f1, f2) {
  function nonStoppableEventChain (line 78) | function nonStoppableEventChain(f1, f2) {
  function promisableChain (line 86) | function promisableChain(f1, f2) {

FILE: src/functions/cmp.ts
  function cmp (line 6) | function cmp(a: any, b: any): number {
  function compareArrays (line 36) | function compareArrays(a: any[], b: any[]): number {
  function compareUint8Arrays (line 47) | function compareUint8Arrays(
  function type (line 61) | function type(x: any) {
  type BinaryType (line 69) | type BinaryType =
  function getUint8Array (line 85) | function getUint8Array(a: BinaryType): Uint8Array {

FILE: src/functions/combine.ts
  function combine (line 1) | function combine(filter1, filter2) {

FILE: src/functions/compare-functions.ts
  function simpleCompare (line 3) | function simpleCompare(a, b) {
  function simpleCompareReverse (line 7) | function simpleCompareReverse(a, b) {

FILE: src/functions/event-wrappers.ts
  function eventRejectHandler (line 3) | function eventRejectHandler(reject) {
  function eventSuccessHandler (line 11) | function eventSuccessHandler (resolve) {
  function hookedEventRejectHandler (line 17) | function hookedEventRejectHandler (reject) {
  function hookedEventSuccessHandler (line 32) | function hookedEventSuccessHandler(resolve) {
  function preventDefault (line 53) | function preventDefault(event) {
  function BulkErrorHandlerCatchAll (line 60) | function BulkErrorHandlerCatchAll(errorList, done?, supportHooks?) {

FILE: src/functions/get-object-diff.ts
  function getObjectDiff (line 3) | function getObjectDiff(a: any, b: any, rv?: any, prfx?: string) {

FILE: src/functions/is-promise-like.ts
  function isPromiseLike (line 1) | function isPromiseLike(p): p is PromiseLike<any> {

FILE: src/functions/make-class-constructor.ts
  function makeClassConstructor (line 4) | function makeClassConstructor<TConstructor> (prototype: Object, construc...

FILE: src/functions/propmods/add.ts
  function add (line 3) | function add(value: number | bigint | Array<string | number>) {

FILE: src/functions/propmods/remove.ts
  function remove (line 3) | function remove(value: number | bigint | Array<string | number>) {

FILE: src/functions/propmods/replace-prefix.ts
  function replacePrefix (line 3) | function replacePrefix(a: string, b:string) {

FILE: src/functions/quirks.ts
  function safariMultiStoreFix (line 3) | function safariMultiStoreFix(storeNames: string[]) {
  function getNativeGetDatabaseNamesFn (line 7) | function getNativeGetDatabaseNamesFn(indexedDB) {

FILE: src/functions/stringify-key.js
  function stringifyKey (line 7) | function stringifyKey (key) { // key is IndexableType but declaring type...
  function unstringifyKey (line 35) | function unstringifyKey(str) {

FILE: src/functions/temp-transaction.ts
  function tempTransaction (line 10) | function tempTransaction (

FILE: src/functions/utils.ts
  function extend (line 12) | function extend<T extends object,X extends object>(obj: T, extension: X)...
  function hasOwn (line 22) | function hasOwn(obj, prop) {
  function props (line 26) | function props (proto, extension) {
  function setProp (line 35) | function setProp(obj, prop, functionOrGetSet, options?) {
  function derive (line 41) | function derive(Child) {
  function getPropertyDescriptor (line 55) | function getPropertyDescriptor(obj, prop) {
  function slice (line 62) | function slice(args, start?, end?) {
  function override (line 66) | function override(origFunc, overridedFactory) {
  function assert (line 70) | function assert (b) {
  function asap (line 74) | function asap(fn) {
  function getUniqueArray (line 79) | function getUniqueArray(a) {
  function arrayToObject (line 88) | function arrayToObject<T,R> (array: T[], extractor: (x:T, idx: number)=>...
  function trycatcher (line 96) | function trycatcher(fn, reject) {
  function tryCatch (line 106) | function tryCatch(fn: (...args: any[])=>void, onerror, args?) : void {
  function getByKeyPath (line 114) | function getByKeyPath(obj, keyPath) {
  function setByKeyPath (line 134) | function setByKeyPath(obj, keyPath, value) {
  function delByKeyPath (line 166) | function delByKeyPath(obj, keyPath) {
  function shallowClone (line 175) | function shallowClone(obj) {
  function flatten (line 184) | function flatten<T> (a: (T | T[])[]) : T[] {
  function cloneSimpleObjectTree (line 210) | function cloneSimpleObjectTree<T extends object>(o: T): T {
  function objectIsEmpty (line 219) | function objectIsEmpty(o: object) {
  function deepClone (line 232) | function deepClone<T>(any: T): T {
  function innerDeepClone (line 239) | function innerDeepClone<T>(x: T): T {
  function toStringTag (line 270) | function toStringTag(o: Object) {
  function delArrayItem (line 286) | function delArrayItem(a: any[], x: any) {
  constant NO_CHAR_ARRAY (line 292) | const NO_CHAR_ARRAY = {};
  function getArrayOf (line 301) | function getArrayOf (arrayLike) {

FILE: src/functions/workaround-undefined-primkey.ts
  function workaroundForUndefinedPrimKey (line 6) | function workaroundForUndefinedPrimKey(keyPath: string | ArrayLike<strin...

FILE: src/globals/connections.ts
  function createConnectionsManager (line 5) | function createConnectionsManager() {

FILE: src/globals/constants.ts
  constant DEXIE_VERSION (line 1) | const DEXIE_VERSION = '{version}';
  constant INVALID_KEY_ARGUMENT (line 4) | const INVALID_KEY_ARGUMENT =
  constant STRING_EXPECTED (line 6) | const STRING_EXPECTED = "String expected.";
  constant DEFAULT_MAX_CONNECTIONS (line 7) | const DEFAULT_MAX_CONNECTIONS = 1000;
  constant DBNAMES_DB (line 9) | const DBNAMES_DB = '__dbnames';
  constant READONLY (line 10) | const READONLY = 'readonly';
  constant READWRITE (line 11) | const READWRITE = 'readwrite';

FILE: src/globals/global-events.ts
  constant DEXIE_STORAGE_MUTATED_EVENT_NAME (line 4) | const DEXIE_STORAGE_MUTATED_EVENT_NAME = 'storagemutated' as 'storagemut...
  constant STORAGE_MUTATED_DOM_EVENT_NAME (line 17) | const STORAGE_MUTATED_DOM_EVENT_NAME = 'x-storagemutated-1';

FILE: src/helpers/Events.js
  function Events (line 5) | function Events(ctx) {

FILE: src/helpers/database-enumerator.ts
  type IDBKeyNamesVar (line 7) | type IDBKeyNamesVar = typeof IDBKeyRange;
  function getDbNamesTable (line 9) | function getDbNamesTable(indexedDB: IDBFactory, IDBKeyRange: IDBKeyNames...
  function hasDatabasesNative (line 22) | function hasDatabasesNative(indexedDB: IDBFactory) {
  function getDatabaseNames (line 26) | function getDatabaseNames({
  function _onDatabaseCreated (line 41) | function _onDatabaseCreated(
  function _onDatabaseDeleted (line 50) | function _onDatabaseDeleted(

FILE: src/helpers/debug.ts
  function setDebug (line 7) | function setDebug(value, filter) {
  function deprecated (line 11) | function deprecated<T> (what: string, fn: (...args)=>T) {

FILE: src/helpers/index-spec.ts
  function createIndexSpec (line 3) | function createIndexSpec(
  function nameFromKeyPath (line 25) | function nameFromKeyPath (keyPath?: string | string[]): string {

FILE: src/helpers/promise.d.ts
  type DexiePromise (line 4) | interface DexiePromise<T=any> extends PromiseExtended<T> {
  type DexiePromiseConstructor (line 15) | interface DexiePromiseConstructor extends PromiseExtendedConstructor {

FILE: src/helpers/promise.js
  constant ZONE_ECHO_LIMIT (line 38) | const
  function schedulePhysicalTick (line 66) | function schedulePhysicalTick() {
  function DexiePromise (line 106) | function DexiePromise(fn) {
  function then (line 142) | function then (onFulfilled, onRejected) {
  function Listener (line 223) | function Listener(onFulfilled, onRejected, resolve, reject, zone) {
  function executePromiseTask (line 344) | function executePromiseTask (promise, fn) {
  function handleRejection (line 370) | function handleRejection (promise, reason) {
  function propagateAllListeners (line 383) | function propagateAllListeners (promise) {
  function propagateToListener (line 405) | function propagateToListener(promise, listener) {
  function callListener (line 421) | function callListener (cb, promise, listener) {
  function physicalTick (line 445) | function physicalTick() {
  function beginMicroTickScope (line 453) | function beginMicroTickScope() {
  function endMicroTickScope (line 468) | function endMicroTickScope() {
  function finalizePhysicalTick (line 485) | function finalizePhysicalTick() {
  function run_at_end_of_this_or_next_physical_tick (line 496) | function run_at_end_of_this_or_next_physical_tick (fn) {
  function addPossiblyUnhandledError (line 508) | function addPossiblyUnhandledError(promise) {
  function markErrorAsHandled (line 516) | function markErrorAsHandled(promise) {
  function PromiseReject (line 529) | function PromiseReject (reason) {
  function wrap (line 533) | function wrap (fn, errorCatcher) {
  function newScope (line 563) | function newScope (fn, props, a1, a2) {
  function incrementExpectedAwaits (line 599) | function incrementExpectedAwaits() {
  function decrementExpectedAwaits (line 609) | function decrementExpectedAwaits() {
  function onPossibleParallellAsync (line 623) | function onPossibleParallellAsync (possiblePromise) {
  function zoneEnterEcho (line 637) | function zoneEnterEcho(targetZone) {
  function zoneLeaveEcho (line 649) | function zoneLeaveEcho() {
  function switchToZone (line 655) | function switchToZone (targetZone, bEnteringZone) {
  function snapShot (line 693) | function snapShot () {
  function usePSD (line 707) | function usePSD (psd, fn, a1, a2, a3) {
  function nativeAwaitCompatibleWrap (line 717) | function nativeAwaitCompatibleWrap(fn, zone, possibleAwait, cleanup) {
  function execInGlobalContext (line 732) | function execInGlobalContext(cb) {

FILE: src/helpers/prop-modification.ts
  class PropModification (line 26) | class PropModification {
    method execute (line 28) | execute(value: any): any {
    method constructor (line 76) | constructor(spec: PropModSpec) {

FILE: src/helpers/rangeset.ts
  function isEmptyRange (line 18) | function isEmptyRange(node: IntervalTree | {from: IndexableType, to: Ind...
  type RangeSet (line 22) | type RangeSet = RangeSetPrototype & IntervalTree;
  method add (line 39) | add(rangeSet: IntervalTree | {from: IndexableType, to: IndexableType}) {
  method addKey (line 43) | addKey(key: IndexableType) {
  method addKeys (line 47) | addKeys(keys: IndexableType[]) {
  method hasKey (line 51) | hasKey(key: IndexableType) {
  method [iteratorSymbol] (line 56) | [iteratorSymbol](): Iterator<IntervalTreeNode, undefined, IndexableType ...
  function addRange (line 61) | function addRange(target: IntervalTree, from: IndexableType, to: Indexab...
  function mergeRanges (line 114) | function mergeRanges(target: IntervalTree, newSet: IntervalTree | {from:...
  function rangesOverlap (line 127) | function rangesOverlap(
  type RangeSetIteratorState (line 151) | type RangeSetIteratorState =
  function getRangeSetIterator (line 159) | function getRangeSetIterator(
  function rebalance (line 202) | function rebalance(target: IntervalTreeNode) {
  function computeDepth (line 243) | function computeDepth({ r, l }: Pick<IntervalTreeNode, "l" | "r">) {

FILE: src/helpers/table-schema.ts
  function createTableSchema (line 5) | function createTableSchema(

FILE: src/helpers/vipify.ts
  function vipify (line 5) | function vipify<T extends Table | Transaction>(

FILE: src/helpers/yield-support.ts
  function awaitIterator (line 3) | function awaitIterator (iterator: Iterator<any>) {

FILE: src/hooks/hooks-middleware.ts
  method table (line 27) | table(tableName: string) {
  function getExistingValues (line 154) | function getExistingValues(

FILE: src/live-query/cache/adjust-optimistic-request-from-failures.ts
  function adjustOptimisticFromFailures (line 8) | function adjustOptimisticFromFailures(

FILE: src/live-query/cache/apply-optimistic-ops.ts
  function applyOptimisticOps (line 12) | function applyOptimisticOps(

FILE: src/live-query/cache/are-ranges-equal.ts
  function areRangesEqual (line 4) | function areRangesEqual(r1: DBCoreKeyRange, r2: DBCoreKeyRange) {

FILE: src/live-query/cache/cache-middleware.ts
  method table (line 142) | table(tableName: string) {

FILE: src/live-query/cache/does-ranges-overlap.ts
  function doesRangesOverlap (line 5) | function doesRangesOverlap(r1: DBCoreKeyRange, r2: DBCoreKeyRange) {

FILE: src/live-query/cache/find-compatible-query.ts
  function findCompatibleQuery (line 22) | function findCompatibleQuery(

FILE: src/live-query/cache/is-cachable-context.ts
  function isCachableContext (line 4) | function isCachableContext(ctx: LiveQueryContext, table: DBCoreTable) {

FILE: src/live-query/cache/is-cachable-request.ts
  function isCachableRequest (line 4) | function isCachableRequest(type: string, req: Partial<DBCoreQueryRequest...

FILE: src/live-query/cache/is-super-range.ts
  function compareLowers (line 4) | function compareLowers(lower1: any, lower2: any, lowerOpen1: boolean, lo...
  function compareUppers (line 16) | function compareUppers(upper1: any, upper2: any, upperOpen1: boolean, up...
  function isSuperRange (line 28) | function isSuperRange(r1: DBCoreKeyRange, r2: DBCoreKeyRange) {

FILE: src/live-query/cache/is-within-range.ts
  function isAboveLower (line 5) | function isAboveLower(key: IndexableType, range: DBCoreKeyRange) {
  function isBelowUpper (line 13) | function isBelowUpper(key: IndexableType, range: DBCoreKeyRange) {
  function isWithinRange (line 21) | function isWithinRange(key: IndexableType, range: DBCoreKeyRange) {

FILE: src/live-query/cache/signalSubscribers.ts
  function signalSubscribersLazily (line 10) | function signalSubscribersLazily(part: ObservabilitySet, optimistic = fa...
  function signalSubscribersNow (line 23) | function signalSubscribersNow(
  function collectTableSubscribers (line 58) | function collectTableSubscribers(

FILE: src/live-query/cache/subscribe-cachentry.ts
  function subscribeToCacheEntry (line 4) | function subscribeToCacheEntry(cacheEntry: CacheEntry, container: CacheE...
  function enqueForDeletion (line 15) | function enqueForDeletion(cacheEntry: CacheEntry, container: CacheEntry[...

FILE: src/live-query/extend-observability-set.ts
  function extendObservabilitySet (line 5) | function extendObservabilitySet(

FILE: src/live-query/live-query.ts
  type LiveQueryContext (line 29) | interface LiveQueryContext {
  function liveQuery (line 37) | function liveQuery<T>(querier: () => T | Promise<T>): IObservable<T> {

FILE: src/live-query/obs-sets-overlap.ts
  function obsSetsOverlap (line 4) | function obsSetsOverlap(os1: ObservabilitySet, os2: ObservabilitySet) {

FILE: src/live-query/observability-middleware.ts
  method get (line 287) | get() {
  method get (line 293) | get() {
  method get (line 300) | get() {
  function trackAffectedIndexes (line 322) | function trackAffectedIndexes(

FILE: src/live-query/propagate-locally.ts
  function propagateLocally (line 33) | function propagateLocally(updateParts: ObservabilitySet) {

FILE: src/public/index.d.ts
  type _Table (line 37) | interface _Table<T, TKey, TInsertType> extends Table<T, TKey, TInsertTyp...
  type _Collection (line 38) | interface _Collection<T,TKey> extends Collection<T,TKey> {}
  type Promise (line 44) | type Promise<T=any> = PromiseExtended<T> // Because many samples have be...
  type Table (line 46) | interface Table<T=any,Key=any,TInsertType=T> extends _Table<T,Key,TInser...
  type Collection (line 48) | interface Collection<T=any,Key=any> extends _Collection<T, Key> {}

FILE: src/public/types/_insert-type.d.ts
  type NonInsertProps (line 5) | type NonInsertProps<T> = {
  type InsertType (line 19) | type InsertType<T, OptionalProps extends keyof T> = Omit<T, OptionalProp...

FILE: src/public/types/cache.d.ts
  type GlobalQueryCache (line 13) | type GlobalQueryCache = {
  type TblQueryCache (line 19) | interface TblQueryCache {
  type CacheEntryCommon (line 29) | interface CacheEntryCommon {
  type CacheEntry (line 37) | type CacheEntry = CacheEntryCommon &

FILE: src/public/types/collection.d.ts
  type Collection (line 9) | interface Collection<T=any, TKey=IndexableType, TInsertType=T> {

FILE: src/public/types/db-events.d.ts
  type DexieOnReadyEvent (line 6) | interface DexieOnReadyEvent {
  type DexieVersionChangeEvent (line 12) | interface DexieVersionChangeEvent {
  type DexiePopulateEvent (line 18) | interface DexiePopulateEvent {
  type DexieCloseEvent (line 24) | interface DexieCloseEvent {
  type DbEventFns (line 30) | interface DbEventFns {
  type DbEvents (line 36) | interface DbEvents extends DbEventFns, DexieEventSet {
  type ObservabilitySet (line 47) | type ObservabilitySet = {
  type DexieOnStorageMutatedEvent (line 76) | interface DexieOnStorageMutatedEvent {
  type GlobalDexieEvents (line 82) | interface GlobalDexieEvents extends DexieEventSet {

FILE: src/public/types/db-schema.d.ts
  type DbSchema (line 3) | type DbSchema = {[tableName: string]: TableSchema};

FILE: src/public/types/dbcore.d.ts
  type DBCoreRangeType (line 6) | const enum DBCoreRangeType {
  type DBCoreKeyRange (line 13) | interface DBCoreKeyRange {
  type DBCoreTransaction (line 22) | interface DBCoreTransaction {
  type DbCoreTransactionOptions (line 26) | interface DbCoreTransactionOptions {
  type DBCoreMutateRequest (line 30) | type DBCoreMutateRequest = DBCoreAddRequest | DBCorePutRequest | DBCoreD...
  type DBCoreMutateResponse (line 32) | interface DBCoreMutateResponse {
  type DBCoreAddRequest (line 39) | interface DBCoreAddRequest {
  type DBCorePutRequest (line 49) | interface DBCorePutRequest {
  type DBCoreDeleteRequest (line 70) | interface DBCoreDeleteRequest {
  type DBCoreDeleteRangeRequest (line 82) | interface DBCoreDeleteRangeRequest {
  type DBCoreGetManyRequest (line 89) | interface DBCoreGetManyRequest {
  type DBCoreGetRequest (line 96) | interface DBCoreGetRequest {
  type DBCoreQuery (line 102) | interface DBCoreQuery {
  type DBCoreQueryRequest (line 107) | interface DBCoreQueryRequest {
  type DBCoreQueryResponse (line 117) | interface DBCoreQueryResponse {
  type DBCoreOpenCursorRequest (line 121) | interface DBCoreOpenCursorRequest {
  type DBCoreCountRequest (line 130) | interface DBCoreCountRequest {
  type DBCoreCursor (line 136) | interface DBCoreCursor {
  type DBCoreSchema (line 151) | interface DBCoreSchema {
  type DBCoreTableSchema (line 155) | interface DBCoreTableSchema {
  type DBCoreIndex (line 162) | interface DBCoreIndex {
  type DBCore (line 184) | interface DBCore {
  type DBCoreTable (line 196) | interface DBCoreTable {
  type Key (line 209) | type Key = any;
  type RangeType (line 210) | type RangeType = DBCoreRangeType;
  type KeyRange (line 211) | type KeyRange = DBCoreKeyRange;
  type MutateRequest (line 212) | type MutateRequest = DBCoreMutateRequest;
  type AddRequest (line 213) | type AddRequest = DBCoreAddRequest;
  type PutRequest (line 214) | type PutRequest = DBCorePutRequest;
  type DeleteRequest (line 215) | type DeleteRequest = DBCoreDeleteRequest;
  type DeleteRangeRequest (line 216) | type DeleteRangeRequest = DBCoreDeleteRangeRequest;
  type MutateResponse (line 217) | type MutateResponse = DBCoreMutateResponse;
  type DBCoreTransactionMode (line 218) | type DBCoreTransactionMode = 'readonly' | 'readwrite';

FILE: src/public/types/dbquerycore.d.ts
  type DBQueryCore (line 17) | interface DBQueryCore {
  type DBQueryCoreTable (line 33) | interface DBQueryCoreTable {
  type DBQueryCoreMutateRequest (line 45) | type DBQueryCoreMutateRequest = DBCoreMutateRequest | DBQueryCoreUpdateR...
  type DBQueryCoreUpdateRequest (line 47) | interface DBQueryCoreUpdateRequest {

FILE: src/public/types/dexie-constructor.d.ts
  type ChromeTransactionDurability (line 14) | type ChromeTransactionDurability = 'default' | 'strict' | 'relaxed'
  type DexieOptions (line 16) | interface DexieOptions {
  type DexieConstructor (line 28) | interface DexieConstructor extends DexieExceptionClasses {

FILE: src/public/types/dexie-dom-dependencies.d.ts
  type DexieDOMDependencies (line 1) | interface DexieDOMDependencies {

FILE: src/public/types/dexie-event-set.d.ts
  type DexieEventSet (line 3) | interface DexieEventSet {

FILE: src/public/types/dexie-event.d.ts
  type DexieEvent (line 1) | interface DexieEvent {

FILE: src/public/types/dexie.d.ts
  type TableProp (line 15) | type TableProp<DX> = {
  type TXWithTables (line 19) | type TXWithTables<DX extends Dexie> = Dexie extends DX
  type Dexie (line 24) | interface Dexie {

FILE: src/public/types/entity-table.d.ts
  type IDType (line 10) | type IDType<T, TKeyPropNameOrKeyType> = IsStrictlyAny<T> extends true
  type EntityTable (line 18) | type EntityTable<T, TKeyPropName extends keyof T = never, TInsertType = ...

FILE: src/public/types/entity.d.ts
  class Entity (line 3) | class Entity<TDexieSubClass extends Dexie=Dexie> {

FILE: src/public/types/errors.d.ts
  type DexieError (line 11) | interface DexieError extends Error {
  type DexieErrors (line 42) | type DexieErrors = {
  type ModifyError (line 129) | interface ModifyError extends DexieError {
  type BulkError (line 139) | interface BulkError extends DexieError {
  type DexieErrorConstructor (line 144) | interface DexieErrorConstructor {
  type ModifyErrorConstructor (line 150) | interface ModifyErrorConstructor {
  type BulkErrorConstructor (line 159) | interface BulkErrorConstructor {
  type ExceptionAliasSet (line 164) | type ExceptionAliasSet = {[ShortName in keyof DexieErrors]: DexieErrorCo...
  type ExceptionSet (line 170) | type ExceptionSet = {[P in DexieErrors[keyof DexieErrors]]: DexieErrorCo...
  type DexieExceptionClasses (line 172) | type DexieExceptionClasses = ExceptionSet & {

FILE: src/public/types/global.d.ts
  type ChromeTransactionDurability (line 5) | type ChromeTransactionDurability = 'default' | 'strict' | 'relaxed'
  type IDBTransactionOptions (line 7) | interface IDBTransactionOptions {
  type IDBDatabase (line 11) | interface IDBDatabase {
  type IDBGetAllOptions (line 22) | interface IDBGetAllOptions {
  type IDBRecord (line 28) | interface IDBRecord<T = any> {
  type IDBObjectStore (line 34) | interface IDBObjectStore {
  type IDBIndex (line 42) | interface IDBIndex {

FILE: src/public/types/index-spec.d.ts
  type IndexSpec (line 1) | interface IndexSpec {

FILE: src/public/types/indexable-type.d.ts
  type IndexableTypePart (line 1) | type IndexableTypePart =
  type IndexableTypeArray (line 4) | type IndexableTypeArray = Array<IndexableTypePart>;
  type IndexableTypeArrayReadonly (line 5) | type IndexableTypeArrayReadonly = ReadonlyArray<IndexableTypePart>;
  type IndexableType (line 6) | type IndexableType = IndexableTypePart | IndexableTypeArrayReadonly;

FILE: src/public/types/insert-type.d.ts
  type NonInsertProps (line 5) | type NonInsertProps<T> = {
  type InsertType (line 19) | type InsertType<T, OptionalProps extends keyof T> = Omit<T, OptionalProp...

FILE: src/public/types/is-strictly-any.d.ts
  type IsStrictlyAny (line 1) | type IsStrictlyAny<T> = (T extends never ? true : false) extends false ?...

FILE: src/public/types/keypaths.d.ts
  type KeyPathIgnoreObject (line 1) | type KeyPathIgnoreObject =
  type KeyPaths (line 21) | type KeyPaths<T, MAXDEPTH = 'II', CURRDEPTH extends string = ''> = {
  type KeyPathValue (line 41) | type KeyPathValue<T, PATH> = PATH extends `${infer R}.${infer S}`

FILE: src/public/types/middleware.d.ts
  type Middleware (line 3) | interface Middleware<TStack extends {stack: string}> {
  type DexieStacks (line 10) | interface DexieStacks {

FILE: src/public/types/observable.d.ts
  type SymbolConstructor (line 4) | interface SymbolConstructor {
  type Subscribable (line 9) | interface Subscribable<T> {
  type Unsubscribable (line 12) | interface Unsubscribable {
  type Observable (line 15) | interface Observable<T = any> {
  type Subscription (line 24) | interface Subscription {
  type Observer (line 29) | interface Observer<T = any> {

FILE: src/public/types/promise-extended.d.ts
  type PromiseExtendedConstructor (line 1) | interface PromiseExtendedConstructor extends PromiseConstructor {
  type PromiseExtended (line 38) | interface PromiseExtended<T=any> extends Promise<T> {

FILE: src/public/types/prop-modification.d.ts
  type PropModSpec (line 1) | type PropModSpec = {
  class PropModification (line 7) | class PropModification {

FILE: src/public/types/rangeset.d.ts
  type IntervalTree (line 3) | type IntervalTree = IntervalTreeNode | EmptyRange;
  type IntervalTreeNode (line 4) | interface IntervalTreeNode {
  type EmptyRange (line 11) | interface EmptyRange {
  type RangeSetPrototype (line 15) | interface RangeSetPrototype {
  type RangeSet (line 23) | type RangeSet = RangeSetPrototype & IntervalTree;
  type RangeSetConstructor (line 25) | interface RangeSetConstructor {

FILE: src/public/types/table-hooks.d.ts
  type CreatingHookContext (line 6) | interface CreatingHookContext<T,Key> {
  type UpdatingHookContext (line 11) | interface UpdatingHookContext<T,Key> {
  type DeletingHookContext (line 16) | interface DeletingHookContext<T,Key> {
  type TableHooks (line 21) | interface TableHooks<T=any,TKey=IndexableType,TInsertType=T> extends Dex...

FILE: src/public/types/table-schema.d.ts
  type TableSchema (line 3) | interface TableSchema {

FILE: src/public/types/table.d.ts
  type Table (line 13) | interface Table<T=any, TKey=any, TInsertType=T> {

FILE: src/public/types/then-shortcut.d.ts
  type ThenShortcut (line 1) | type ThenShortcut<T,TResult> =  (value: T) => TResult | PromiseLike<TRes...

FILE: src/public/types/transaction-events.d.ts
  type TransactionEvents (line 4) | interface TransactionEvents extends DexieEventSet {

FILE: src/public/types/transaction-mode.d.ts
  type TransactionMode (line 1) | type TransactionMode = 'readonly' | 'readwrite' | 'r' | 'r!' | 'r?' | 'r...

FILE: src/public/types/transaction.d.ts
  type Transaction (line 5) | interface Transaction {

FILE: src/public/types/update-spec.d.ts
  type UpdateSpec (line 4) | type UpdateSpec<T> = { [KP in KeyPaths<Required<T>>]?: KeyPathValue<Requ...

FILE: src/public/types/version.d.ts
  type Version (line 7) | interface Version {
  type ExtendableVersion (line 12) | interface ExtendableVersion extends Version {

FILE: src/public/types/where-clause.d.ts
  type WhereClause (line 5) | interface WhereClause<T=any, TKey=IndexableType, TInsertType=T> {

FILE: test/deepEqual.js
  function deepEqual (line 5) | function deepEqual(actual, expected, description) {
  function isDeepEqual (line 12) | function isDeepEqual(actual, expected, allowedExtra, prevActual) {

FILE: test/dexie-unittest-utils.js
  function stringify (line 26) | function stringify (idbKey) {
  function resetDatabase (line 32) | function resetDatabase(db) {
  function deleteDatabase (line 103) | function deleteDatabase(db) {
  function supports (line 136) | function supports (features) {
  function spawnedTest (line 163) | function spawnedTest (name, num, promiseGenerator) {
  function promisedTest (line 182) | function promisedTest (name, num, asyncFunction) {

FILE: test/is-idb-and-promise-compatible.js
  class IdbPromiseIncompatibleError (line 7) | class IdbPromiseIncompatibleError extends Error {
    method constructor (line 8) | constructor() {
  function isIdbAndPromiseCompatible (line 14) | async function isIdbAndPromiseCompatible() {

FILE: test/karma.common.js
  function getKarmaConfig (line 85) | function getKarmaConfig(browserMatrixOverrides, configOverrides) {

FILE: test/karma.lambdatest.js
  function configureLambdaTest (line 69) | function configureLambdaTest(karmaCommon) {

FILE: test/tests-asyncawait.js
  function promiseFlow (line 260) | function promiseFlow () {

FILE: test/tests-blobs.js
  function readBlob (line 21) | function readBlob (blob) {
  function arraysAreEqual (line 31) | function arraysAreEqual (a1, a2) {
  function updatingHook (line 59) | function updatingHook (modifications, primKey, obj, trans) {

FILE: test/tests-cmp.js
  function fillArrayBuffer (line 4) | function fillArrayBuffer(ab, val) {

FILE: test/tests-collection.js
  function pseudoRandom (line 490) | function pseudoRandom() {
  function randomString (line 495) | function randomString(count) {

FILE: test/tests-crud-hooks.js
  function unsubscribeHooks (line 38) | function unsubscribeHooks() {
  function subscrubeHooks (line 51) | function subscrubeHooks() {
  function nop (line 93) | function nop(){}
  function creating1 (line 95) | function creating1 (primKey, obj, transaction) {
  function creating2 (line 121) | function creating2 (primKey, obj, transaction) {
  function reading1 (line 139) | function reading1 (obj) {
  function reading2 (line 147) | function reading2 (obj) {
  function updating1 (line 155) | function updating1 (modifications, primKey, obj, transaction) {
  function updating2 (line 182) | function updating2 (modifications, primKey, obj, transaction) {
  function deleting1 (line 207) | function deleting1 (primKey, obj, transaction) {
  function deleting2 (line 230) | function deleting2 (primKey, obj, transaction) {

FILE: test/tests-exception-handling.js
  function deletingHook (line 109) | function deletingHook () {
  function deleteKarls (line 115) | function deleteKarls() {
  function deleteKarls (line 141) | function deleteKarls() {
  function CustomError (line 255) | function CustomError() { }
  function CustomError (line 275) | function CustomError() { }

FILE: test/tests-extendability.js
  function Root (line 92) | function Root() { }
  function Branch1 (line 93) | function Branch1() { }
  function Branch2 (line 94) | function Branch2() { }

FILE: test/tests-live-query.js
  function objectify (line 34) | function objectify(map) {
  class Signal (line 42) | class Signal {
  function liveQueryUnitTester (line 46) | function liveQueryUnitTester(lq, {graceTime}={graceTime: 0}) {
  method id (line 461) | get id(){return lastFriendId}
  method id (line 468) | get id(){return lastFriendId}
  method id (line 469) | get id(){return barbarFriendId}
  method id (line 483) | get id(){return lastFriendId}
  method id (line 484) | get id(){return barbarFriendId}
  method id (line 485) | get id() { return f.id; }
  function zeroFlyers (line 660) | function zeroFlyers(abortSignal) {
  function timeout (line 667) | function timeout(ms) {
  function allValuesOk (line 673) | async function allValuesOk(actual, expected, allowedExtra, prevActual, a...

FILE: test/tests-misc.js
  function CustomDate (line 150) | function CustomDate (realDate) {
  function creatingHook (line 158) | function creatingHook (primKey, obj) {
  function updatingHook (line 165) | function updatingHook (modifications, primKey, obj) {
  function isDate (line 172) | function isDate(obj) {
  function readingHook (line 176) | function readingHook (obj) {
  class Foo (line 232) | class Foo {
    method synced (line 233) | get synced() { return false;}
  class Foo (line 298) | class Foo {
    method synced (line 233) | get synced() { return false;}
  function Bar (line 376) | function Bar(text) {

FILE: test/tests-performance.js
  function log (line 20) | function log(txt, noPerf) {
  function randomString (line 64) | function randomString(count) {

FILE: test/tests-promise.js
  function createDirectlyResolvedPromise (line 9) | function createDirectlyResolvedPromise() {
  function check (line 153) | function check() {
  function check (line 199) | function check() {

FILE: test/tests-rangeset.js
  function isSequencial (line 74) | function isSequencial(set) {
  function printTree (line 105) | function printTree(nodes, pad=-1) {
  function verifySet (line 169) | function verifySet(set) {

FILE: test/tests-table.js
  method mutate (line 476) | mutate(req) {
  function deepEqual (line 1243) | function deepEqual(actual, expected, description) {
  function stripObj (line 1247) | function stripObj(obj, props) {
  function sortObj (line 1255) | function sortObj(obj) {
  function deepEqualPartial (line 1259) | function deepEqualPartial(actual, expected, description) {

FILE: test/tests-transaction.js
  function addUser (line 166) | function addUser(user, pets) {
  function smallChild (line 547) | function smallChild() {
  function middleChild (line 566) | function middleChild() {
  function bigParent (line 580) | function bigParent() {
  function CurrentTransChecker (line 719) | function CurrentTransChecker(scope, trans) {
  function onCreating (line 725) | function onCreating(primKey, obj, transaction) {
  function onReading (line 733) | function onReading(obj) {
  function onUpdating (line 738) | function onUpdating(modifications, primKey, obj, transaction) {
  function onDeleting (line 745) | function onDeleting(primKey, obj, transaction) {
  function doTheTests (line 756) | async function doTheTests() {
  function sleep (line 808) | function sleep (ms) {

FILE: test/tests-upgrading.js
  function checkVersion (line 39) | function checkVersion(version) {
  function checkObjectStores (line 46) | function checkObjectStores(expected) {
  function checkTransactionObjectStores (line 64) | function checkTransactionObjectStores(t, expected) {
  function error (line 381) | function error(e) {

FILE: test/tests-whereclause.js
  function runTheTests (line 131) | function runTheTests (mippler) {
  function runTheTests (line 677) | function runTheTests(mippler) {

FILE: test/typings-test/test-extend-dexie.ts
  type Table (line 8) | interface Table<T, TKey> {
  type DbEvents (line 11) | interface DbEvents {
  type DexieConstructor (line 17) | interface DexieConstructor {
  type Dexie (line 21) | interface Dexie {

FILE: test/typings-test/test-misc.ts
  class MyDb (line 3) | class MyDb extends Dexie {
    method constructor (line 5) | constructor() {

FILE: test/typings-test/test-typings.ts
  class SomeClass (line 48) | class SomeClass {
    method method (line 49) | method<T> (promise: Promise<T>) { return promise; }
  type Friend (line 67) | interface Friend {
  class Entity2 (line 76) | class Entity2 {
  class BaseEntity (line 81) | class BaseEntity {
    method foo (line 84) | foo(): void {
  class Entity3 (line 89) | class Entity3 extends BaseEntity {
    method foo2 (line 91) | foo2(): void {
  type CompoundKeyEntity (line 95) | interface CompoundKeyEntity {
  class MyDatabase (line 100) | class MyDatabase extends Dexie {
    method constructor (line 108) | constructor () {
  class NotFoundError (line 218) | class NotFoundError extends Error {
    method constructor (line 219) | constructor() {
    method name (line 222) | get name() {
  type Friend (line 266) | interface Friend {
  type Friend (line 288) | interface Friend {
  type TodoItem (line 307) | interface TodoItem {
  class MyDexie (line 381) | class MyDexie extends Dexie {
    method constructor (line 391) | constructor() {

FILE: test/typings-test/test-updatespec.ts
  type WithArray (line 4) | interface WithArray {
  type Address (line 13) | interface Address {
  type WithNestedObject (line 16) | interface WithNestedObject {
  type WithNestedArray (line 28) | interface WithNestedArray {

FILE: tools/build-configs/rollup.config.js
  constant ERRORS_TO_IGNORE (line 10) | const ERRORS_TO_IGNORE = [
  method onwarn (line 27) | onwarn ({loc, frame, code, message}) {

FILE: tools/build-configs/rollup.config.mjs
  constant ERRORS_TO_IGNORE (line 14) | const ERRORS_TO_IGNORE = [
  method onwarn (line 31) | onwarn ({loc, frame, code, message}) {

FILE: tools/build-configs/rollup.modern.config.js
  constant ERRORS_TO_IGNORE (line 10) | const ERRORS_TO_IGNORE = [
  method onwarn (line 27) | onwarn ({loc, frame, code, message}) {

FILE: tools/build-configs/rollup.modern.config.mjs
  constant ERRORS_TO_IGNORE (line 14) | const ERRORS_TO_IGNORE = [
  method onwarn (line 31) | onwarn ({loc, frame, code, message}) {

FILE: tools/build-configs/rollup.tests.config.js
  constant ERRORS_TO_IGNORE (line 6) | const ERRORS_TO_IGNORE = [
  method onwarn (line 26) | onwarn ({loc, frame, code, message}) {

FILE: tools/build-configs/rollup.tests.config.mjs
  constant ERRORS_TO_IGNORE (line 10) | const ERRORS_TO_IGNORE = [
  method onwarn (line 30) | onwarn ({loc, frame, code, message}) {

FILE: tools/build-configs/rollup.umd.config.js
  constant ERRORS_TO_IGNORE (line 10) | const ERRORS_TO_IGNORE = [
  method onwarn (line 29) | onwarn ({loc, frame, code, message}) {

FILE: tools/build-configs/rollup.umd.config.mjs
  constant ERRORS_TO_IGNORE (line 14) | const ERRORS_TO_IGNORE = [
  method onwarn (line 33) | onwarn ({loc, frame, code, message}) {
Condensed preview — 792 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,536K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 19,
    "preview": "github: dfahlander\n"
  },
  {
    "path": ".github/workflows/dexie-cloud-common.yml",
    "chars": 949,
    "preview": "name: dexie-cloud-common Tests\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n    paths:\n      - 'libs/d"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 1592,
    "preview": "name: Build and Test\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - master # Add also master-4 when dexie@4 is "
  },
  {
    "path": ".gitignore",
    "chars": 2762,
    "preview": "# Ignore node_modules\nnode_modules/\n\n# Ignore all build output\ndist/*.js\ndist/*.map\ndist/*.ts\ndist/*.gz\ndist/*.mjs\ndist/"
  },
  {
    "path": ".npmignore",
    "chars": 136,
    "preview": "**/tmp/\nsamples/\naddons/\nlibs/\n*.njsproj\n.*\n*.log\ntest/\ntools/\nbower.json\nsrc/\n.lambdatest\ntunnel.pid\ntsconfig.json\npnpm"
  },
  {
    "path": ".npmrc",
    "chars": 24,
    "preview": "auto-install-peers=true\n"
  },
  {
    "path": ".prettierrc",
    "chars": 69,
    "preview": "{\n  \"trailingComma\": \"es5\",\n  \"tabWidth\": 2,\n  \"singleQuote\": true\n}\n"
  },
  {
    "path": ".prettierrc.yml",
    "chars": 63,
    "preview": "trailingComma: 'none'\ntabWidth: 2\nsemi: true\nsingleQuote: true\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3211,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2576,
    "preview": "HOW TO CONTRIBUTE\n=================\n\nWe appreciate contributions in forms of:\n\n* issues\n* help answering questions in [i"
  },
  {
    "path": "LICENSE",
    "chars": 11325,
    "preview": "Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licens"
  },
  {
    "path": "NOTICE",
    "chars": 575,
    "preview": "Dexie.js\n\nCopyright (c) 2014-2017 David Fahlander\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou m"
  },
  {
    "path": "README.md",
    "chars": 8862,
    "preview": "# Dexie.js\n\n[![NPM Version][npm-image]][npm-url] ![Build Status](https://github.com/dexie/Dexie.js/actions/workflows/mai"
  },
  {
    "path": "SECURITY.md",
    "chars": 1147,
    "preview": "# Security Policy\n\n## Supported Versions\n\n| Version | Supported          | Branch\n| ------- | ------------------ | -----"
  },
  {
    "path": "addons/Dexie.Observable/.gitignore",
    "chars": 49,
    "preview": "dist/*.js\ndist/*.map\ndist/*.ts\ndist/*.gz\n**/tmp/\n"
  },
  {
    "path": "addons/Dexie.Observable/.npmignore",
    "chars": 39,
    "preview": "tools/\nsrc/\n.*\ntmp/\n**/tmp/\ntest\n*.log\n"
  },
  {
    "path": "addons/Dexie.Observable/README.md",
    "chars": 5434,
    "preview": "# Dexie.Observable.js\n\n*NOTE! Dexie's liveQuery feature is NOT dependent on this old package. This package has been unma"
  },
  {
    "path": "addons/Dexie.Observable/api.d.ts",
    "chars": 1296,
    "preview": "/**\n * API for Dexie.Observable.\n *\n * Contains interfaces used by dexie-observable.\n *\n * By separating module 'dexie-o"
  },
  {
    "path": "addons/Dexie.Observable/api.js",
    "chars": 148,
    "preview": "// This file is deliberatly left empty to allow the api.d.ts to contain the definitions for Dexie.Observable without gen"
  },
  {
    "path": "addons/Dexie.Observable/dist/README.md",
    "chars": 1336,
    "preview": "## Can't find dexie-observable.js?\nTranspiled code (dist version) IS ONLY checked in to\nthe [releases](https://github.co"
  },
  {
    "path": "addons/Dexie.Observable/package.json",
    "chars": 3690,
    "preview": "{\n  \"name\": \"dexie-observable\",\n  \"version\": \"4.0.1-beta.13\",\n  \"description\": \"Addon to Dexie that makes it possible to"
  },
  {
    "path": "addons/Dexie.Observable/src/.eslintrc.json",
    "chars": 709,
    "preview": "{\n  \"extends\": \"eslint:recommended\",\n  \"parserOptions\": {\n    \"ecmaVersion\": 2020,\n    \"sourceType\": \"module\",\n    \"ecma"
  },
  {
    "path": "addons/Dexie.Observable/src/Dexie.Observable.d.ts",
    "chars": 3894,
    "preview": "// Type definitions for dexie-observable v{version}\n// Project: https://github.com/dexie/Dexie.js/tree/master/addons/Dex"
  },
  {
    "path": "addons/Dexie.Observable/src/Dexie.Observable.js",
    "chars": 27735,
    "preview": "/* ========================================================================== \n *                           dexie-observ"
  },
  {
    "path": "addons/Dexie.Observable/src/change_types.js",
    "chars": 91,
    "preview": "// Change Types\nexport const CREATE = 1;\nexport const UPDATE = 2;\nexport const DELETE = 3;\n"
  },
  {
    "path": "addons/Dexie.Observable/src/delete-old-changes.js",
    "chars": 1372,
    "preview": "import Dexie from 'dexie';\n\nexport default function deleteOldChanges(db) {\n  // This is a background job and should neve"
  },
  {
    "path": "addons/Dexie.Observable/src/hooks/creating.js",
    "chars": 1602,
    "preview": "import Dexie from 'dexie';\n\nimport {CREATE} from '../change_types';\n\nexport default function initCreatingHook(db, table)"
  },
  {
    "path": "addons/Dexie.Observable/src/hooks/crud-monitor.js",
    "chars": 696,
    "preview": "import initCreatingHook from './creating';\nimport initUpdatingHook from './updating';\nimport initDeletingHook from './de"
  },
  {
    "path": "addons/Dexie.Observable/src/hooks/deleting.js",
    "chars": 1167,
    "preview": "import {DELETE} from '../change_types';\n\nexport default function initDeletingHook(db, tableName) {\n  return function del"
  },
  {
    "path": "addons/Dexie.Observable/src/hooks/updating.js",
    "chars": 2420,
    "preview": "import Dexie from 'dexie';\n\nimport {UPDATE} from '../change_types';\n\nexport default function initUpdatingHook(db, tableN"
  },
  {
    "path": "addons/Dexie.Observable/src/intercomm.js",
    "chars": 6086,
    "preview": "import Dexie from 'dexie';\n\nconst Promise = Dexie.Promise;\n\nexport default function initIntercomm(db, Observable, SyncNo"
  },
  {
    "path": "addons/Dexie.Observable/src/on-storage.js",
    "chars": 1192,
    "preview": "import Dexie from 'dexie';\n\nexport default function initOnStorage(Observable) {\n  return function onStorage(event) {\n   "
  },
  {
    "path": "addons/Dexie.Observable/src/override-create-transaction.js",
    "chars": 2637,
    "preview": "export default function initOverrideCreateTransaction(db, wakeupObservers) {\n  return function overrideCreateTransaction"
  },
  {
    "path": "addons/Dexie.Observable/src/override-open.js",
    "chars": 644,
    "preview": "export default function initOverrideOpen(db, SyncNode, crudMonitor) {\n  return function overrideOpen(origOpen) {\n    ret"
  },
  {
    "path": "addons/Dexie.Observable/src/override-parse-stores-spec.js",
    "chars": 1259,
    "preview": "export default function overrideParseStoresSpec(origFunc) {\n  return function(stores, dbSchema) {\n    // Create the _cha"
  },
  {
    "path": "addons/Dexie.Observable/src/utils.js",
    "chars": 785,
    "preview": "export function nop() {}\n\nexport function promisableChain(f1, f2) {\n  if (f1 === nop) return f2;\n  return function() {\n "
  },
  {
    "path": "addons/Dexie.Observable/src/wakeup-observers.js",
    "chars": 1369,
    "preview": "import Dexie from 'dexie';\n\nexport default function initWakeupObservers(db, Observable, localStorage) {\n  return functio"
  },
  {
    "path": "addons/Dexie.Observable/test/gh-actions.sh",
    "chars": 184,
    "preview": "#!/bin/bash -e\necho \"Installing dependencies for dexie-observable\"\npnpm install >/dev/null\npnpm run build\npnpm run test:"
  },
  {
    "path": "addons/Dexie.Observable/test/integration/karma-env.js",
    "chars": 244,
    "preview": "// workerImports will be used by tests-open.js in the dexie test suite when\n// launching a Worker. This line will instru"
  },
  {
    "path": "addons/Dexie.Observable/test/integration/karma.conf.js",
    "chars": 1133,
    "preview": "// Include common configuration\nconst {karmaCommon, getKarmaConfig, defaultBrowserMatrix} = require('../../../../test/ka"
  },
  {
    "path": "addons/Dexie.Observable/test/integration/test-observable-dexie-tests.html",
    "chars": 855,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>Dexie Unit tests with Dexie.Observable applied</title>\n"
  },
  {
    "path": "addons/Dexie.Observable/test/typings/test-typings.ts",
    "chars": 2397,
    "preview": "\nimport Dexie from 'dexie';\nimport '../../src/Dexie.Observable';\nimport dexieObservable from '../../src/Dexie.Observable"
  },
  {
    "path": "addons/Dexie.Observable/test/typings/tsconfig.json",
    "chars": 317,
    "preview": "{\n    \"compilerOptions\": {\n        \"module\": \"es6\",\n        \"target\": \"es5\",\n        \"noImplicitAny\": true,\n        \"str"
  },
  {
    "path": "addons/Dexie.Observable/test/unit/.eslintrc.json",
    "chars": 245,
    "preview": "{\n  \"parserOptions\": {\n    \"ecmaVersion\": 6,\n    \"sourceType\": \"module\",\n    \"ecmaFeatures\": {\n    }\n  },\n  \"env\": {\n   "
  },
  {
    "path": "addons/Dexie.Observable/test/unit/.gitignore",
    "chars": 26,
    "preview": "/bundle.js\n/bundle.js.map\n"
  },
  {
    "path": "addons/Dexie.Observable/test/unit/deep-equal.js",
    "chars": 669,
    "preview": "import {equal} from 'QUnit';\n\n// Must use this rather than QUnit's deepEqual() because that one fails on Safari when run"
  },
  {
    "path": "addons/Dexie.Observable/test/unit/hooks/tests-creating.js",
    "chars": 5810,
    "preview": "import Dexie from 'dexie';\nimport {module, asyncTest, start, stop, strictEqual, ok} from 'QUnit';\nimport {deepEqual} fro"
  },
  {
    "path": "addons/Dexie.Observable/test/unit/hooks/tests-deleting.js",
    "chars": 2550,
    "preview": "import Dexie from 'dexie';\nimport {module, asyncTest, start, stop, strictEqual, ok} from 'QUnit';\nimport {deepEqual} fro"
  },
  {
    "path": "addons/Dexie.Observable/test/unit/hooks/tests-updating.js",
    "chars": 3989,
    "preview": "import Dexie from 'dexie';\nimport {module, asyncTest, start, stop, strictEqual, ok} from 'QUnit';\nimport {deepEqual} fro"
  },
  {
    "path": "addons/Dexie.Observable/test/unit/karma.conf.js",
    "chars": 1051,
    "preview": "// Include common configuration\nconst {karmaCommon, getKarmaConfig, defaultBrowserMatrix} = require('../../../../test/ka"
  },
  {
    "path": "addons/Dexie.Observable/test/unit/run-unit-tests.html",
    "chars": 579,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>Dexie.Observable Unit tests</title>\n  <link rel=\"styles"
  },
  {
    "path": "addons/Dexie.Observable/test/unit/tests-observable-misc.js",
    "chars": 9210,
    "preview": "import {module, asyncTest, equal, strictEqual, ok, start} from 'QUnit';\nimport {deepEqual} from './deep-equal';\nimport "
  },
  {
    "path": "addons/Dexie.Observable/test/unit/tests-override-open.js",
    "chars": 1438,
    "preview": "import {module, test, strictEqual, deepEqual, ok} from 'QUnit';\nimport initOverrideOpen from '../../src/override-open';\n"
  },
  {
    "path": "addons/Dexie.Observable/test/unit/tests-override-parse-stores-spec.js",
    "chars": 2081,
    "preview": "import {module, test, strictEqual, deepEqual, ok} from 'QUnit';\nimport overrideParseStoresSpec from '../../src/override-"
  },
  {
    "path": "addons/Dexie.Observable/test/unit/unit-tests-all.js",
    "chars": 225,
    "preview": "import './hooks/tests-creating.js';\nimport './hooks/tests-deleting.js';\nimport './hooks/tests-updating.js';\nimport './te"
  },
  {
    "path": "addons/Dexie.Observable/tools/build-configs/banner.txt",
    "chars": 719,
    "preview": "/* ========================================================================== \n *                           dexie-observ"
  },
  {
    "path": "addons/Dexie.Observable/tools/build-configs/rollup.config.mjs",
    "chars": 936,
    "preview": "import sourcemaps from 'rollup-plugin-sourcemaps';\nimport {readFileSync} from 'fs';\nimport path from 'path';\nimport { fi"
  },
  {
    "path": "addons/Dexie.Observable/tools/build-configs/rollup.tests.config.js",
    "chars": 942,
    "preview": "import sourcemaps from 'rollup-plugin-sourcemaps';\nimport commonjs from '@rollup/plugin-commonjs';\nimport nodeResolve fr"
  },
  {
    "path": "addons/Dexie.Observable/tools/build-configs/rollup.tests.config.mjs",
    "chars": 942,
    "preview": "import sourcemaps from 'rollup-plugin-sourcemaps';\nimport commonjs from '@rollup/plugin-commonjs';\nimport nodeResolve fr"
  },
  {
    "path": "addons/Dexie.Observable/tools/build-configs/rollup.tests.unit.config.js",
    "chars": 942,
    "preview": "import sourcemaps from 'rollup-plugin-sourcemaps';\nimport commonjs from '@rollup/plugin-commonjs';\nimport nodeResolve fr"
  },
  {
    "path": "addons/Dexie.Observable/tools/build-configs/rollup.tests.unit.config.mjs",
    "chars": 942,
    "preview": "import sourcemaps from 'rollup-plugin-sourcemaps';\nimport commonjs from '@rollup/plugin-commonjs';\nimport nodeResolve fr"
  },
  {
    "path": "addons/Dexie.Observable/tools/replaceVersionAndDate.js",
    "chars": 374,
    "preview": "const fs = require('fs');\nconst files = process.argv.slice(2);\nconst version = require('../package.json').version;\n\nfile"
  },
  {
    "path": "addons/Dexie.Syncable/.gitignore",
    "chars": 62,
    "preview": "dist/*.js\ndist/*.map\ndist/*.ts\ndist/*.gz\n.eslintcache\n**/tmp/\n"
  },
  {
    "path": "addons/Dexie.Syncable/.npmignore",
    "chars": 39,
    "preview": "tools/\nsrc/\n.*\ntmp/\n**/tmp/\ntest\n*.log\n"
  },
  {
    "path": "addons/Dexie.Syncable/README.md",
    "chars": 8011,
    "preview": "# Dexie.Syncable.js\n\nEnables two-way synchronization with remote database.\n\n*NOTE! This package has been unmaintained fo"
  },
  {
    "path": "addons/Dexie.Syncable/api.d.ts",
    "chars": 6510,
    "preview": "/* dexie-syncable API - an independant syncronization API used by 'dexie-syncable'.\n * Version: 1.1\n * Date: December 2"
  },
  {
    "path": "addons/Dexie.Syncable/api.js",
    "chars": 146,
    "preview": "// This file is deliberatly left empty to allow the api.d.ts to contain the definitions for Dexie.Syncable without gener"
  },
  {
    "path": "addons/Dexie.Syncable/dist/README.md",
    "chars": 1287,
    "preview": "## Can't find dexie-syncable.js?\nTranspiled code (dist version) IS ONLY checked in to\nthe [releases](https://github.com/"
  },
  {
    "path": "addons/Dexie.Syncable/package.json",
    "chars": 3349,
    "preview": "{\n  \"name\": \"dexie-syncable\",\n  \"version\": \"4.0.1-beta.13\",\n  \"description\": \"Addon to Dexie that makes it possible to s"
  },
  {
    "path": "addons/Dexie.Syncable/src/.eslintrc.json",
    "chars": 706,
    "preview": "{\n  \"extends\": \"eslint:recommended\",\n  \"parserOptions\": {\n    \"ecmaVersion\": 6,\n    \"sourceType\": \"module\",\n    \"ecmaFea"
  },
  {
    "path": "addons/Dexie.Syncable/src/Dexie.Syncable.d.ts",
    "chars": 3814,
    "preview": "// Type definitions for dexie-syncable v{version}\n// Project: https://github.com/dfahlander/Dexie.js/tree/master/addons/"
  },
  {
    "path": "addons/Dexie.Syncable/src/Dexie.Syncable.js",
    "chars": 13302,
    "preview": "/* ========================================================================== \n *                           dexie-syncab"
  },
  {
    "path": "addons/Dexie.Syncable/src/PersistedContext.js",
    "chars": 472,
    "preview": "import Dexie from 'dexie';\n\nexport default function initPersistedContext(node) {\n  //\n  // PersistedContext : IPersisted"
  },
  {
    "path": "addons/Dexie.Syncable/src/apply-changes.js",
    "chars": 1431,
    "preview": "import { CREATE, DELETE, UPDATE } from './change_types';\nimport bulkUpdate from './bulk-update';\n\nexport default functio"
  },
  {
    "path": "addons/Dexie.Syncable/src/bulk-update.js",
    "chars": 1005,
    "preview": "import Dexie from 'dexie';\n\nexport default function bulkUpdate(table, changes) {\n  let keys = changes.map(c => c.key);\n "
  },
  {
    "path": "addons/Dexie.Syncable/src/change_types.js",
    "chars": 91,
    "preview": "// Change Types\nexport const CREATE = 1;\nexport const UPDATE = 2;\nexport const DELETE = 3;\n"
  },
  {
    "path": "addons/Dexie.Syncable/src/combine-create-and-update.js",
    "chars": 421,
    "preview": "import Dexie from 'dexie';\n\nexport default function combineCreateAndUpdate(prevChange, nextChange) {\n  var clonedChange "
  },
  {
    "path": "addons/Dexie.Syncable/src/combine-update-and-update.js",
    "chars": 1352,
    "preview": "import Dexie from 'dexie';\n\nexport default function combineUpdateAndUpdate(prevChange, nextChange) {\n  var clonedChange "
  },
  {
    "path": "addons/Dexie.Syncable/src/connect-fn.js",
    "chars": 2555,
    "preview": "import Dexie from 'dexie';\n\nimport initGetOrCreateSyncNode from './get-or-create-sync-node';\nimport initConnectProtocol "
  },
  {
    "path": "addons/Dexie.Syncable/src/connect-protocol.js",
    "chars": 13040,
    "preview": "import Dexie from 'dexie';\n\nimport initEnqueue from './enqueue';\nimport initSaveToUncommittedChanges from './save-to-unc"
  },
  {
    "path": "addons/Dexie.Syncable/src/enqueue.js",
    "chars": 1197,
    "preview": "import Dexie from 'dexie';\n\nexport default function initEnqueue(db) {\n  return function enqueue(context, fn, instanceID)"
  },
  {
    "path": "addons/Dexie.Syncable/src/finally-commit-all-changes.js",
    "chars": 3121,
    "preview": "import Dexie from 'dexie';\nimport initApplyChanges from './apply-changes';\n\nexport default function initFinallyCommitAll"
  },
  {
    "path": "addons/Dexie.Syncable/src/get-local-changes-for-node/get-base-revision-and-max-client-revision.js",
    "chars": 1150,
    "preview": "export default function getBaseRevisionAndMaxClientRevision(node) {\n  /// <param name=\"node\" type=\"db.observable.SyncNod"
  },
  {
    "path": "addons/Dexie.Syncable/src/get-local-changes-for-node/get-changes-since-revision.js",
    "chars": 2427,
    "preview": "import {CREATE, UPDATE} from '../change_types';\nimport mergeChange from '../merge-change';\n\nexport default function init"
  },
  {
    "path": "addons/Dexie.Syncable/src/get-local-changes-for-node/get-local-changes-for-node.js",
    "chars": 3438,
    "preview": "import Dexie from 'dexie';\n\nimport getBaseRevisionAndMaxClientRevision from './get-base-revision-and-max-client-revision"
  },
  {
    "path": "addons/Dexie.Syncable/src/get-local-changes-for-node/get-table-objects-as-changes.js",
    "chars": 2229,
    "preview": "import {CREATE} from '../change_types';\nimport getBaseRevisionAndMaxClientRevision from './get-base-revision-and-max-cli"
  },
  {
    "path": "addons/Dexie.Syncable/src/get-or-create-sync-node.js",
    "chars": 2406,
    "preview": "import Dexie from 'dexie';\n\nimport initPersistedContext from './PersistedContext';\n\nexport default function initGetOrCre"
  },
  {
    "path": "addons/Dexie.Syncable/src/merge-change.js",
    "chars": 1827,
    "preview": "import { CREATE, UPDATE, DELETE } from './change_types';\nimport combineCreateAndUpdate from './combine-create-and-update"
  },
  {
    "path": "addons/Dexie.Syncable/src/save-to-uncommitted-changes.js",
    "chars": 700,
    "preview": "export default function initSaveToUncommittedChanges(db, node) {\n  return function saveToUncommittedChanges(changes, rem"
  },
  {
    "path": "addons/Dexie.Syncable/src/statuses.js",
    "chars": 722,
    "preview": "export const Statuses = {\n  ERROR: -1, // An irreparable error occurred and the sync provider is dead.\n  OFFLINE: 0, // "
  },
  {
    "path": "addons/Dexie.Syncable/src/syncable-connect.js",
    "chars": 3848,
    "preview": "import Dexie from 'dexie';\n\nconst Promise = Dexie.Promise;\n\nexport default function initSyncableConnect(db, connect) {\n "
  },
  {
    "path": "addons/Dexie.Syncable/test/gh-actions.sh",
    "chars": 369,
    "preview": "#!/bin/bash -e\ncd ../../Dexie.Observable\necho \"Installing dependencies for dexie-observable\"\npnpm install >/dev/null\nech"
  },
  {
    "path": "addons/Dexie.Syncable/test/integration/dummy-sync-protocol.js",
    "chars": 3564,
    "preview": "Dexie.Syncable.registerSyncProtocol(\"logger\", {\n    sync: function (context, url, options, baseRevision, syncedRevision,"
  },
  {
    "path": "addons/Dexie.Syncable/test/integration/karma-env.js",
    "chars": 344,
    "preview": "// workerImports will be used by tests-open.js in the dexie test suite when\n// launching a Worker. This line will instru"
  },
  {
    "path": "addons/Dexie.Syncable/test/integration/karma.conf.js",
    "chars": 1368,
    "preview": "// Include common configuration\nconst {karmaCommon, getKarmaConfig, defaultBrowserMatrix} = require('../../../../test/ka"
  },
  {
    "path": "addons/Dexie.Syncable/test/integration/test-syncable-dexie-tests.html",
    "chars": 1223,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>Dexie Unit tests with Dexie.Syncable applied and dummy "
  },
  {
    "path": "addons/Dexie.Syncable/test/test-typings/test-typings.ts",
    "chars": 3935,
    "preview": "\nimport Dexie from 'dexie';\nimport 'dexie-observable';\nimport '../../src/Dexie.Syncable';\nimport dexieSyncable from '../"
  },
  {
    "path": "addons/Dexie.Syncable/test/test-typings/tsconfig.json",
    "chars": 317,
    "preview": "{\n    \"compilerOptions\": {\n        \"module\": \"es6\",\n        \"target\": \"es5\",\n        \"noImplicitAny\": true,\n        \"str"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/.eslintrc.json",
    "chars": 245,
    "preview": "{\n  \"parserOptions\": {\n    \"ecmaVersion\": 6,\n    \"sourceType\": \"module\",\n    \"ecmaFeatures\": {\n    }\n  },\n  \"env\": {\n   "
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/.gitignore",
    "chars": 26,
    "preview": "/bundle.js\n/bundle.js.map\n"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/get-local-changes-for-node/tests-get-base-revision-and-max-client-revision.js",
    "chars": 2114,
    "preview": "import {module, test, deepEqual, equal, ok} from 'QUnit';\nimport getBaseRevisionAndMaxClientRevision from '../../../src/"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/get-local-changes-for-node/tests-get-changes-since-revision.js",
    "chars": 7360,
    "preview": "import Dexie from 'dexie';\nimport 'dexie-observable';\nimport {module, asyncTest, start, stop, strictEqual, deepEqual, ok"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/get-local-changes-for-node/tests-get-local-changes-for-node.js",
    "chars": 5243,
    "preview": "import Dexie from 'dexie';\nimport 'dexie-observable';\nimport {module, asyncTest, start, stop, strictEqual, deepEqual, ok"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/karma-env.js",
    "chars": 32,
    "preview": "QUnit.config.autostart = false;\n"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/karma.conf.js",
    "chars": 1321,
    "preview": "// Include common configuration\nconst {karmaCommon, getKarmaConfig, defaultBrowserMatrix} = require('../../../../test/ka"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/run-unit-tests.html",
    "chars": 906,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>Dexie.Syncable Unit tests</title>\n  <link rel=\"styleshe"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-PersistedContext.js",
    "chars": 1752,
    "preview": "import Dexie from 'dexie';\nimport observable from 'dexie-observable';\n// Add this so we have the SyncNode.prototype.save"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-WebSocketSyncServer.js",
    "chars": 2664,
    "preview": "import 'dexie-observable';\nimport '../../src/Dexie.Syncable';\nimport {module, asyncTest, start, stop, strictEqual, deep"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-apply-changes.js",
    "chars": 3105,
    "preview": "import Dexie from 'dexie';\nimport {module, asyncTest, start, stop, strictEqual, deepEqual, ok} from 'QUnit';\nimport {res"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-bulk-update.js",
    "chars": 2021,
    "preview": "import Dexie from 'dexie';\nimport {module, asyncTest, start, stop, strictEqual, deepEqual, ok} from 'QUnit';\nimport {res"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-changing-options.js",
    "chars": 3322,
    "preview": "import Dexie from 'dexie';\nimport 'dexie-observable';\nimport '../../src/Dexie.Syncable';\nimport {module, asyncTest, star"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-combine-create-and-update.js",
    "chars": 925,
    "preview": "import {module, test, deepEqual, ok} from 'QUnit';\nimport combineCreateAndUpdate from '../../src/combine-create-and-upda"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-combine-update-and-update.js",
    "chars": 1877,
    "preview": "import {module, test, deepEqual, ok} from 'QUnit';\nimport combineUpdateAndUpdate from '../../src/combine-update-and-upda"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-finally-commit-all-changes.js",
    "chars": 4836,
    "preview": "import Dexie from 'dexie';\nimport observable from 'dexie-observable';\nimport {module, asyncTest, start, stop, strictEqua"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-get-or-create-sync-node.js",
    "chars": 3957,
    "preview": "import Dexie from 'dexie';\nimport observable from 'dexie-observable';\n// Add this so we have the SyncNode.prototype.save"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-merge-change.js",
    "chars": 3893,
    "preview": "import {module, test, deepEqual} from 'QUnit';\nimport mergeChange from '../../src/merge-change';\nimport {CREATE, UPDATE,"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-register-sync-protocol.js",
    "chars": 1242,
    "preview": "import Dexie from 'dexie';\nimport '../../src/Dexie.Syncable';\nimport {module, test, strictEqual, raises} from 'QUnit';\n\n"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-save-to-uncommitted-changes.js",
    "chars": 2532,
    "preview": "import Dexie from 'dexie';\nimport observable from 'dexie-observable';\nimport {module, asyncTest, start, stop, strictEqua"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-syncable-partials.js",
    "chars": 7847,
    "preview": "import Dexie from 'dexie';\nimport 'dexie-observable';\nimport '../../src/Dexie.Syncable';\nimport {module, asyncTest, star"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-syncable.js",
    "chars": 10921,
    "preview": "import Dexie from 'dexie';\nimport 'dexie-observable';\nimport '../../src/Dexie.Syncable';\nimport {module, asyncTest, sta"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/tests-syncprovider.js",
    "chars": 9377,
    "preview": "import Dexie from 'dexie';\nimport 'dexie-observable';\nimport '../../src/Dexie.Syncable';\nimport {module, asyncTest, sta"
  },
  {
    "path": "addons/Dexie.Syncable/test/unit/unit-tests-all.js",
    "chars": 842,
    "preview": "import './get-local-changes-for-node/tests-get-base-revision-and-max-client-revision.js';\nimport './get-local-changes-fo"
  },
  {
    "path": "addons/Dexie.Syncable/tools/build-configs/banner.txt",
    "chars": 596,
    "preview": "/* ========================================================================== \n *                           dexie-syncab"
  },
  {
    "path": "addons/Dexie.Syncable/tools/build-configs/rollup.config.mjs",
    "chars": 1008,
    "preview": "import sourcemaps from 'rollup-plugin-sourcemaps';\nimport {readFileSync} from 'fs';\nimport path from 'path';\nimport { fi"
  },
  {
    "path": "addons/Dexie.Syncable/tools/build-configs/rollup.tests.config.js",
    "chars": 925,
    "preview": "import sourcemaps from 'rollup-plugin-sourcemaps';\nimport commonjs from '@rollup/plugin-commonjs';\nimport nodeResolve fr"
  },
  {
    "path": "addons/Dexie.Syncable/tools/build-configs/rollup.tests.config.mjs",
    "chars": 925,
    "preview": "import sourcemaps from 'rollup-plugin-sourcemaps';\nimport commonjs from '@rollup/plugin-commonjs';\nimport nodeResolve fr"
  },
  {
    "path": "addons/Dexie.Syncable/tools/replaceVersionAndDate.js",
    "chars": 374,
    "preview": "const fs = require('fs');\nconst files = process.argv.slice(2);\nconst version = require('../package.json').version;\n\nfile"
  },
  {
    "path": "addons/dexie-cloud/.gitignore",
    "chars": 85,
    "preview": "dist/\nesnext/\n.eslintcache\n**/tmp/\ntest/**/bundle.*\ndexie-cloud.key\ndexie-cloud.json\n"
  },
  {
    "path": "addons/dexie-cloud/.npmignore",
    "chars": 91,
    "preview": ".DS_Store\ntools/\nsrc/\nbin-src/\n.*\ntmp/\n**/tmp/\ntest\n*.log\ndexie-cloud.key\ndexie-cloud.json\n"
  },
  {
    "path": "addons/dexie-cloud/.vscode/settings.json",
    "chars": 34,
    "preview": "{\n  \"editor.formatOnSave\": true\n}\n"
  },
  {
    "path": "addons/dexie-cloud/README.md",
    "chars": 1440,
    "preview": "The web client for [Dexie Cloud](https://dexie.org/cloud/).\n\n## Getting started\n\n```\nnpm install dexie@latest\nnpm instal"
  },
  {
    "path": "addons/dexie-cloud/TODO-SOCIALAUTH.md",
    "chars": 11973,
    "preview": "# Social Authentication for Dexie Cloud\n\n## Overview\n\nThis feature adds support for OAuth 2.0 social login providers (Go"
  },
  {
    "path": "addons/dexie-cloud/dexie-cloud-import.json",
    "chars": 107,
    "preview": "{\n  \"demoUsers\": {\n    \"foo@demo.local\": {},\n    \"bar@demo.local\": {},\n    \"issue2228@demo.local\": {}\n  }\n}"
  },
  {
    "path": "addons/dexie-cloud/oauth_flow.md",
    "chars": 8210,
    "preview": "# OAuth Authorization Code Flow for Dexie Cloud SPA Integration\n\n## Actors\n\n- **SPA** – Customer's frontend application\n"
  },
  {
    "path": "addons/dexie-cloud/package.json",
    "chars": 3390,
    "preview": "{\n  \"name\": \"dexie-cloud-addon\",\n  \"version\": \"4.4.1\",\n  \"description\": \"Dexie addon that syncs with to Dexie Cloud\",\n  "
  },
  {
    "path": "addons/dexie-cloud/src/DISABLE_SERVICEWORKER_STRATEGY.ts",
    "chars": 728,
    "preview": "import { isFirefox } from './isFirefox';\nimport { isSafari, safariVersion } from './isSafari';\n\n// What we know: Safari "
  },
  {
    "path": "addons/dexie-cloud/src/DXCWebSocketStatus.ts",
    "chars": 105,
    "preview": "export type DXCWebSocketStatus = \"not-started\" | \"connecting\" | \"connected\" | \"disconnected\" | \"error\";\n\n"
  },
  {
    "path": "addons/dexie-cloud/src/DexieCloudAPI.ts",
    "chars": 5046,
    "preview": "import { DexieCloudOptions } from './DexieCloudOptions';\nimport { DBRealmRole, DexieCloudSchema, AuthProvidersResponse }"
  },
  {
    "path": "addons/dexie-cloud/src/DexieCloudOptions.ts",
    "chars": 3800,
    "preview": "import type { TokenFinalResponse } from 'dexie-cloud-common';\nimport type { LoginHints } from './DexieCloudAPI';\n\nexport"
  },
  {
    "path": "addons/dexie-cloud/src/DexieCloudSyncOptions.ts",
    "chars": 89,
    "preview": "\nexport interface DexieCloudSyncOptions {\n  wait: boolean;\n  purpose: 'push' | 'pull';\n}\n"
  },
  {
    "path": "addons/dexie-cloud/src/DexieCloudTable.ts",
    "chars": 974,
    "preview": "import { EntityTable, InsertType } from 'dexie';\n\nexport interface DexieCloudEntity {\n  owner: string;\n  realmId: string"
  },
  {
    "path": "addons/dexie-cloud/src/InvalidLicenseError.ts",
    "chars": 401,
    "preview": "export class InvalidLicenseError extends Error {\n  name = 'InvalidLicenseError';\n  license?: 'expired' | 'deactivated';\n"
  },
  {
    "path": "addons/dexie-cloud/src/Invite.ts",
    "chars": 237,
    "preview": "import { DBPermissionSet, DBRealm, DBRealmMember } from 'dexie-cloud-common';\n\nexport interface Invite extends DBRealmMe"
  },
  {
    "path": "addons/dexie-cloud/src/PermissionChecker.ts",
    "chars": 2649,
    "preview": "import { KeyPaths } from 'dexie';\nimport { DBPermissionSet } from 'dexie-cloud-common';\n\ntype TableName<T> = T extends {"
  },
  {
    "path": "addons/dexie-cloud/src/TSON.ts",
    "chars": 3236,
    "preview": "import { \n  TypesonSimplified, \n  undefinedTypeDef,\n  blobTypeDef,\n  typedArrayTypeDefs,\n  arrayBufferTypeDef,\n  fileTyp"
  },
  {
    "path": "addons/dexie-cloud/src/WSObservable.ts",
    "chars": 13792,
    "preview": "import { DBOperationsSet } from 'dexie-cloud-common';\nimport { BehaviorSubject, Observable, Subscriber, Subscription, ta"
  },
  {
    "path": "addons/dexie-cloud/src/associate.ts",
    "chars": 246,
    "preview": "export function associate<T extends object,M>(factory: (x: T)=>M): (x: T) => M {\n  const wm = new WeakMap<T, M>();\n  ret"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/AuthPersistedContext.ts",
    "chars": 886,
    "preview": "import { DexieCloudDB } from \"../db/DexieCloudDB\";\nimport { UserLogin } from \"../db/entities/UserLogin\";\n\nexport interfa"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/TokenErrorResponseError.ts",
    "chars": 577,
    "preview": "import { TokenErrorResponse } from 'dexie-cloud-common';\n\nexport class TokenErrorResponseError extends Error {\n  title: "
  },
  {
    "path": "addons/dexie-cloud/src/authentication/TokenExpiredError.ts",
    "chars": 79,
    "preview": "export class TokenExpiredError extends Error {\n  name = \"TokenExpiredError\";\n}\n"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/UNAUTHORIZED_USER.ts",
    "chars": 317,
    "preview": "import { UserLogin } from '../db/entities/UserLogin';\n\nexport const UNAUTHORIZED_USER: UserLogin = {\n  userId: \"unauthor"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/authenticate.ts",
    "chars": 10087,
    "preview": "import Dexie from 'dexie';\nimport type {\n  RefreshTokenRequest,\n  TokenErrorResponse,\n  TokenFinalResponse,\n} from 'dexi"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/currentUserObservable.ts",
    "chars": 213,
    "preview": "import { Dexie } from \"dexie\";\nimport { BehaviorSubject } from 'rxjs';\nimport { UserLogin } from '../db/entities/UserLog"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/exchangeOAuthCode.ts",
    "chars": 3226,
    "preview": "import type {\n  AuthorizationCodeTokenRequest,\n  TokenFinalResponse,\n  TokenErrorResponse,\n} from 'dexie-cloud-common';\n"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/fetchAuthProviders.ts",
    "chars": 1769,
    "preview": "import type { AuthProvidersResponse } from 'dexie-cloud-common';\n\n/** Default response when OAuth is disabled or unavail"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/handleOAuthCallback.ts",
    "chars": 5414,
    "preview": "import { OAuthError } from '../errors/OAuthError';\n\n/** Parsed OAuth callback parameters from dxc-auth query parameter *"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/interactWithUser.ts",
    "chars": 8785,
    "preview": "import Dexie from 'dexie';\nimport type { OAuthProviderInfo } from 'dexie-cloud-common';\nimport { BehaviorSubject } from "
  },
  {
    "path": "addons/dexie-cloud/src/authentication/login.ts",
    "chars": 2560,
    "preview": "import { DexieCloudDB } from '../db/DexieCloudDB';\nimport { LoginHints } from '../DexieCloudAPI';\nimport { triggerSync }"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/logout.ts",
    "chars": 2372,
    "preview": "import { DexieCloudDB } from '../db/DexieCloudDB';\nimport { TXExpandos } from '../types/TXExpandos';\nimport { confirmLog"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/oauthLogin.ts",
    "chars": 2453,
    "preview": "import { OAuthError } from '../errors/OAuthError';\n\n/** Options for initiating OAuth redirect */\nexport interface OAuthR"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/otpFetchTokenCallback.ts",
    "chars": 8492,
    "preview": "import {\n  AuthorizationCodeTokenRequest,\n  DemoTokenRequest,\n  OTPTokenRequest1,\n  OTPTokenRequest2,\n  TokenErrorRespon"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/setCurrentUser.ts",
    "chars": 1841,
    "preview": "import { DexieCloudDB } from '../db/DexieCloudDB';\nimport { prodLog } from '../prodLog';\nimport { AuthPersistedContext }"
  },
  {
    "path": "addons/dexie-cloud/src/authentication/waitUntil.ts",
    "chars": 328,
    "preview": "import { filter, firstValueFrom, from, InteropObservable, Observable } from 'rxjs';\n\nexport function waitUntil<T>(\n  o: "
  },
  {
    "path": "addons/dexie-cloud/src/computeSyncState.ts",
    "chars": 3475,
    "preview": "import { combineLatest, Observable, of } from 'rxjs';\nimport { debounceTime, map, startWith, switchMap } from 'rxjs/oper"
  },
  {
    "path": "addons/dexie-cloud/src/createSharedValueObservable.ts",
    "chars": 1030,
    "preview": "import {\n  concat,\n  from,\n  InteropObservable,\n  map,\n  Observable,\n  ObservableInput,\n  share,\n  timer,\n} from 'rxjs';"
  },
  {
    "path": "addons/dexie-cloud/src/currentUserEmitter.ts",
    "chars": 371,
    "preview": "import Dexie from \"dexie\";\nimport { BehaviorSubject } from \"rxjs\";\nimport { associate } from \"./associate\";\nimport { UNA"
  },
  {
    "path": "addons/dexie-cloud/src/db/DexieCloudDB.ts",
    "chars": 6801,
    "preview": "import Dexie, { Table } from 'dexie';\nimport { GuardedJob } from './entities/GuardedJob';\nimport { UserLogin } from './e"
  },
  {
    "path": "addons/dexie-cloud/src/db/entities/BaseRevisionMapEntry.ts",
    "chars": 195,
    "preview": "// This interface has been moved to dexie-cloud-common. TODO: Remove file and update imports.\nexport interface BaseRevis"
  },
  {
    "path": "addons/dexie-cloud/src/db/entities/EntityCommon.ts",
    "chars": 161,
    "preview": "export interface EntityCommon {\n  realmId?: string;\n  owner?: string;\n  $ts?: string;\n  _hasBlobRefs?: 1; // Indicates t"
  },
  {
    "path": "addons/dexie-cloud/src/db/entities/GuardedJob.ts",
    "chars": 87,
    "preview": "\nexport interface GuardedJob {\n  nodeId: string;\n  started: Date;\n  heartbeat: Date;\n}\n"
  },
  {
    "path": "addons/dexie-cloud/src/db/entities/Member.ts",
    "chars": 697,
    "preview": "export interface Member {\n  id?: string; // Auto-generated universal primary key\n  realmId: string;\n  userId?: string; /"
  },
  {
    "path": "addons/dexie-cloud/src/db/entities/PersistedSyncState.ts",
    "chars": 458,
    "preview": "export interface PersistedSyncState {\n  serverRevision?: any;\n  yServerRevision?: string;\n  latestRevisions: {\n    [tabl"
  },
  {
    "path": "addons/dexie-cloud/src/db/entities/Realm.ts",
    "chars": 400,
    "preview": "export interface Realm {\n  /** Primary key of the realm.\n   */\n  realmId: string;\n\n  /** The name of the realm.\n   *\n   "
  },
  {
    "path": "addons/dexie-cloud/src/db/entities/Role.ts",
    "chars": 306,
    "preview": "export interface Role {\n  realmId: string;\n  name: string;\n  permissions: {\n    add?: string[] | \"*\"; // array of tables"
  },
  {
    "path": "addons/dexie-cloud/src/db/entities/UserLogin.ts",
    "chars": 683,
    "preview": "import { DXCUserInteraction } from \"../../types/DXCUserInteraction\";\n\nexport interface UserLogin {\n  userId?: string;\n  "
  },
  {
    "path": "addons/dexie-cloud/src/default-ui/Dialog.tsx",
    "chars": 417,
    "preview": "import { Styles } from './Styles';\nimport { ComponentChildren, h } from 'preact';\n\nexport function Dialog({ children, cl"
  },
  {
    "path": "addons/dexie-cloud/src/default-ui/LoginDialog.tsx",
    "chars": 7646,
    "preview": "import { Dialog } from './Dialog';\nimport { Styles } from './Styles';\nimport { h, Fragment } from 'preact';\nimport { use"
  },
  {
    "path": "addons/dexie-cloud/src/default-ui/OptionButton.tsx",
    "chars": 2030,
    "preview": "import { h } from 'preact';\nimport { DXCOption } from '../types/DXCUserInteraction';\nimport { Styles } from './Styles';\n"
  },
  {
    "path": "addons/dexie-cloud/src/default-ui/Styles.ts",
    "chars": 5397,
    "preview": "export const Styles: { [styleAlias: string]: Partial<CSSStyleDeclaration> | any} = {\n  Error: {\n    color: \"red\",\n  },\n "
  },
  {
    "path": "addons/dexie-cloud/src/default-ui/index.tsx",
    "chars": 1781,
    "preview": "import Dexie from \"dexie\";\nimport \"../extend-dexie-interface\";\nimport { h, Component } from \"preact\";\nimport { from, Sub"
  },
  {
    "path": "addons/dexie-cloud/src/define-ydoc-trigger.ts",
    "chars": 7361,
    "preview": "import Dexie, {\n  RangeSet,\n  type DBCore,\n  type Middleware,\n  type Table,\n} from 'dexie';\nimport { DexieYProvider, YUp"
  },
  {
    "path": "addons/dexie-cloud/src/dexie-cloud-addon.ts",
    "chars": 122,
    "preview": "import dexieCloudAddon from './dexie-cloud-client';\nexport * from './dexie-cloud-client';\nexport default dexieCloudAddon"
  },
  {
    "path": "addons/dexie-cloud/src/dexie-cloud-client.ts",
    "chars": 25404,
    "preview": "import Dexie, { liveQuery, Subscription, Table } from 'dexie';\nimport {\n  DBPermissionSet,\n  DBRealmMember,\n  getDbNameF"
  },
  {
    "path": "addons/dexie-cloud/src/errors/HttpError.ts",
    "chars": 262,
    "preview": "export class HttpError extends Error {\n  httpStatus: number;\n  constructor(\n    res: Response,\n    message?: string)\n  {"
  },
  {
    "path": "addons/dexie-cloud/src/errors/OAuthError.ts",
    "chars": 1312,
    "preview": "/** OAuth-specific error codes */\nexport type OAuthErrorCode =\n  | 'access_denied'\n  | 'invalid_state'\n  | 'email_not_ve"
  },
  {
    "path": "addons/dexie-cloud/src/errors/OAuthRedirectError.ts",
    "chars": 494,
    "preview": "/**\n * Error thrown when initiating an OAuth redirect.\n * \n * This is not a real error - it's used to signal that the pa"
  },
  {
    "path": "addons/dexie-cloud/src/extend-dexie-interface.ts",
    "chars": 1054,
    "preview": "import { IndexableType, TableProp } from 'dexie';\nimport {\n  DBRealm,\n  DBRealmMember,\n  DBRealmRole,\n} from 'dexie-clou"
  },
  {
    "path": "addons/dexie-cloud/src/getGlobalRolesObservable.ts",
    "chars": 730,
    "preview": "import Dexie, { liveQuery } from 'dexie';\nimport { DBRealmRole } from 'dexie-cloud-common';\nimport { associate } from '."
  },
  {
    "path": "addons/dexie-cloud/src/getInternalAccessControlObservable.ts",
    "chars": 1700,
    "preview": "import Dexie, { liveQuery } from 'dexie';\nimport { DBRealm, DBRealmMember } from 'dexie-cloud-common';\nimport { concat, "
  },
  {
    "path": "addons/dexie-cloud/src/getInvitesObservable.ts",
    "chars": 2120,
    "preview": "import { Dexie, liveQuery } from 'dexie';\nimport { DBRealmMember } from 'dexie-cloud-common';\nimport { combineLatest } f"
  },
  {
    "path": "addons/dexie-cloud/src/getPermissionsLookupObservable.ts",
    "chars": 2744,
    "preview": "import Dexie from 'dexie';\nimport { DBPermissionSet, DBRealm, DBRealmMember } from 'dexie-cloud-common';\nimport { combin"
  },
  {
    "path": "addons/dexie-cloud/src/getTiedRealmId.ts",
    "chars": 200,
    "preview": "\nexport function getTiedRealmId(objectId: string) {\n  return 'rlm~' + objectId;\n}\n\nexport function getTiedObjectId(realm"
  },
  {
    "path": "addons/dexie-cloud/src/helpers/BroadcastedAndLocalEvent.ts",
    "chars": 2810,
    "preview": "import { Observable } from \"rxjs\";\nimport { SWBroadcastChannel } from \"./SWBroadcastChannel\";\n\nconst events: Map<string,"
  },
  {
    "path": "addons/dexie-cloud/src/helpers/CancelToken.ts",
    "chars": 233,
    "preview": "import Dexie from \"dexie\";\n\nexport interface CancelToken {\n  cancelled: boolean;\n}\n\nexport function throwIfCancelled(can"
  },
  {
    "path": "addons/dexie-cloud/src/helpers/IS_SERVICE_WORKER.ts",
    "chars": 103,
    "preview": "export const IS_SERVICE_WORKER =\n  typeof self !== \"undefined\" && \"clients\" in self && !self.document;\n"
  },
  {
    "path": "addons/dexie-cloud/src/helpers/SWBroadcastChannel.ts",
    "chars": 2290,
    "preview": "const swHolder: { registration?: ServiceWorkerRegistration } = {};\nconst swContainer = typeof self !== 'undefined' && se"
  },
  {
    "path": "addons/dexie-cloud/src/helpers/allSettled.ts",
    "chars": 488,
    "preview": "\nexport function allSettled(possiblePromises: any[]) {\n  return new Promise(resolve => {\n      if (possiblePromises.leng"
  },
  {
    "path": "addons/dexie-cloud/src/helpers/bulkUpdate.ts",
    "chars": 854,
    "preview": "import Dexie, { Table, cmp } from 'dexie';\n\nexport async function bulkUpdate(\n  table: Table,\n  keys: any[],\n  changeSpe"
  },
  {
    "path": "addons/dexie-cloud/src/helpers/computeRealmSetHash.ts",
    "chars": 669,
    "preview": "import { PersistedSyncState } from '../db/entities/PersistedSyncState';\nimport { b64encode } from 'dexie-cloud-common';\n"
  },
  {
    "path": "addons/dexie-cloud/src/helpers/date-constants.ts",
    "chars": 164,
    "preview": "export const SECONDS = 1000;\nexport const MINUTES = 60 * SECONDS;\nexport const HOURS = 60 * MINUTES;\nexport const DAYS ="
  }
]

// ... and 592 more files (download for full content)

About this extraction

This page contains the full source code of the dexie/Dexie.js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 792 files (2.3 MB), approximately 634.1k tokens, and a symbol index with 1558 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!