dexie-cloud-addon 4.4.0 → 4.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modern/DexieCloudOptions.d.ts +12 -0
- package/dist/modern/default-ui/AuthProviderButton.d.ts +21 -0
- package/dist/modern/default-ui/ProviderSelectionDialog.d.ts +7 -0
- package/dist/modern/default-ui/SelectDialog.d.ts +10 -0
- package/dist/modern/dexie-cloud-addon.js +132 -35
- package/dist/modern/dexie-cloud-addon.js.map +1 -1
- package/dist/modern/dexie-cloud-addon.min.js +1 -1
- package/dist/modern/dexie-cloud-addon.min.js.gz +0 -0
- package/dist/modern/dexie-cloud-addon.min.js.map +1 -1
- package/dist/modern/service-worker.js +269 -172
- package/dist/modern/service-worker.js.map +1 -1
- package/dist/modern/service-worker.min.js +1 -1
- package/dist/modern/service-worker.min.js.map +1 -1
- package/dist/modern/sync/blobOffloading.d.ts +5 -4
- package/dist/modern/sync/blobResolve.d.ts +3 -3
- package/dist/umd/DISABLE_SERVICEWORKER_STRATEGY.d.ts +1 -0
- package/dist/umd/DXCWebSocketStatus.d.ts +1 -0
- package/dist/umd/DexieCloudAPI.d.ts +75 -0
- package/dist/umd/DexieCloudOptions.d.ts +27 -0
- package/dist/umd/DexieCloudSyncOptions.d.ts +4 -0
- package/dist/umd/DexieCloudTable.d.ts +18 -0
- package/dist/umd/InvalidLicenseError.d.ts +5 -0
- package/dist/umd/Invite.d.ts +8 -0
- package/dist/umd/PermissionChecker.d.ts +15 -0
- package/dist/umd/TSON.d.ts +17 -0
- package/dist/umd/WSObservable.d.ts +72 -0
- package/dist/umd/associate.d.ts +1 -0
- package/dist/umd/authentication/AuthPersistedContext.d.ts +9 -0
- package/dist/umd/authentication/TokenErrorResponseError.d.ts +10 -0
- package/dist/umd/authentication/TokenExpiredError.d.ts +3 -0
- package/dist/umd/authentication/UNAUTHORIZED_USER.d.ts +2 -0
- package/dist/umd/authentication/authenticate.d.ts +13 -0
- package/dist/umd/authentication/currentUserObservable.d.ts +1 -0
- package/dist/umd/authentication/interactWithUser.d.ts +21 -0
- package/dist/umd/authentication/login.d.ts +3 -0
- package/dist/umd/authentication/logout.d.ts +5 -0
- package/dist/umd/authentication/otpFetchTokenCallback.d.ts +3 -0
- package/dist/umd/authentication/setCurrentUser.d.ts +14 -0
- package/dist/umd/authentication/waitUntil.d.ts +3 -0
- package/dist/umd/computeSyncState.d.ts +4 -0
- package/dist/umd/createSharedValueObservable.d.ts +3 -0
- package/dist/umd/currentUserEmitter.d.ts +3 -0
- package/dist/umd/db/DexieCloudDB.d.ts +61 -0
- package/dist/umd/db/entities/BaseRevisionMapEntry.d.ts +5 -0
- package/dist/umd/db/entities/EntityCommon.d.ts +5 -0
- package/dist/umd/db/entities/GuardedJob.d.ts +5 -0
- package/dist/umd/db/entities/Member.d.ts +19 -0
- package/dist/umd/db/entities/PersistedSyncState.d.ts +22 -0
- package/dist/umd/db/entities/Realm.d.ts +14 -0
- package/dist/umd/db/entities/Role.d.ts +11 -0
- package/dist/umd/db/entities/UserLogin.d.ts +23 -0
- package/dist/umd/default-ui/Dialog.d.ts +5 -0
- package/dist/umd/default-ui/LoginDialog.d.ts +3 -0
- package/dist/umd/default-ui/Styles.d.ts +3 -0
- package/dist/umd/default-ui/index.d.ts +24 -0
- package/dist/umd/define-ydoc-trigger.d.ts +3 -0
- package/dist/umd/dexie-cloud-addon.d.ts +3 -0
- package/dist/umd/dexie-cloud-addon.js +133 -36
- package/dist/umd/dexie-cloud-addon.js.gz +0 -0
- package/dist/umd/dexie-cloud-addon.js.map +1 -1
- package/dist/umd/dexie-cloud-addon.min.js +1 -1
- package/dist/umd/dexie-cloud-addon.min.js.gz +0 -0
- package/dist/umd/dexie-cloud-addon.min.js.map +1 -1
- package/dist/umd/dexie-cloud-client.d.ts +23 -0
- package/dist/umd/errors/HttpError.d.ts +5 -0
- package/dist/umd/extend-dexie-interface.d.ts +23 -0
- package/dist/umd/getGlobalRolesObservable.d.ts +5 -0
- package/dist/umd/getInternalAccessControlObservable.d.ts +12 -0
- package/dist/umd/getInvitesObservable.d.ts +23 -0
- package/dist/umd/getPermissionsLookupObservable.d.ts +16 -0
- package/dist/umd/getTiedRealmId.d.ts +2 -0
- package/dist/umd/helpers/BroadcastedAndLocalEvent.d.ts +8 -0
- package/dist/umd/helpers/CancelToken.d.ts +4 -0
- package/dist/umd/helpers/IS_SERVICE_WORKER.d.ts +1 -0
- package/dist/umd/helpers/SWBroadcastChannel.d.ts +12 -0
- package/dist/umd/helpers/allSettled.d.ts +1 -0
- package/dist/umd/helpers/bulkUpdate.d.ts +4 -0
- package/dist/umd/helpers/computeRealmSetHash.d.ts +2 -0
- package/dist/umd/helpers/date-constants.d.ts +5 -0
- package/dist/umd/helpers/flatten.d.ts +1 -0
- package/dist/umd/helpers/getMutationTable.d.ts +1 -0
- package/dist/umd/helpers/getSyncableTables.d.ts +4 -0
- package/dist/umd/helpers/getTableFromMutationTable.d.ts +1 -0
- package/dist/umd/helpers/makeArray.d.ts +1 -0
- package/dist/umd/helpers/randomString.d.ts +1 -0
- package/dist/umd/helpers/resolveText.d.ts +16 -0
- package/dist/umd/helpers/throwVersionIncrementNeeded.d.ts +1 -0
- package/dist/umd/helpers/visibilityState.d.ts +1 -0
- package/dist/umd/isEagerSyncDisabled.d.ts +2 -0
- package/dist/umd/isFirefox.d.ts +1 -0
- package/dist/umd/isSafari.d.ts +2 -0
- package/dist/umd/mapValueObservable.d.ts +5 -0
- package/dist/umd/mergePermissions.d.ts +2 -0
- package/dist/umd/middleware-helpers/guardedTable.d.ts +11 -0
- package/dist/umd/middleware-helpers/idGenerationHelpers.d.ts +18 -0
- package/dist/umd/middlewares/createIdGenerationMiddleware.d.ts +3 -0
- package/dist/umd/middlewares/createImplicitPropSetterMiddleware.d.ts +3 -0
- package/dist/umd/middlewares/createMutationTrackingMiddleware.d.ts +17 -0
- package/dist/umd/middlewares/outstandingTransaction.d.ts +4 -0
- package/dist/umd/overrideParseStoresSpec.d.ts +4 -0
- package/dist/umd/performInitialSync.d.ts +4 -0
- package/dist/umd/permissions.d.ts +9 -0
- package/dist/umd/prodLog.d.ts +9 -0
- package/dist/umd/service-worker.d.ts +1 -0
- package/dist/umd/service-worker.js +270 -173
- package/dist/umd/service-worker.js.map +1 -1
- package/dist/umd/service-worker.min.js +1 -1
- package/dist/umd/service-worker.min.js.map +1 -1
- package/dist/umd/sync/DEXIE_CLOUD_SYNCER_ID.d.ts +1 -0
- package/dist/umd/sync/LocalSyncWorker.d.ts +7 -0
- package/dist/umd/sync/SyncRequiredError.d.ts +3 -0
- package/dist/umd/sync/applyServerChanges.d.ts +3 -0
- package/dist/umd/sync/connectWebSocket.d.ts +2 -0
- package/dist/umd/sync/encodeIdsForServer.d.ts +4 -0
- package/dist/umd/sync/extractRealm.d.ts +2 -0
- package/dist/umd/sync/getLatestRevisionsPerTable.d.ts +6 -0
- package/dist/umd/sync/getTablesToSyncify.d.ts +3 -0
- package/dist/umd/sync/isOnline.d.ts +1 -0
- package/dist/umd/sync/isSyncNeeded.d.ts +2 -0
- package/dist/umd/sync/listClientChanges.d.ts +9 -0
- package/dist/umd/sync/listSyncifiedChanges.d.ts +5 -0
- package/dist/umd/sync/messageConsumerIsReady.d.ts +2 -0
- package/dist/umd/sync/messagesFromServerQueue.d.ts +8 -0
- package/dist/umd/sync/modifyLocalObjectsWithNewUserId.d.ts +4 -0
- package/dist/umd/sync/myId.d.ts +1 -0
- package/dist/umd/sync/numUnsyncedMutations.d.ts +2 -0
- package/dist/umd/sync/old_startSyncingClientChanges.d.ts +39 -0
- package/dist/umd/sync/performGuardedJob.d.ts +2 -0
- package/dist/umd/sync/ratelimit.d.ts +3 -0
- package/dist/umd/sync/registerSyncEvent.d.ts +3 -0
- package/dist/umd/sync/sync.d.ts +15 -0
- package/dist/umd/sync/syncIfPossible.d.ts +5 -0
- package/dist/umd/sync/syncWithServer.d.ts +6 -0
- package/dist/umd/sync/triggerSync.d.ts +2 -0
- package/dist/umd/sync/updateBaseRevs.d.ts +5 -0
- package/dist/umd/types/DXCAlert.d.ts +25 -0
- package/dist/umd/types/DXCInputField.d.ts +11 -0
- package/dist/umd/types/DXCUserInteraction.d.ts +93 -0
- package/dist/umd/types/NewIdOptions.d.ts +3 -0
- package/dist/umd/types/SWMessageEvent.d.ts +3 -0
- package/dist/umd/types/SWSyncEvent.d.ts +4 -0
- package/dist/umd/types/SyncState.d.ts +9 -0
- package/dist/umd/types/TXExpandos.d.ts +11 -0
- package/dist/umd/updateSchemaFromOptions.d.ts +3 -0
- package/dist/umd/userIsActive.d.ts +7 -0
- package/dist/umd/verifyConfig.d.ts +2 -0
- package/dist/umd/verifySchema.d.ts +2 -0
- package/dist/umd/yjs/YDexieCloudSyncState.d.ts +3 -0
- package/dist/umd/yjs/YTable.d.ts +3 -0
- package/dist/umd/yjs/applyYMessages.d.ts +9 -0
- package/dist/umd/yjs/awareness.d.ts +3 -0
- package/dist/umd/yjs/createYClientUpdateObservable.d.ts +4 -0
- package/dist/umd/yjs/createYHandler.d.ts +2 -0
- package/dist/umd/yjs/downloadYDocsFromServer.d.ts +3 -0
- package/dist/umd/yjs/getUpdatesTable.d.ts +3 -0
- package/dist/umd/yjs/listUpdatesSince.d.ts +3 -0
- package/dist/umd/yjs/listYClientMessagesAndStateVector.d.ts +26 -0
- package/dist/umd/yjs/reopenDocSignal.d.ts +10 -0
- package/dist/umd/yjs/updateYSyncStates.d.ts +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Dexie from "dexie";
|
|
2
|
+
import "../extend-dexie-interface";
|
|
3
|
+
import { h, Component } from "preact";
|
|
4
|
+
import { Subscription } from "rxjs";
|
|
5
|
+
import { DXCUserInteraction } from "../types/DXCUserInteraction";
|
|
6
|
+
export interface Props {
|
|
7
|
+
db: Dexie;
|
|
8
|
+
}
|
|
9
|
+
interface State {
|
|
10
|
+
userInteraction: DXCUserInteraction | undefined;
|
|
11
|
+
}
|
|
12
|
+
export default class LoginGui extends Component<Props, State> {
|
|
13
|
+
subscription?: Subscription;
|
|
14
|
+
observer: (userInteraction: DXCUserInteraction | undefined) => void;
|
|
15
|
+
constructor(props: Props);
|
|
16
|
+
componentDidMount(): void;
|
|
17
|
+
componentWillUnmount(): void;
|
|
18
|
+
render(props: Props, { userInteraction }: State): h.JSX.Element | null;
|
|
19
|
+
}
|
|
20
|
+
export declare function setupDefaultGUI(db: Dexie): {
|
|
21
|
+
unsubscribe(): void;
|
|
22
|
+
readonly closed: boolean;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* ==========================================================================
|
|
10
10
|
*
|
|
11
|
-
* Version 4.4.
|
|
11
|
+
* Version 4.4.2, Thu Mar 19 2026
|
|
12
12
|
*
|
|
13
13
|
* https://dexie.org
|
|
14
14
|
*
|
|
@@ -2665,10 +2665,48 @@
|
|
|
2665
2665
|
obj._bt === undefined // Not a raw BlobRef
|
|
2666
2666
|
);
|
|
2667
2667
|
}
|
|
2668
|
+
/**
|
|
2669
|
+
* Recursively check if an object contains any BlobRefs
|
|
2670
|
+
*/
|
|
2671
|
+
function hasBlobRefs(obj, visited = new WeakSet()) {
|
|
2672
|
+
if (obj === null || obj === undefined) {
|
|
2673
|
+
return false;
|
|
2674
|
+
}
|
|
2675
|
+
if (isBlobRef(obj)) {
|
|
2676
|
+
return true;
|
|
2677
|
+
}
|
|
2678
|
+
if (typeof obj !== 'object') {
|
|
2679
|
+
return false;
|
|
2680
|
+
}
|
|
2681
|
+
// Avoid circular references - check BEFORE processing
|
|
2682
|
+
if (visited.has(obj)) {
|
|
2683
|
+
return false;
|
|
2684
|
+
}
|
|
2685
|
+
visited.add(obj);
|
|
2686
|
+
// Skip special objects that can't contain BlobRefs
|
|
2687
|
+
if (obj instanceof Date || obj instanceof RegExp || obj instanceof Blob) {
|
|
2688
|
+
return false;
|
|
2689
|
+
}
|
|
2690
|
+
if (obj instanceof ArrayBuffer || ArrayBuffer.isView(obj)) {
|
|
2691
|
+
return false;
|
|
2692
|
+
}
|
|
2693
|
+
if (Array.isArray(obj)) {
|
|
2694
|
+
return obj.some(item => hasBlobRefs(item, visited));
|
|
2695
|
+
}
|
|
2696
|
+
// Only traverse POJOs
|
|
2697
|
+
if (obj.constructor === Object) {
|
|
2698
|
+
return Object.values(obj).some(value => hasBlobRefs(value, visited));
|
|
2699
|
+
}
|
|
2700
|
+
return false;
|
|
2701
|
+
}
|
|
2668
2702
|
/**
|
|
2669
2703
|
* Convert downloaded Uint8Array to the original type specified in BlobRef
|
|
2670
2704
|
*/
|
|
2671
2705
|
function convertToOriginalType(data, ref) {
|
|
2706
|
+
// String type: decode UTF-8 back to string
|
|
2707
|
+
if (ref._bt === 'string') {
|
|
2708
|
+
return new TextDecoder().decode(data);
|
|
2709
|
+
}
|
|
2672
2710
|
// Get the underlying ArrayBuffer (handle shared buffer case)
|
|
2673
2711
|
const buffer = data.buffer.byteLength === data.byteLength
|
|
2674
2712
|
? data.buffer
|
|
@@ -4841,6 +4879,19 @@
|
|
|
4841
4879
|
});
|
|
4842
4880
|
}
|
|
4843
4881
|
|
|
4882
|
+
/**
|
|
4883
|
+
* If the incoming value contains BlobRefs (e.g. offloaded strings or binaries),
|
|
4884
|
+
* mark it with _hasBlobRefs = 1 so the blobResolveMiddleware will resolve them
|
|
4885
|
+
* on the next read.
|
|
4886
|
+
*/
|
|
4887
|
+
function markIfHasBlobRefs(obj) {
|
|
4888
|
+
if (obj !== null &&
|
|
4889
|
+
typeof obj === 'object' &&
|
|
4890
|
+
obj.constructor === Object &&
|
|
4891
|
+
hasBlobRefs(obj)) {
|
|
4892
|
+
obj._hasBlobRefs = 1;
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4844
4895
|
function applyServerChanges(changes, db) {
|
|
4845
4896
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4846
4897
|
console.debug('Applying server changes', changes, Dexie.currentTransaction);
|
|
@@ -4876,6 +4927,7 @@
|
|
|
4876
4927
|
const keys = mut.keys.map(keyDecoder);
|
|
4877
4928
|
switch (mut.type) {
|
|
4878
4929
|
case 'insert':
|
|
4930
|
+
mut.values.forEach(markIfHasBlobRefs);
|
|
4879
4931
|
if (primaryKey.outbound) {
|
|
4880
4932
|
yield table.bulkAdd(mut.values, keys);
|
|
4881
4933
|
}
|
|
@@ -4888,6 +4940,7 @@
|
|
|
4888
4940
|
}
|
|
4889
4941
|
break;
|
|
4890
4942
|
case 'upsert':
|
|
4943
|
+
mut.values.forEach(markIfHasBlobRefs);
|
|
4891
4944
|
if (primaryKey.outbound) {
|
|
4892
4945
|
yield table.bulkPut(mut.values, keys);
|
|
4893
4946
|
}
|
|
@@ -14306,7 +14359,7 @@
|
|
|
14306
14359
|
*
|
|
14307
14360
|
* ==========================================================================
|
|
14308
14361
|
*
|
|
14309
|
-
* Version 4.4.0,
|
|
14362
|
+
* Version 4.4.0, Thu Mar 19 2026
|
|
14310
14363
|
*
|
|
14311
14364
|
* https://dexie.org
|
|
14312
14365
|
*
|
|
@@ -14811,6 +14864,8 @@
|
|
|
14811
14864
|
*/
|
|
14812
14865
|
// Blobs >= 4KB are offloaded to blob storage
|
|
14813
14866
|
const BLOB_OFFLOAD_THRESHOLD = 4096;
|
|
14867
|
+
// Default max string length before offloading (32KB characters)
|
|
14868
|
+
const DEFAULT_MAX_STRING_LENGTH = 32768;
|
|
14814
14869
|
// Cache: once we know the server doesn't support blob storage, skip future uploads.
|
|
14815
14870
|
// Maps databaseUrl → boolean (true = supported, false = not supported).
|
|
14816
14871
|
const blobEndpointSupported = new Map();
|
|
@@ -14951,10 +15006,10 @@
|
|
|
14951
15006
|
);
|
|
14952
15007
|
});
|
|
14953
15008
|
}
|
|
14954
|
-
function offloadBlobsAndMarkDirty(
|
|
14955
|
-
return __awaiter(this,
|
|
15009
|
+
function offloadBlobsAndMarkDirty(obj_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
15010
|
+
return __awaiter(this, arguments, void 0, function* (obj, databaseUrl, getCachedAccessToken, maxStringLength = DEFAULT_MAX_STRING_LENGTH) {
|
|
14956
15011
|
const dirtyFlag = { dirty: false };
|
|
14957
|
-
const result = yield offloadBlobs(obj, databaseUrl, getCachedAccessToken, dirtyFlag);
|
|
15012
|
+
const result = yield offloadBlobs(obj, databaseUrl, getCachedAccessToken, maxStringLength, dirtyFlag);
|
|
14958
15013
|
// Mark the object as dirty for sync if any blobs were offloaded
|
|
14959
15014
|
if (dirtyFlag.dirty && typeof result === 'object' && result !== null && result.constructor === Object) {
|
|
14960
15015
|
result._hasBlobRefs = 1;
|
|
@@ -14967,10 +15022,26 @@
|
|
|
14967
15022
|
* Returns a new object with blobs replaced by BlobRefs
|
|
14968
15023
|
*/
|
|
14969
15024
|
function offloadBlobs(obj_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
14970
|
-
return __awaiter(this, arguments, void 0, function* (obj, databaseUrl, getCachedAccessToken, dirtyFlag = { dirty: false }, visited = new WeakSet()) {
|
|
15025
|
+
return __awaiter(this, arguments, void 0, function* (obj, databaseUrl, getCachedAccessToken, maxStringLength = DEFAULT_MAX_STRING_LENGTH, dirtyFlag = { dirty: false }, visited = new WeakSet()) {
|
|
14971
15026
|
if (obj === null || obj === undefined) {
|
|
14972
15027
|
return obj;
|
|
14973
15028
|
}
|
|
15029
|
+
// Check if this is a long string that should be offloaded
|
|
15030
|
+
if (typeof obj === 'string' && obj.length > maxStringLength && maxStringLength !== Infinity) {
|
|
15031
|
+
if (blobEndpointSupported.get(databaseUrl) === false) {
|
|
15032
|
+
return obj;
|
|
15033
|
+
}
|
|
15034
|
+
const blob = new Blob([obj], { type: 'text/plain;charset=utf-8' });
|
|
15035
|
+
const blobRef = yield uploadBlob(databaseUrl, getCachedAccessToken, blob);
|
|
15036
|
+
if (blobRef === null) {
|
|
15037
|
+
blobEndpointSupported.set(databaseUrl, false);
|
|
15038
|
+
return obj;
|
|
15039
|
+
}
|
|
15040
|
+
blobEndpointSupported.set(databaseUrl, true);
|
|
15041
|
+
dirtyFlag.dirty = true;
|
|
15042
|
+
// Mark as string type so it's resolved back to string, not Blob
|
|
15043
|
+
return Object.assign(Object.assign({}, blobRef), { _bt: 'string' });
|
|
15044
|
+
}
|
|
14974
15045
|
// Check if this is a blob that should be offloaded
|
|
14975
15046
|
if (shouldOffloadBlob(obj)) {
|
|
14976
15047
|
if (blobEndpointSupported.get(databaseUrl) === false) {
|
|
@@ -14999,7 +15070,7 @@
|
|
|
14999
15070
|
if (Array.isArray(obj)) {
|
|
15000
15071
|
const result = [];
|
|
15001
15072
|
for (const item of obj) {
|
|
15002
|
-
result.push(yield offloadBlobs(item, databaseUrl, getCachedAccessToken, dirtyFlag, visited));
|
|
15073
|
+
result.push(yield offloadBlobs(item, databaseUrl, getCachedAccessToken, maxStringLength, dirtyFlag, visited));
|
|
15003
15074
|
}
|
|
15004
15075
|
return result;
|
|
15005
15076
|
}
|
|
@@ -15011,7 +15082,7 @@
|
|
|
15011
15082
|
}
|
|
15012
15083
|
const result = {};
|
|
15013
15084
|
for (const [key, value] of Object.entries(obj)) {
|
|
15014
|
-
result[key] = yield offloadBlobs(value, databaseUrl, getCachedAccessToken, dirtyFlag, visited);
|
|
15085
|
+
result[key] = yield offloadBlobs(value, databaseUrl, getCachedAccessToken, maxStringLength, dirtyFlag, visited);
|
|
15015
15086
|
}
|
|
15016
15087
|
return result;
|
|
15017
15088
|
});
|
|
@@ -15020,13 +15091,13 @@
|
|
|
15020
15091
|
* Process a DBOperationsSet and offload any large blobs
|
|
15021
15092
|
* Returns a new DBOperationsSet with blobs replaced by BlobRefs
|
|
15022
15093
|
*/
|
|
15023
|
-
function offloadBlobsInOperations(
|
|
15024
|
-
return __awaiter(this,
|
|
15094
|
+
function offloadBlobsInOperations(operations_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
15095
|
+
return __awaiter(this, arguments, void 0, function* (operations, databaseUrl, getCachedAccessToken, maxStringLength = DEFAULT_MAX_STRING_LENGTH) {
|
|
15025
15096
|
const result = [];
|
|
15026
15097
|
for (const tableOps of operations) {
|
|
15027
15098
|
const processedMuts = [];
|
|
15028
15099
|
for (const mut of tableOps.muts) {
|
|
15029
|
-
const processedMut = yield offloadBlobsInOperation(mut, databaseUrl, getCachedAccessToken);
|
|
15100
|
+
const processedMut = yield offloadBlobsInOperation(mut, databaseUrl, getCachedAccessToken, maxStringLength);
|
|
15030
15101
|
processedMuts.push(processedMut);
|
|
15031
15102
|
}
|
|
15032
15103
|
result.push({
|
|
@@ -15037,20 +15108,20 @@
|
|
|
15037
15108
|
return result;
|
|
15038
15109
|
});
|
|
15039
15110
|
}
|
|
15040
|
-
function offloadBlobsInOperation(
|
|
15041
|
-
return __awaiter(this,
|
|
15111
|
+
function offloadBlobsInOperation(op_1, databaseUrl_1, getCachedAccessToken_1) {
|
|
15112
|
+
return __awaiter(this, arguments, void 0, function* (op, databaseUrl, getCachedAccessToken, maxStringLength = DEFAULT_MAX_STRING_LENGTH) {
|
|
15042
15113
|
switch (op.type) {
|
|
15043
15114
|
case 'insert':
|
|
15044
15115
|
case 'upsert': {
|
|
15045
|
-
const processedValues = yield Promise.all(op.values.map(value => offloadBlobsAndMarkDirty(value, databaseUrl, getCachedAccessToken)));
|
|
15116
|
+
const processedValues = yield Promise.all(op.values.map(value => offloadBlobsAndMarkDirty(value, databaseUrl, getCachedAccessToken, maxStringLength)));
|
|
15046
15117
|
return Object.assign(Object.assign({}, op), { values: processedValues });
|
|
15047
15118
|
}
|
|
15048
15119
|
case 'update': {
|
|
15049
|
-
const processedChangeSpecs = yield Promise.all(op.changeSpecs.map(spec => offloadBlobsAndMarkDirty(spec, databaseUrl, getCachedAccessToken)));
|
|
15120
|
+
const processedChangeSpecs = yield Promise.all(op.changeSpecs.map(spec => offloadBlobsAndMarkDirty(spec, databaseUrl, getCachedAccessToken, maxStringLength)));
|
|
15050
15121
|
return Object.assign(Object.assign({}, op), { changeSpecs: processedChangeSpecs });
|
|
15051
15122
|
}
|
|
15052
15123
|
case 'modify': {
|
|
15053
|
-
const processedChangeSpec = yield offloadBlobsAndMarkDirty(op.changeSpec, databaseUrl, getCachedAccessToken);
|
|
15124
|
+
const processedChangeSpec = yield offloadBlobsAndMarkDirty(op.changeSpec, databaseUrl, getCachedAccessToken, maxStringLength);
|
|
15054
15125
|
return Object.assign(Object.assign({}, op), { changeSpec: processedChangeSpec });
|
|
15055
15126
|
}
|
|
15056
15127
|
case 'delete':
|
|
@@ -15065,33 +15136,37 @@
|
|
|
15065
15136
|
* Check if there are any large blobs in the operations that need offloading
|
|
15066
15137
|
* This is a quick check to avoid unnecessary processing
|
|
15067
15138
|
*/
|
|
15068
|
-
function hasLargeBlobsInOperations(operations) {
|
|
15139
|
+
function hasLargeBlobsInOperations(operations, maxStringLength = DEFAULT_MAX_STRING_LENGTH) {
|
|
15069
15140
|
for (const tableOps of operations) {
|
|
15070
15141
|
for (const mut of tableOps.muts) {
|
|
15071
|
-
if (hasLargeBlobsInOperation(mut)) {
|
|
15142
|
+
if (hasLargeBlobsInOperation(mut, maxStringLength)) {
|
|
15072
15143
|
return true;
|
|
15073
15144
|
}
|
|
15074
15145
|
}
|
|
15075
15146
|
}
|
|
15076
15147
|
return false;
|
|
15077
15148
|
}
|
|
15078
|
-
function hasLargeBlobsInOperation(op) {
|
|
15149
|
+
function hasLargeBlobsInOperation(op, maxStringLength) {
|
|
15079
15150
|
switch (op.type) {
|
|
15080
15151
|
case 'insert':
|
|
15081
15152
|
case 'upsert':
|
|
15082
|
-
return op.values.some(value => hasLargeBlobs(value));
|
|
15153
|
+
return op.values.some(value => hasLargeBlobs(value, maxStringLength));
|
|
15083
15154
|
case 'update':
|
|
15084
|
-
return op.changeSpecs.some(spec => hasLargeBlobs(spec));
|
|
15155
|
+
return op.changeSpecs.some(spec => hasLargeBlobs(spec, maxStringLength));
|
|
15085
15156
|
case 'modify':
|
|
15086
|
-
return hasLargeBlobs(op.changeSpec);
|
|
15157
|
+
return hasLargeBlobs(op.changeSpec, maxStringLength);
|
|
15087
15158
|
default:
|
|
15088
15159
|
return false;
|
|
15089
15160
|
}
|
|
15090
15161
|
}
|
|
15091
|
-
function hasLargeBlobs(obj, visited = new WeakSet()) {
|
|
15162
|
+
function hasLargeBlobs(obj, maxStringLength, visited = new WeakSet()) {
|
|
15092
15163
|
if (obj === null || obj === undefined) {
|
|
15093
15164
|
return false;
|
|
15094
15165
|
}
|
|
15166
|
+
// Check long strings
|
|
15167
|
+
if (typeof obj === 'string' && obj.length > maxStringLength && maxStringLength !== Infinity) {
|
|
15168
|
+
return true;
|
|
15169
|
+
}
|
|
15095
15170
|
if (shouldOffloadBlob(obj)) {
|
|
15096
15171
|
return true;
|
|
15097
15172
|
}
|
|
@@ -15104,13 +15179,13 @@
|
|
|
15104
15179
|
}
|
|
15105
15180
|
visited.add(obj);
|
|
15106
15181
|
if (Array.isArray(obj)) {
|
|
15107
|
-
return obj.some(item => hasLargeBlobs(item, visited));
|
|
15182
|
+
return obj.some(item => hasLargeBlobs(item, maxStringLength, visited));
|
|
15108
15183
|
}
|
|
15109
15184
|
// Traverse plain objects (POJO-like) - use duck typing since IndexedDB
|
|
15110
15185
|
// may return objects where constructor !== Object
|
|
15111
15186
|
const proto = Object.getPrototypeOf(obj);
|
|
15112
15187
|
if (proto === Object.prototype || proto === null) {
|
|
15113
|
-
return Object.values(obj).some(value => hasLargeBlobs(value, visited));
|
|
15188
|
+
return Object.values(obj).some(value => hasLargeBlobs(value, maxStringLength, visited));
|
|
15114
15189
|
}
|
|
15115
15190
|
return false;
|
|
15116
15191
|
}
|
|
@@ -15371,7 +15446,7 @@
|
|
|
15371
15446
|
return __awaiter(this, arguments, void 0, function* (db, options, schema, { isInitialSync, cancelToken, justCheckIfNeeded, purpose } = {
|
|
15372
15447
|
isInitialSync: false,
|
|
15373
15448
|
}) {
|
|
15374
|
-
var _a;
|
|
15449
|
+
var _a, _b, _c;
|
|
15375
15450
|
if (!justCheckIfNeeded) {
|
|
15376
15451
|
console.debug('SYNC STARTED', { isInitialSync, purpose });
|
|
15377
15452
|
}
|
|
@@ -15445,9 +15520,10 @@
|
|
|
15445
15520
|
// Offload large blobs to blob storage before sync
|
|
15446
15521
|
//
|
|
15447
15522
|
let processedChangeSet = clientChangeSet;
|
|
15448
|
-
const
|
|
15523
|
+
const maxStringLength = (_c = (_b = db.cloud.options) === null || _b === void 0 ? void 0 : _b.maxStringLength) !== null && _c !== void 0 ? _c : 32768;
|
|
15524
|
+
const hasLargeBlobs = hasLargeBlobsInOperations(clientChangeSet, maxStringLength);
|
|
15449
15525
|
if (hasLargeBlobs) {
|
|
15450
|
-
processedChangeSet = yield offloadBlobsInOperations(clientChangeSet, databaseUrl, () => loadCachedAccessToken(db));
|
|
15526
|
+
processedChangeSet = yield offloadBlobsInOperations(clientChangeSet, databaseUrl, () => loadCachedAccessToken(db), maxStringLength);
|
|
15451
15527
|
}
|
|
15452
15528
|
//
|
|
15453
15529
|
// Push changes to server
|
|
@@ -15753,13 +15829,13 @@
|
|
|
15753
15829
|
//triggerSync(db, 'pull');
|
|
15754
15830
|
yield db.cloud.sync({ purpose: 'pull', wait: true });
|
|
15755
15831
|
break;
|
|
15756
|
-
case 'changes':
|
|
15832
|
+
case 'changes': {
|
|
15757
15833
|
console.debug('changes');
|
|
15758
15834
|
if (((_f = db.cloud.syncState.value) === null || _f === void 0 ? void 0 : _f.phase) === 'error') {
|
|
15759
15835
|
triggerSync(db, 'pull');
|
|
15760
15836
|
break;
|
|
15761
15837
|
}
|
|
15762
|
-
yield db.transaction('rw', db.dx.tables, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
15838
|
+
const didApplyChanges = yield db.transaction('rw', db.dx.tables, (tx) => __awaiter(this, void 0, void 0, function* () {
|
|
15763
15839
|
// @ts-ignore
|
|
15764
15840
|
tx.idbtrans.disableChangeTracking = true;
|
|
15765
15841
|
// @ts-ignore
|
|
@@ -15776,7 +15852,7 @@
|
|
|
15776
15852
|
schema,
|
|
15777
15853
|
currentUser,
|
|
15778
15854
|
});
|
|
15779
|
-
return; // Initial sync must have taken place - otherwise, ignore this.
|
|
15855
|
+
return false; // Initial sync must have taken place - otherwise, ignore this.
|
|
15780
15856
|
}
|
|
15781
15857
|
// Verify again in ACID tx that we're on same server revision.
|
|
15782
15858
|
if (msg.baseRev !== syncState.serverRevision) {
|
|
@@ -15797,7 +15873,7 @@
|
|
|
15797
15873
|
// If we don't do a sync request now, we could stuck in an endless loop.
|
|
15798
15874
|
triggerSync(db, 'pull');
|
|
15799
15875
|
}
|
|
15800
|
-
return; // Ignore message
|
|
15876
|
+
return false; // Ignore message
|
|
15801
15877
|
}
|
|
15802
15878
|
// Verify also that the message is based on the exact same set of realms
|
|
15803
15879
|
const ourRealmSetHash = yield Dexie.waitFor(
|
|
@@ -15809,7 +15885,7 @@
|
|
|
15809
15885
|
triggerSync(db, 'pull');
|
|
15810
15886
|
// The message isn't based on the same realms.
|
|
15811
15887
|
// Trigger a sync instead to resolve all things up.
|
|
15812
|
-
return;
|
|
15888
|
+
return false;
|
|
15813
15889
|
}
|
|
15814
15890
|
// Get clientChanges
|
|
15815
15891
|
let clientChanges = [];
|
|
@@ -15839,9 +15915,17 @@
|
|
|
15839
15915
|
//
|
|
15840
15916
|
console.debug('Updating syncState', syncState);
|
|
15841
15917
|
yield db.$syncState.put(syncState, 'syncState');
|
|
15918
|
+
return true;
|
|
15842
15919
|
}));
|
|
15843
15920
|
console.debug('msg queue: done with rw transaction');
|
|
15921
|
+
// Trigger eager blob download for any BlobRefs received via WebSocket.
|
|
15922
|
+
// This mirrors the behavior after normal HTTP sync (syncCompleteEvent).
|
|
15923
|
+
// Only emit if changes were actually applied (not on early returns).
|
|
15924
|
+
if (didApplyChanges && msg.changes.length > 0) {
|
|
15925
|
+
db.syncCompleteEvent.next();
|
|
15926
|
+
}
|
|
15844
15927
|
break;
|
|
15928
|
+
}
|
|
15845
15929
|
}
|
|
15846
15930
|
}
|
|
15847
15931
|
catch (error) {
|
|
@@ -16812,7 +16896,7 @@
|
|
|
16812
16896
|
return {
|
|
16813
16897
|
stack: 'dbcore',
|
|
16814
16898
|
name: 'blobResolve',
|
|
16815
|
-
level:
|
|
16899
|
+
level: 2, // Run above cache (0) and other middlewares (1) to resolve BlobRefs from cached data
|
|
16816
16900
|
create(downlevelDatabase) {
|
|
16817
16901
|
// Create a single queue instance for this database
|
|
16818
16902
|
const blobSavingQueue = new BlobSavingQueue(db);
|
|
@@ -19419,7 +19503,7 @@
|
|
|
19419
19503
|
const downloading$ = createDownloadingState();
|
|
19420
19504
|
dexie.cloud = {
|
|
19421
19505
|
// @ts-ignore
|
|
19422
|
-
version: "4.4.
|
|
19506
|
+
version: "4.4.2",
|
|
19423
19507
|
options: Object.assign({}, DEFAULT_OPTIONS),
|
|
19424
19508
|
schema: null,
|
|
19425
19509
|
get currentUserId() {
|
|
@@ -19447,6 +19531,19 @@
|
|
|
19447
19531
|
invites: getInvitesObservable(dexie),
|
|
19448
19532
|
roles: getGlobalRolesObservable(dexie),
|
|
19449
19533
|
configure(options) {
|
|
19534
|
+
// Validate maxStringLength — Infinity disables offloading, otherwise must be
|
|
19535
|
+
// a finite number between 100 and the server limit (32768).
|
|
19536
|
+
// Minimum 100 prevents accidental offloading of primary keys and short strings
|
|
19537
|
+
// that would break sync.
|
|
19538
|
+
const MIN_STRING_LENGTH = 100;
|
|
19539
|
+
const MAX_SERVER_STRING_LENGTH = 32768;
|
|
19540
|
+
if (options.maxStringLength !== undefined &&
|
|
19541
|
+
options.maxStringLength !== Infinity &&
|
|
19542
|
+
(!Number.isFinite(options.maxStringLength) ||
|
|
19543
|
+
options.maxStringLength < MIN_STRING_LENGTH ||
|
|
19544
|
+
options.maxStringLength > MAX_SERVER_STRING_LENGTH)) {
|
|
19545
|
+
throw new Error(`maxStringLength must be Infinity or a finite number in [${MIN_STRING_LENGTH}, ${MAX_SERVER_STRING_LENGTH}]. Got: ${options.maxStringLength}`);
|
|
19546
|
+
}
|
|
19450
19547
|
options = dexie.cloud.options = Object.assign(Object.assign({}, dexie.cloud.options), options);
|
|
19451
19548
|
configuredProgramatically = true;
|
|
19452
19549
|
if (options.databaseUrl && options.nameSuffix) {
|
|
@@ -19833,7 +19930,7 @@
|
|
|
19833
19930
|
}
|
|
19834
19931
|
}
|
|
19835
19932
|
// @ts-ignore
|
|
19836
|
-
dexieCloud.version = "4.4.
|
|
19933
|
+
dexieCloud.version = "4.4.2";
|
|
19837
19934
|
Dexie.Cloud = dexieCloud;
|
|
19838
19935
|
|
|
19839
19936
|
exports.default = dexieCloud;
|
|
Binary file
|