|
1 | 1 | import AsyncStorage from '@react-native-async-storage/async-storage'; |
2 | 2 | import { Platform } from 'react-native'; |
3 | 3 | import Constants from 'expo-constants'; |
4 | | -import { AppData, SYNC_ENCRYPTION_LOG_EVENTS, buildSyncEncryptionActivationExtra, buildSyncEncryptionErrorExtra, buildSyncEncryptionRemoteReadExtra, buildSyncEncryptionStateExtra, type SyncEncryptionState, type SyncEncryptionStateDecision, acquireSyncRemoteMutationFence, clearIdleSyncCycleSnapshot, createDropboxSyncRemoteMutationFencePort, createSyncOrchestrator, createWebdavSyncRemoteMutationFencePort, probeWebdavSyncCompatibility, runSerializedSyncDocumentOperation, runSharedSyncCycle, useTaskStore, webdavGetSyncDocument, webdavHeadFile, webdavPutSyncDocument, syncEncryptedArtifactName, markRemoteEncryptionDiscovered, markRemotePlaintextDiscovered, SyncEncryptionRemoteConflictError, SyncEncryptionRemotePlaintextError, SyncEncryptionRemoteVersionUnavailableError, SyncEncryptionTerminalError, SyncEncryptionTransitionIncompleteError, SyncFileLockUnavailableError, SyncRemoteWriteConflict, type SyncKeyMaterial, cloudGetJson, cloudHeadJson, cloudPutJson, flushPendingSave, performSyncCycle, withRetry, isRetryableError, isRetryableWebdavReadError, isWebdavInvalidJsonError, normalizeStrongWebdavEtag, normalizeWebdavUrl, normalizeCloudUrl, createSyncBackendIO, buildFastSyncScope, hasPendingSyncSideEffects, injectExternalCalendars as injectExternalCalendarsForSync, persistExternalCalendars as persistExternalCalendarsForSync, getInMemoryAppDataSnapshot, createAbortableFetch, normalizeCloudProvider as normalizeCoreCloudProvider, isDropboxUnauthorizedError, parseFastSyncState, serializeFastSyncState, summarizeTaskLifecycleCounts, decodeUriSafe, buildSyncPayloadTraceExtra, isSyncPayloadTraceEnabled, SYNC_TRACE_EVENT_MESSAGES, SYNC_FILE_NAME, SYNC_REMOTE_MUTATION_REQUEST_HORIZON_MS, CLOUD_PROVIDER_DROPBOX, CLOUD_PROVIDER_SELF_HOSTED, type Attachment, type CloudProvider, type FastSyncState, type SyncBackendContext, type SyncBackendIO, type SyncRunDiagnosticEvent, type SyncRunNotifier, type SyncRunPlatformHooks, type SyncRunResult, type SyncRunStorage, type SyncTransport } from '@mindwtr/core'; |
| 4 | +import { AppData, SYNC_ENCRYPTION_LOG_EVENTS, buildSyncEncryptionActivationExtra, buildSyncEncryptionErrorExtra, buildSyncEncryptionRemoteReadExtra, buildSyncEncryptionStateExtra, type SyncEncryptionState, type SyncEncryptionStateDecision, acquireSyncRemoteMutationFence, clearIdleSyncCycleSnapshot, createDropboxSyncRemoteMutationFencePort, createSyncOrchestrator, createWebdavSyncRemoteMutationFencePort, webdavMutationFenceUrl, probeWebdavSyncCompatibility, runSerializedSyncDocumentOperation, runSharedSyncCycle, useTaskStore, webdavGetSyncDocument, webdavHeadFile, webdavPutSyncDocument, syncEncryptedArtifactName, markRemoteEncryptionDiscovered, markRemotePlaintextDiscovered, SyncEncryptionRemoteConflictError, SyncEncryptionRemotePlaintextError, SyncEncryptionRemoteVersionUnavailableError, SyncEncryptionTerminalError, SyncEncryptionTransitionIncompleteError, SyncFileLockUnavailableError, SyncRemoteWriteConflict, type SyncKeyMaterial, cloudGetJson, cloudHeadJson, cloudPutJson, flushPendingSave, performSyncCycle, withRetry, isRetryableError, isRetryableWebdavReadError, isWebdavInvalidJsonError, normalizeStrongWebdavEtag, normalizeWebdavUrl, normalizeCloudUrl, createSyncBackendIO, buildFastSyncScope, hasPendingSyncSideEffects, injectExternalCalendars as injectExternalCalendarsForSync, persistExternalCalendars as persistExternalCalendarsForSync, getInMemoryAppDataSnapshot, createAbortableFetch, normalizeCloudProvider as normalizeCoreCloudProvider, isDropboxUnauthorizedError, parseFastSyncState, serializeFastSyncState, summarizeTaskLifecycleCounts, decodeUriSafe, buildSyncPayloadTraceExtra, isSyncPayloadTraceEnabled, SYNC_TRACE_EVENT_MESSAGES, SYNC_FILE_NAME, SYNC_REMOTE_MUTATION_REQUEST_HORIZON_MS, CLOUD_PROVIDER_DROPBOX, CLOUD_PROVIDER_SELF_HOSTED, type Attachment, type CloudProvider, type FastSyncState, type SyncBackendContext, type SyncBackendIO, type SyncRunDiagnosticEvent, type SyncRunNotifier, type SyncRunPlatformHooks, type SyncRunResult, type SyncRunStorage, type SyncTransport } from '@mindwtr/core'; |
5 | 5 | import { mobileStorage } from './storage-adapter'; |
6 | 6 | import { logInfo, logSyncError, logWarn, sanitizeLogMessage } from './app-log'; |
7 | 7 | import { readSyncFileVersioned, resolveSyncFileUri, writeSyncFile } from './storage-file'; |
@@ -1528,6 +1528,16 @@ class MobileSyncRun { |
1528 | 1528 | lastSyncHistory: mergedData.settings.lastSyncHistory, |
1529 | 1529 | }); |
1530 | 1530 | } |
| 1531 | + void logInfo('Sync status published to the store', { |
| 1532 | + scope: 'sync', |
| 1533 | + extra: { |
| 1534 | + releaseCheck: 'v1.2.7/sync-status-published', |
| 1535 | + backend: this.backend, |
| 1536 | + statusPublished: info.localWriteSkipped ? 'unchanged' : 'wrote-local', |
| 1537 | + lastSyncAt: String(mergedData.settings.lastSyncAt ?? 'none'), |
| 1538 | + lastSyncStatus: String(mergedData.settings.lastSyncStatus ?? 'none'), |
| 1539 | + }, |
| 1540 | + }); |
1531 | 1541 | logSyncDiagnostic('Sync diagnostic complete', this.syncDiagnosticStartedAt, { |
1532 | 1542 | backend: this.backend, |
1533 | 1543 | step: this.lastStep, |
@@ -1573,6 +1583,15 @@ class MobileSyncRun { |
1573 | 1583 | const webdavConfig = this.webdavConfig; |
1574 | 1584 | if (!webdavConfig?.url) throw new Error('WebDAV URL not configured'); |
1575 | 1585 | this.ensureWebdavSyncNotRateLimited(); |
| 1586 | + // #1132 proof: React Native's URL class ignored pathname writes and resolved the |
| 1587 | + // fence to the sync document itself. The basename below must never be data.json. |
| 1588 | + void logInfo('WebDAV sync fence artifact resolved', { |
| 1589 | + scope: 'sync', |
| 1590 | + extra: { |
| 1591 | + releaseCheck: 'v1.2.7/fence-artifact', |
| 1592 | + artifact: webdavMutationFenceUrl(webdavConfig.url).split('/').pop() ?? 'none', |
| 1593 | + }, |
| 1594 | + }); |
1576 | 1595 | try { |
1577 | 1596 | return await acquireSyncRemoteMutationFence( |
1578 | 1597 | createWebdavSyncRemoteMutationFencePort(webdavConfig.url, { |
|
0 commit comments