@vrtmrz/livesync-commonlib 0.1.0-rc.2 → 0.1.0-rc.3

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.
Files changed (32) hide show
  1. package/dist/common/configForDoc.js +6 -3
  2. package/dist/common/messages/combinedMessages.prod.d.ts +9 -0
  3. package/dist/common/messages/combinedMessages.prod.js +9 -0
  4. package/dist/common/messages/def.d.ts +3 -0
  5. package/dist/common/messagesJson/en.json +3 -0
  6. package/dist/common/models/setting.const.defaults.js +1 -0
  7. package/dist/common/models/setting.type.d.ts +4 -2
  8. package/dist/common/settingConstants.js +2 -2
  9. package/dist/interfaces/Confirm.d.ts +2 -1
  10. package/dist/replication/LiveSyncAbstractReplicator.d.ts +1 -2
  11. package/dist/replication/couchdb/LiveSyncReplicator.d.ts +0 -1
  12. package/dist/replication/couchdb/LiveSyncReplicator.js +0 -3
  13. package/dist/replication/journal/LiveSyncJournalReplicator.d.ts +0 -1
  14. package/dist/replication/journal/LiveSyncJournalReplicator.js +0 -3
  15. package/dist/replication/trystero/LiveSyncTrysteroReplicator.d.ts +1 -2
  16. package/dist/replication/trystero/LiveSyncTrysteroReplicator.js +1 -4
  17. package/dist/serviceFeatures/checkRemoteSize.d.ts +5 -3
  18. package/dist/serviceFeatures/checkRemoteSize.js +51 -11
  19. package/dist/serviceModules/Rebuilder.d.ts +0 -4
  20. package/dist/serviceModules/Rebuilder.js +2 -10
  21. package/dist/services/base/IService.d.ts +1 -5
  22. package/dist/services/base/ReplicationService.d.ts +1 -1
  23. package/dist/services/base/ReplicationService.js +5 -15
  24. package/dist/services/base/SettingService.d.ts +0 -8
  25. package/dist/services/base/SettingService.js +0 -5
  26. package/dist/services/implements/headless/HeadlessAPIService.d.ts +2 -2
  27. package/dist/services/implements/headless/HeadlessAPIService.js +1 -1
  28. package/dist/worker/bgWorker.js +1 -1
  29. package/docs/development.md +8 -0
  30. package/docs/proven-in-use.md +9 -7
  31. package/docs/releasing.md +3 -1
  32. package/package.json +1 -1
@@ -20,12 +20,12 @@ const DoctorRegulationV0_24_16 = {
20
20
  rules: {
21
21
  sendChunksBulk: {
22
22
  value: false,
23
- reason: "This is an obsolete setting and we should not enable this no more",
23
+ reason: "Automatic bulk chunk pre-send is obsolete and must remain disabled",
24
24
  level: 0 /* Must */
25
25
  },
26
26
  sendChunksBulkMaxSize: {
27
27
  value: 1,
28
- reason: "This is an obsolete setting and we should not enable this no more",
28
+ reason: "Use a conservative request size for the explicit manual chunk resend tool",
29
29
  level: 0 /* Must */
30
30
  },
31
31
  doNotUseFixedRevisionForChunks: {
@@ -263,7 +263,10 @@ async function performDoctorConsultation(env, settings, {
263
263
  }),
264
264
  options,
265
265
  {
266
- title: translate("Doctor.Dialogue.TitleFix", { current: `${++idx}`, total: `${issueItems.length}` }),
266
+ title: translate("Doctor.Dialogue.TitleFix", {
267
+ current: `${++idx}`,
268
+ total: `${issueItems.length}`
269
+ }),
267
270
  defaultAction: OPT_FIX
268
271
  }
269
272
  );
@@ -2597,6 +2597,12 @@ export declare const allMessages: {
2597
2597
  readonly ru: "Можно установить предупреждение о максимальной ёмкости базы данных.";
2598
2598
  readonly zh: "我们可以设置一个最大数据库容量警告,**以便在远程存储空间耗尽前采取行动**。\n您想启用这个功能吗?\n\n> [!MORE]-\n> - 0: 不警告存储大小。\n> 如果您在远程存储(尤其是自托管)上有足够的空间,则推荐此选项。您可以手动检查存储大小并重建。\n> - 800: 如果远程存储大小超过 800MB 则发出警告。\n> 如果您使用的是 fly.io(1GB 限制) 或 IBM Cloudant,则推荐此选项。\n> - 2000: 如果远程存储大小超过 2GB 则发出警告。\n\n如果达到限制,系统会要求我们逐步增大限制\n";
2599
2599
  };
2600
+ readonly "moduleCheckRemoteSize.noticeExceeded": {
2601
+ readonly def: "Remote storage size is ${measuredSize}, above the configured ${notifySize} notification threshold. {HERE}";
2602
+ };
2603
+ readonly "moduleCheckRemoteSize.noticeNotConfigured": {
2604
+ readonly def: "Remote storage size notifications are not configured. {HERE}";
2605
+ };
2600
2606
  readonly "moduleCheckRemoteSize.option2GB": {
2601
2607
  readonly def: "2GB (Standard)";
2602
2608
  readonly es: "2GB (Estándar)";
@@ -2667,6 +2673,9 @@ export declare const allMessages: {
2667
2673
  readonly ru: "Перестроить всё сейчас";
2668
2674
  readonly zh: "立即重建所有内容";
2669
2675
  };
2676
+ readonly "moduleCheckRemoteSize.optionReview": {
2677
+ readonly def: "Review options";
2678
+ };
2670
2679
  readonly "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": {
2671
2680
  readonly def: "Remote storage size exceeded the limit";
2672
2681
  readonly es: "El tamaño del almacenamiento remoto superó el límite";
@@ -2597,6 +2597,12 @@ const allMessages = {
2597
2597
  ru: "\u041C\u043E\u0436\u043D\u043E \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u0435 \u043E \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0439 \u0451\u043C\u043A\u043E\u0441\u0442\u0438 \u0431\u0430\u0437\u044B \u0434\u0430\u043D\u043D\u044B\u0445.",
2598
2598
  zh: "\u6211\u4EEC\u53EF\u4EE5\u8BBE\u7F6E\u4E00\u4E2A\u6700\u5927\u6570\u636E\u5E93\u5BB9\u91CF\u8B66\u544A,**\u4EE5\u4FBF\u5728\u8FDC\u7A0B\u5B58\u50A8\u7A7A\u95F4\u8017\u5C3D\u524D\u91C7\u53D6\u884C\u52A8**\u3002\n\u60A8\u60F3\u542F\u7528\u8FD9\u4E2A\u529F\u80FD\u5417?\n\n> [!MORE]-\n> - 0: \u4E0D\u8B66\u544A\u5B58\u50A8\u5927\u5C0F\u3002\n> \u5982\u679C\u60A8\u5728\u8FDC\u7A0B\u5B58\u50A8(\u5C24\u5176\u662F\u81EA\u6258\u7BA1)\u4E0A\u6709\u8DB3\u591F\u7684\u7A7A\u95F4,\u5219\u63A8\u8350\u6B64\u9009\u9879\u3002\u60A8\u53EF\u4EE5\u624B\u52A8\u68C0\u67E5\u5B58\u50A8\u5927\u5C0F\u5E76\u91CD\u5EFA\u3002\n> - 800: \u5982\u679C\u8FDC\u7A0B\u5B58\u50A8\u5927\u5C0F\u8D85\u8FC7 800MB \u5219\u53D1\u51FA\u8B66\u544A\u3002\n> \u5982\u679C\u60A8\u4F7F\u7528\u7684\u662F fly.io(1GB \u9650\u5236) \u6216 IBM Cloudant,\u5219\u63A8\u8350\u6B64\u9009\u9879\u3002\n> - 2000: \u5982\u679C\u8FDC\u7A0B\u5B58\u50A8\u5927\u5C0F\u8D85\u8FC7 2GB \u5219\u53D1\u51FA\u8B66\u544A\u3002\n\n\u5982\u679C\u8FBE\u5230\u9650\u5236,\u7CFB\u7EDF\u4F1A\u8981\u6C42\u6211\u4EEC\u9010\u6B65\u589E\u5927\u9650\u5236\n"
2599
2599
  },
2600
+ "moduleCheckRemoteSize.noticeExceeded": {
2601
+ def: "Remote storage size is ${measuredSize}, above the configured ${notifySize} notification threshold. {HERE}"
2602
+ },
2603
+ "moduleCheckRemoteSize.noticeNotConfigured": {
2604
+ def: "Remote storage size notifications are not configured. {HERE}"
2605
+ },
2600
2606
  "moduleCheckRemoteSize.option2GB": {
2601
2607
  def: "2GB (Standard)",
2602
2608
  es: "2GB (Est\xE1ndar)",
@@ -2667,6 +2673,9 @@ const allMessages = {
2667
2673
  ru: "\u041F\u0435\u0440\u0435\u0441\u0442\u0440\u043E\u0438\u0442\u044C \u0432\u0441\u0451 \u0441\u0435\u0439\u0447\u0430\u0441",
2668
2674
  zh: "\u7ACB\u5373\u91CD\u5EFA\u6240\u6709\u5185\u5BB9"
2669
2675
  },
2676
+ "moduleCheckRemoteSize.optionReview": {
2677
+ def: "Review options"
2678
+ },
2670
2679
  "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": {
2671
2680
  def: "Remote storage size exceeded the limit",
2672
2681
  es: "El tama\xF1o del almacenamiento remoto super\xF3 el l\xEDmite",
@@ -278,6 +278,8 @@ export declare const PartialMessages: {
278
278
  "moduleCheckRemoteSize.msgConfirmRebuild": string;
279
279
  "moduleCheckRemoteSize.msgDatabaseGrowing": string;
280
280
  "moduleCheckRemoteSize.msgSetDBCapacity": string;
281
+ "moduleCheckRemoteSize.noticeExceeded": string;
282
+ "moduleCheckRemoteSize.noticeNotConfigured": string;
281
283
  "moduleCheckRemoteSize.option2GB": string;
282
284
  "moduleCheckRemoteSize.option800MB": string;
283
285
  "moduleCheckRemoteSize.optionAskMeLater": string;
@@ -285,6 +287,7 @@ export declare const PartialMessages: {
285
287
  "moduleCheckRemoteSize.optionIncreaseLimit": string;
286
288
  "moduleCheckRemoteSize.optionNoWarn": string;
287
289
  "moduleCheckRemoteSize.optionRebuildAll": string;
290
+ "moduleCheckRemoteSize.optionReview": string;
288
291
  "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": string;
289
292
  "moduleCheckRemoteSize.titleDatabaseSizeNotify": string;
290
293
  "moduleInputUIObsidian.defaultTitleConfirmation": string;
@@ -277,6 +277,8 @@
277
277
  "moduleCheckRemoteSize.msgConfirmRebuild": "This may take a bit of a long time. Do you really want to rebuild everything now?",
278
278
  "moduleCheckRemoteSize.msgDatabaseGrowing": "**Your database is getting larger!** But do not worry, we can address it now. The time before running out of space on the remote storage.\n\n| Measured size | Configured size |\n| --- | --- |\n| ${estimatedSize} | ${maxSize} |\n\n> [!MORE]-\n> If you have been using it for many years, there may be unreferenced chunks - that is, garbage - accumulating in the database. Therefore, we recommend rebuilding everything. It will probably become much smaller.\n>\n> If the volume of your vault is simply increasing, it is better to rebuild everything after organizing the files. Self-hosted LiveSync does not delete the actual data even if you delete it to speed up the process. It is roughly [documented](https://github.com/vrtmrz/obsidian-livesync/blob/main/docs/tech_info.md).\n>\n> If you don't mind the increase, you can increase the notification limit by 100MB. This is the case if you are running it on your own server. However, it is better to rebuild everything from time to time.\n>\n\n> [!WARNING]\n> If you perform rebuild everything, make sure all devices are synchronised. The plug-in will merge as much as possible, though.\n",
279
279
  "moduleCheckRemoteSize.msgSetDBCapacity": "We can set a maximum database capacity warning, **to take action before running out of space on the remote storage**.\nDo you want to enable this?\n\n> [!MORE]-\n> - 0: Do not warn about storage size.\n> This is recommended if you have enough space on the remote storage especially you have self-hosted. And you can check the storage size and rebuild manually.\n> - 800: Warn if the remote storage size exceeds 800MB.\n> This is recommended if you are using fly.io with 1GB limit or IBM Cloudant.\n> - 2000: Warn if the remote storage size exceeds 2GB.\n\nIf we have reached the limit, we will be asked to enlarge the limit step by step.\n",
280
+ "moduleCheckRemoteSize.noticeExceeded": "Remote storage size is ${measuredSize}, above the configured ${notifySize} notification threshold. {HERE}",
281
+ "moduleCheckRemoteSize.noticeNotConfigured": "Remote storage size notifications are not configured. {HERE}",
280
282
  "moduleCheckRemoteSize.option2GB": "2GB (Standard)",
281
283
  "moduleCheckRemoteSize.option800MB": "800MB (Cloudant, fly.io)",
282
284
  "moduleCheckRemoteSize.optionAskMeLater": "Ask me later",
@@ -284,6 +286,7 @@
284
286
  "moduleCheckRemoteSize.optionIncreaseLimit": "increase to ${newMax}MB",
285
287
  "moduleCheckRemoteSize.optionNoWarn": "No, never warn please",
286
288
  "moduleCheckRemoteSize.optionRebuildAll": "Rebuild Everything Now",
289
+ "moduleCheckRemoteSize.optionReview": "Review options",
287
290
  "moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded": "Remote storage size exceeded the limit",
288
291
  "moduleCheckRemoteSize.titleDatabaseSizeNotify": "Setting up database size notification",
289
292
  "moduleInputUIObsidian.defaultTitleConfirmation": "Confirmation",
@@ -146,6 +146,7 @@ const SETTINGS_SCHEMA_DEFAULTS = {
146
146
  handleFilenameCaseSensitive: void 0,
147
147
  doNotUseFixedRevisionForChunks: true,
148
148
  showLongerLogInsideEditor: false,
149
+ /** @deprecated Retained for settings and Setup URI compatibility. */
149
150
  sendChunksBulk: false,
150
151
  sendChunksBulkMaxSize: 1,
151
152
  /**
@@ -668,11 +668,13 @@ interface ObsoleteRemoteDBSettings {
668
668
  */
669
669
  disableRequestURI: boolean;
670
670
  /**
671
- * Indicates whether to send data in bulk chunks.
671
+ * Retained for settings and Setup URI compatibility.
672
+ * Automatic bulk chunk pre-send is no longer supported.
673
+ * @deprecated
672
674
  */
673
675
  sendChunksBulk: boolean;
674
676
  /**
675
- * The maximum size of the bulk chunks to be sent.
677
+ * The maximum request size used by the explicit manual chunk resend tool, in MB.
676
678
  */
677
679
  sendChunksBulkMaxSize: number;
678
680
  /**
@@ -328,8 +328,8 @@ const SettingInformation = {
328
328
  desc: "If this enabled, all chunks will be stored with the revision made from its content."
329
329
  },
330
330
  sendChunksBulkMaxSize: {
331
- name: "Maximum size of chunks to send in one request",
332
- desc: "MB"
331
+ name: "Maximum request size for manually resending chunks",
332
+ desc: "MB per request"
333
333
  },
334
334
  useAdvancedMode: {
335
335
  name: "Enable advanced features"
@@ -1,3 +1,4 @@
1
+ export type ConfirmActionLayout = "auto" | "vertical";
1
2
  export interface Confirm {
2
3
  askYesNo(message: string): Promise<"yes" | "no">;
3
4
  askString(title: string, key: string, placeholder: string, isPassword?: boolean): Promise<string | false>;
@@ -20,5 +21,5 @@ export interface Confirm {
20
21
  * interactive action.
21
22
  */
22
23
  askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void, durationMs?: number): void;
23
- confirmWithMessage(title: string, contentMd: string, buttons: string[], defaultAction: (typeof buttons)[number], timeout?: number): Promise<(typeof buttons)[number] | false>;
24
+ confirmWithMessage(title: string, contentMd: string, buttons: string[], defaultAction: (typeof buttons)[number], timeout?: number, actionLayout?: ConfirmActionLayout): Promise<(typeof buttons)[number] | false>;
24
25
  }
@@ -34,7 +34,6 @@ export declare abstract class LiveSyncAbstractReplicator {
34
34
  remoteLockedAndDeviceNotAccepted: boolean;
35
35
  tweakSettingsMismatched: boolean;
36
36
  preferredTweakValue?: TweakValues;
37
- abstract get isChunkSendingSupported(): boolean;
38
37
  get database(): import("../pouchdb/LiveSyncLocalDB.js").LiveSyncLocalDB;
39
38
  get rawDatabase(): PouchDB.Database<EntryDoc>;
40
39
  get currentSettings(): import("../common/types.js").ObsidianLiveSyncSettings;
@@ -49,7 +48,7 @@ export declare abstract class LiveSyncAbstractReplicator {
49
48
  abstract openReplication(setting: RemoteDBSettings, keepAlive: boolean, showResult: boolean, ignoreCleanLock: boolean): Promise<void | boolean>;
50
49
  updateInfo: () => void;
51
50
  abstract tryConnectRemote(setting: RemoteDBSettings, showResult?: boolean): Promise<boolean>;
52
- abstract replicateAllToServer(setting: RemoteDBSettings, showingNotice?: boolean, sendChunksInBulkDisabled?: boolean): Promise<boolean>;
51
+ abstract replicateAllToServer(setting: RemoteDBSettings, showingNotice?: boolean): Promise<boolean>;
53
52
  abstract replicateAllFromServer(setting: RemoteDBSettings, showingNotice?: boolean): Promise<boolean>;
54
53
  abstract closeReplication(): void;
55
54
  abstract tryResetRemoteDatabase(setting: RemoteDBSettings): Promise<void>;
@@ -5,7 +5,6 @@ export interface LiveSyncCouchDBReplicatorEnv extends LiveSyncReplicatorEnv {
5
5
  services: ServiceHub;
6
6
  }
7
7
  export declare class LiveSyncCouchDBReplicator extends LiveSyncAbstractReplicator {
8
- get isChunkSendingSupported(): boolean;
9
8
  isMobile(): boolean;
10
9
  constructor(env: LiveSyncCouchDBReplicatorEnv);
11
10
  getInitialSyncParameters(setting: RemoteDBSettings): Promise<SyncParameters>;
@@ -85,9 +85,6 @@ async function* genReplication(s, signal) {
85
85
  }
86
86
  }
87
87
  class LiveSyncCouchDBReplicator extends LiveSyncAbstractReplicator {
88
- get isChunkSendingSupported() {
89
- return true;
90
- }
91
88
  isMobile() {
92
89
  return this.env.services.API.isMobile();
93
90
  }
@@ -7,7 +7,6 @@ import { type SimpleStore } from "../../common/utils.js";
7
7
  import type { LiveSyncJournalReplicatorEnv } from "./LiveSyncJournalReplicatorEnv.js";
8
8
  export declare class LiveSyncJournalReplicator extends LiveSyncAbstractReplicator {
9
9
  env: LiveSyncJournalReplicatorEnv;
10
- get isChunkSendingSupported(): boolean;
11
10
  get client(): JournalSyncCore;
12
11
  get simpleStore(): SimpleStore<CheckPointInfo>;
13
12
  _client: JournalSyncCore;
@@ -19,9 +19,6 @@ const currentVersionRange = {
19
19
  current: 2
20
20
  };
21
21
  class LiveSyncJournalReplicator extends LiveSyncAbstractReplicator {
22
- get isChunkSendingSupported() {
23
- return false;
24
- }
25
22
  get client() {
26
23
  return this.setupJournalSyncClient();
27
24
  }
@@ -23,7 +23,6 @@ export declare class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicat
23
23
  get openReplicationUI(): (showResult: boolean) => Promise<boolean | void>;
24
24
  get rawReplicator(): TrysteroReplicator;
25
25
  get rawHost(): P2PHost;
26
- get isChunkSendingSupported(): boolean;
27
26
  getReplicationPBKDF2Salt(_setting: RemoteDBSettings, _refresh?: boolean): Promise<Uint8Array<ArrayBuffer>>;
28
27
  terminateSync(): void;
29
28
  private _buildEnv;
@@ -70,7 +69,7 @@ export declare class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicat
70
69
  makeSureOpened(): Promise<void>;
71
70
  openReplication(_setting: RemoteDBSettings, _keepAlive: boolean, showResult: boolean, _ignoreCleanLock: boolean): Promise<void | boolean>;
72
71
  tryConnectRemote(_setting: RemoteDBSettings, _showResult?: boolean): Promise<boolean>;
73
- replicateAllToServer(_setting: RemoteDBSettings, _showingNotice?: boolean, _sendChunksInBulkDisabled?: boolean): Promise<boolean>;
72
+ replicateAllToServer(_setting: RemoteDBSettings, _showingNotice?: boolean): Promise<boolean>;
74
73
  selectPeer(settingPeerName: string, r: TrysteroReplicator, logLevel: LOG_LEVEL): Promise<string | false>;
75
74
  tryUntilSuccess<T>(func: () => Promise<T | false>, repeat: number, logLevel: LOG_LEVEL): Promise<T | false>;
76
75
  replicateAllFromServer(setting: RemoteDBSettings, showingNotice?: boolean): Promise<boolean>;
@@ -29,9 +29,6 @@ class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicator {
29
29
  get rawHost() {
30
30
  return this._p2pHost;
31
31
  }
32
- get isChunkSendingSupported() {
33
- return false;
34
- }
35
32
  getReplicationPBKDF2Salt(_setting, _refresh) {
36
33
  return Promise.resolve(new Uint8Array(32));
37
34
  }
@@ -215,7 +212,7 @@ class LiveSyncTrysteroReplicator extends LiveSyncAbstractReplicator {
215
212
  tryConnectRemote(_setting, _showResult) {
216
213
  return Promise.resolve(false);
217
214
  }
218
- replicateAllToServer(_setting, _showingNotice, _sendChunksInBulkDisabled) {
215
+ replicateAllToServer(_setting, _showingNotice) {
219
216
  return Promise.resolve(false);
220
217
  }
221
218
  async selectPeer(settingPeerName, r, logLevel) {
@@ -1,10 +1,11 @@
1
1
  import { createInstanceLogFunction, type LogFunction } from "../services/lib/logUtils.js";
2
2
  import type { NecessaryServices } from "../interfaces/ServiceModule.js";
3
+ type RemoteSizeReviewMode = "notice" | "dialogue";
3
4
  /**
4
5
  * Notify when checking remote storage size is not configured.
5
6
  * @returns true if the check is passed or user has configured the notification, false to block subsequent processes. (always true).
6
7
  */
7
- export declare function onNotifyRemoteSizeNotConfiguredFactory(host: NecessaryServices<"appLifecycle" | "API" | "setting", never>, log: ReturnType<typeof createInstanceLogFunction>): () => Promise<boolean>;
8
+ export declare function onNotifyRemoteSizeNotConfiguredFactory(host: NecessaryServices<"appLifecycle" | "API" | "setting", never>, log: ReturnType<typeof createInstanceLogFunction>, mode?: RemoteSizeReviewMode): () => Promise<boolean>;
8
9
  /**
9
10
  * Notify when the remote storage size exceed the threshold.
10
11
  * @returns true if the check is passed or user has chosen to ignore the warning, false to block subsequent processes.
@@ -12,7 +13,7 @@ export declare function onNotifyRemoteSizeNotConfiguredFactory(host: NecessarySe
12
13
  * @param log
13
14
  * @returns
14
15
  */
15
- export declare function onNotifyRemoteSizeExceedFactory(host: NecessaryServices<"API" | "setting" | "replicator", "rebuilder">, log: ReturnType<typeof createInstanceLogFunction>): () => Promise<boolean>;
16
+ export declare function onNotifyRemoteSizeExceedFactory(host: NecessaryServices<"API" | "setting" | "replicator", "rebuilder">, log: ReturnType<typeof createInstanceLogFunction>, mode?: RemoteSizeReviewMode): () => Promise<boolean>;
16
17
  /**
17
18
  * Scan the remote storage size and notify if it is not configured or exceed the threshold.
18
19
  * @param host The necessary services required for the operation.
@@ -20,9 +21,10 @@ export declare function onNotifyRemoteSizeExceedFactory(host: NecessaryServices<
20
21
  * @param resetThreshold Whether to reset the notification threshold before scanning. This is useful when you want to force the notification to show up again.
21
22
  * @returns A promise that resolves to true if all checks pass or user has configured the notification.
22
23
  */
23
- export declare function scanAllStat(host: NecessaryServices<"API" | "setting" | "replicator" | "appLifecycle", "rebuilder">, log: LogFunction, resetThreshold?: boolean): Promise<boolean>;
24
+ export declare function scanAllStat(host: NecessaryServices<"API" | "setting" | "replicator" | "appLifecycle", "rebuilder">, log: LogFunction, resetThreshold?: boolean, mode?: RemoteSizeReviewMode): Promise<boolean>;
24
25
  /**
25
26
  * Associate the remote storage size check feature with the app lifecycle events.
26
27
  * @param host
27
28
  */
28
29
  export declare function useCheckRemoteSize(host: NecessaryServices<"API" | "setting" | "replicator" | "appLifecycle", "rebuilder">): void;
30
+ export {};
@@ -2,7 +2,17 @@ import { sizeToHumanReadable } from "octagonal-wheels/number";
2
2
  import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE } from "../common/types.js";
3
3
  import { createInstanceLogFunction } from "../services/lib/logUtils.js";
4
4
  import { EVENT_REQUEST_CHECK_REMOTE_SIZE } from "../events/coreEvents.js";
5
- function onNotifyRemoteSizeNotConfiguredFactory(host, log) {
5
+ import { fireAndForget } from "../common/utils.js";
6
+ const REMOTE_SIZE_NOTICE_DURATION_MS = 5 * 60 * 1e3;
7
+ function configureReviewAnchor(anchor, label, review) {
8
+ anchor.href = "#";
9
+ anchor.textContent = label;
10
+ anchor.addEventListener("click", (event) => {
11
+ event.preventDefault();
12
+ fireAndForget(review);
13
+ });
14
+ }
15
+ function onNotifyRemoteSizeNotConfiguredFactory(host, log, mode = "notice") {
6
16
  return async () => {
7
17
  const translate = host.services.context.translate;
8
18
  log(translate("moduleCheckRemoteSize.logCheckingStorageSizes"), LOG_LEVEL_VERBOSE);
@@ -15,13 +25,25 @@ function onNotifyRemoteSizeNotConfiguredFactory(host, log) {
15
25
  const ANSWER_800 = translate("moduleCheckRemoteSize.option800MB");
16
26
  const ANSWER_2000 = translate("moduleCheckRemoteSize.option2GB");
17
27
  const ASK_ME_NEXT_TIME = translate("moduleCheckRemoteSize.optionAskMeLater");
28
+ if (mode === "notice") {
29
+ host.services.API.confirm.askInPopup(
30
+ "remote-size-not-configured",
31
+ translate("moduleCheckRemoteSize.noticeNotConfigured"),
32
+ (anchor) => configureReviewAnchor(
33
+ anchor,
34
+ translate("moduleCheckRemoteSize.optionReview"),
35
+ () => onNotifyRemoteSizeNotConfiguredFactory(host, log, "dialogue")()
36
+ ),
37
+ REMOTE_SIZE_NOTICE_DURATION_MS
38
+ );
39
+ return true;
40
+ }
18
41
  const ret = await host.services.API.confirm.askSelectStringDialogue(
19
42
  message,
20
43
  [ANSWER_0, ANSWER_800, ANSWER_2000, ASK_ME_NEXT_TIME],
21
44
  {
22
45
  defaultAction: ASK_ME_NEXT_TIME,
23
- title: translate("moduleCheckRemoteSize.titleDatabaseSizeNotify"),
24
- timeout: 40
46
+ title: translate("moduleCheckRemoteSize.titleDatabaseSizeNotify")
25
47
  }
26
48
  );
27
49
  if (ret == ANSWER_0) {
@@ -49,7 +71,7 @@ function onNotifyRemoteSizeNotConfiguredFactory(host, log) {
49
71
  return true;
50
72
  };
51
73
  }
52
- function onNotifyRemoteSizeExceedFactory(host, log) {
74
+ function onNotifyRemoteSizeExceedFactory(host, log, mode = "notice") {
53
75
  return async () => {
54
76
  const translate = host.services.context.translate;
55
77
  const settings = host.services.setting.currentSettings();
@@ -89,13 +111,28 @@ function onNotifyRemoteSizeExceedFactory(host, log) {
89
111
  });
90
112
  const ANSWER_REBUILD = translate("moduleCheckRemoteSize.optionRebuildAll");
91
113
  const ANSWER_IGNORE = translate("moduleCheckRemoteSize.optionDismiss");
114
+ if (mode === "notice") {
115
+ host.services.API.confirm.askInPopup(
116
+ "remote-size-exceeded",
117
+ translate("moduleCheckRemoteSize.noticeExceeded", {
118
+ measuredSize: sizeToHumanReadable(estimatedSize),
119
+ notifySize: sizeToHumanReadable(maxSize)
120
+ }),
121
+ (anchor) => configureReviewAnchor(
122
+ anchor,
123
+ translate("moduleCheckRemoteSize.optionReview"),
124
+ () => onNotifyRemoteSizeExceedFactory(host, log, "dialogue")()
125
+ ),
126
+ REMOTE_SIZE_NOTICE_DURATION_MS
127
+ );
128
+ return true;
129
+ }
92
130
  const ret = await host.services.API.confirm.askSelectStringDialogue(
93
131
  message,
94
132
  [ANSWER_ENLARGE_LIMIT, ANSWER_REBUILD, ANSWER_IGNORE],
95
133
  {
96
134
  defaultAction: ANSWER_IGNORE,
97
- title: translate("moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded"),
98
- timeout: 60
135
+ title: translate("moduleCheckRemoteSize.titleDatabaseSizeLimitExceeded")
99
136
  }
100
137
  );
101
138
  if (ret == ANSWER_REBUILD) {
@@ -142,7 +179,7 @@ function onNotifyRemoteSizeExceedFactory(host, log) {
142
179
  return true;
143
180
  };
144
181
  }
145
- async function scanAllStat(host, log, resetThreshold = false) {
182
+ async function scanAllStat(host, log, resetThreshold = false, mode = "notice") {
146
183
  if (resetThreshold) {
147
184
  await host.services.setting.applyPartial(
148
185
  {
@@ -151,8 +188,8 @@ async function scanAllStat(host, log, resetThreshold = false) {
151
188
  true
152
189
  );
153
190
  }
154
- const onNotifyNotConfigured = onNotifyRemoteSizeNotConfiguredFactory(host, log);
155
- const onNotifyExceed = onNotifyRemoteSizeExceedFactory(host, log);
191
+ const onNotifyNotConfigured = onNotifyRemoteSizeNotConfiguredFactory(host, log, mode);
192
+ const onNotifyExceed = onNotifyRemoteSizeExceedFactory(host, log, mode);
156
193
  return await onNotifyNotConfigured() && await onNotifyExceed();
157
194
  }
158
195
  function useCheckRemoteSize(host) {
@@ -163,10 +200,13 @@ function useCheckRemoteSize(host) {
163
200
  id: "livesync-reset-remote-size-threshold-and-check",
164
201
  name: "Reset notification threshold and check the remote database usage",
165
202
  callback: async () => {
166
- await scanAllStat(host, log, true);
203
+ await scanAllStat(host, log, true, "dialogue");
167
204
  }
168
205
  });
169
- host.services.context.events.onEvent(EVENT_REQUEST_CHECK_REMOTE_SIZE, () => scanAllStat(host, log, true));
206
+ host.services.context.events.onEvent(
207
+ EVENT_REQUEST_CHECK_REMOTE_SIZE,
208
+ () => scanAllStat(host, log, true, "dialogue")
209
+ );
170
210
  return Promise.resolve(true);
171
211
  });
172
212
  }
@@ -48,10 +48,6 @@ export declare class ServiceRebuilder extends ServiceModuleBase<ServiceRebuilder
48
48
  constructor(services: ServiceRebuilderDependencies);
49
49
  $performRebuildDB(method: "localOnly" | "remoteOnly" | "rebuildBothByThisDevice" | "localOnlyWithChunks"): Promise<void>;
50
50
  informOptionalFeatures(): Promise<void>;
51
- askUsingOptionalFeature(opt: {
52
- enableFetch?: boolean;
53
- enableOverwrite?: boolean;
54
- }): Promise<void>;
55
51
  rebuildRemote(): Promise<void>;
56
52
  private performRemoteRebuild;
57
53
  $rebuildRemote(): Promise<void>;
@@ -67,14 +67,6 @@ Please enable them from the settings screen after setup is complete.`,
67
67
  ["OK"]
68
68
  );
69
69
  }
70
- async askUsingOptionalFeature(opt) {
71
- if (await this.UI.confirm.askYesNoDialog(
72
- "Do you want to enable extra features? If you are new to Self-hosted LiveSync, try the core feature first!",
73
- { title: "Enable extra features", defaultOption: "No", timeout: 15 }
74
- ) == "yes") {
75
- await this.setting.suggestOptionalFeatures(opt);
76
- }
77
- }
78
70
  async rebuildRemote() {
79
71
  await this.replicator.runBoundedRemoteActivity(() => this.performRemoteRebuild(), {
80
72
  label: "rebuild-remote"
@@ -95,7 +87,7 @@ Please enable them from the settings screen after setup is complete.`,
95
87
  await delay(1e3);
96
88
  await this.replication.replicateAllToRemote(true);
97
89
  await delay(1e3);
98
- await this.replication.replicateAllToRemote(true, true);
90
+ await this.replication.replicateAllToRemote(true);
99
91
  }
100
92
  $rebuildRemote() {
101
93
  return this.rebuildRemote();
@@ -123,7 +115,7 @@ Please enable them from the settings screen after setup is complete.`,
123
115
  await delay(1e3);
124
116
  await this.replication.replicateAllToRemote(true);
125
117
  await delay(1e3);
126
- await this.replication.replicateAllToRemote(true, true);
118
+ await this.replication.replicateAllToRemote(true);
127
119
  }
128
120
  $rebuildEverything() {
129
121
  return this.rebuildEverything();
@@ -128,7 +128,7 @@ export interface IReplicationService {
128
128
  databaseQueueCount: ReactiveSource<number>;
129
129
  storageApplyingCount: ReactiveSource<number>;
130
130
  replicationResultCount: ReactiveSource<number>;
131
- replicateAllToRemote(showingNotice?: boolean, sendChunksInBulkDisabled?: boolean): Promise<boolean>;
131
+ replicateAllToRemote(showingNotice?: boolean): Promise<boolean>;
132
132
  replicateAllFromRemote(showingNotice?: boolean): Promise<boolean>;
133
133
  markLocked(lockByClean?: boolean): Promise<void>;
134
134
  markUnlocked(): Promise<void>;
@@ -189,10 +189,6 @@ export interface ISettingService {
189
189
  onRealiseSetting(): Promise<boolean>;
190
190
  suspendAllSync(): Promise<boolean>;
191
191
  suspendExtraSync(): Promise<boolean>;
192
- suggestOptionalFeatures(opt: {
193
- enableFetch?: boolean;
194
- enableOverwrite?: boolean;
195
- }): Promise<boolean>;
196
192
  enableOptionalFeature(mode: keyof OPTIONAL_SYNC_FEATURES): Promise<boolean>;
197
193
  clearUsedPassphrase(): void;
198
194
  decryptSettings(settings: ObsidianLiveSyncSettings): Promise<ObsidianLiveSyncSettings>;
@@ -85,7 +85,7 @@ export declare abstract class ReplicationService<T extends ServiceContext = Serv
85
85
  storageApplyingCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource<number>;
86
86
  replicationResultCount: import("octagonal-wheels/dataobject/reactive_v2").ReactiveSource<number>;
87
87
  getActiveReplicatorFor(usage: string): false | LiveSyncAbstractReplicator;
88
- replicateAllToRemote(showingNotice?: boolean, sendChunksInBulkDisabled?: boolean): Promise<boolean>;
88
+ replicateAllToRemote(showingNotice?: boolean): Promise<boolean>;
89
89
  replicateAllFromRemote(showingNotice?: boolean): Promise<boolean>;
90
90
  private _getReplicatorAndPerform;
91
91
  markLocked(lockByClean?: boolean): Promise<void>;
@@ -34,7 +34,10 @@ class ReplicationService extends ServiceBase {
34
34
  this.fileProcessing = dependencies.fileProcessingService;
35
35
  this.databaseService = dependencies.databaseService;
36
36
  this._log = createInstanceLogFunction("ReplicationService", dependencies.APIService);
37
- this._unresolvedErrorManager = new UnresolvedErrorManager(dependencies.appLifecycleService, this.context.events);
37
+ this._unresolvedErrorManager = new UnresolvedErrorManager(
38
+ dependencies.appLifecycleService,
39
+ this.context.events
40
+ );
38
41
  }
39
42
  /**
40
43
  * Process a synchronisation result document.
@@ -183,7 +186,7 @@ class ReplicationService extends ServiceBase {
183
186
  }
184
187
  return activeReplicator;
185
188
  }
186
- async replicateAllToRemote(showingNotice = false, sendChunksInBulkDisabled = false) {
189
+ async replicateAllToRemote(showingNotice = false) {
187
190
  if (!this.appLifecycleService.isReady()) return false;
188
191
  if (!await this.onBeforeReplicate(showingNotice)) {
189
192
  this._log(this.context.translate("Replicator.Message.SomeModuleFailed"), LOG_LEVEL_NOTICE);
@@ -194,19 +197,6 @@ class ReplicationService extends ServiceBase {
194
197
  if (!activeReplicator) {
195
198
  return false;
196
199
  }
197
- if (!sendChunksInBulkDisabled) {
198
- if (activeReplicator?.isChunkSendingSupported) {
199
- if (await this.APIService.confirm.askYesNoDialog(
200
- "Do you want to send all chunks before replication?",
201
- {
202
- defaultOption: "No",
203
- timeout: 20
204
- }
205
- ) == "yes") {
206
- await activeReplicator.sendChunks(currentSettings, void 0, true, 0);
207
- }
208
- }
209
- }
210
200
  const ret = await activeReplicator.replicateAllToServer(currentSettings, showingNotice);
211
201
  if (ret) return true;
212
202
  const checkResult = await this.checkConnectionFailure();
@@ -82,16 +82,8 @@ export declare abstract class SettingService<T extends ServiceContext = ServiceC
82
82
  * Suspend extra synchronisation activities, e.g., hidden files sync.
83
83
  */
84
84
  readonly suspendExtraSync: import("../lib/HandlerUtils.js").BooleanMultipleHandlerFunction<() => Promise<boolean>>;
85
- /**
86
- * Suggest enabling optional features to the user.
87
- */
88
- readonly suggestOptionalFeatures: import("../lib/HandlerUtils.js").BooleanMultipleHandlerFunction<(opt: {
89
- enableFetch?: boolean;
90
- enableOverwrite?: boolean;
91
- }) => Promise<boolean>>;
92
85
  /**
93
86
  * Enable an optional feature and save to the settings.
94
- * It may also raised from `handleSuggestOptionalFeatures` if the user agrees.
95
87
  * @param mode The optional feature to enable.
96
88
  */
97
89
  readonly enableOptionalFeature: import("../lib/HandlerUtils.js").BooleanMultipleHandlerFunction<(mode: keyof OPTIONAL_SYNC_FEATURES) => Promise<boolean>>;
@@ -287,13 +287,8 @@ class SettingService extends ServiceBase {
287
287
  * Suspend extra synchronisation activities, e.g., hidden files sync.
288
288
  */
289
289
  suspendExtraSync = handlers().all("suspendExtraSync");
290
- /**
291
- * Suggest enabling optional features to the user.
292
- */
293
- suggestOptionalFeatures = handlers().all("suggestOptionalFeatures");
294
290
  /**
295
291
  * Enable an optional feature and save to the settings.
296
- * It may also raised from `handleSuggestOptionalFeatures` if the user agrees.
297
292
  * @param mode The optional feature to enable.
298
293
  */
299
294
  enableOptionalFeature = handlers().all("enableOptionalFeature");
@@ -2,7 +2,7 @@ import type { ServiceContext } from "../../base/ServiceBase.js";
2
2
  import { InjectableAPIService } from "../injectable/InjectableAPIService.js";
3
3
  import type { FetchHttpHandler } from "@smithy/fetch-http-handler";
4
4
  import type { ICommandCompat } from "../../base/IService.js";
5
- import type { Confirm } from "../../../interfaces/Confirm.js";
5
+ import type { Confirm, ConfirmActionLayout } from "../../../interfaces/Confirm.js";
6
6
  /**
7
7
  * Headless implementation of Confirm that returns sensible defaults instead
8
8
  * of throwing. Dialogs are logged to stderr so the prompts are visible in
@@ -23,7 +23,7 @@ export declare class HeadlessConfirm implements Confirm {
23
23
  timeout?: number;
24
24
  }): Promise<T[number] | false>;
25
25
  askInPopup(key: string, dialogText: string, anchorCallback: (anchor: HTMLAnchorElement) => void, durationMs?: number): void;
26
- confirmWithMessage(title: string, contentMd: string, buttons: string[], defaultAction: (typeof buttons)[number], timeout?: number): Promise<(typeof buttons)[number] | false>;
26
+ confirmWithMessage(title: string, contentMd: string, buttons: string[], defaultAction: (typeof buttons)[number], timeout?: number, _actionLayout?: ConfirmActionLayout): Promise<(typeof buttons)[number] | false>;
27
27
  }
28
28
  export declare class HeadlessAPIService<T extends ServiceContext> extends InjectableAPIService<T> {
29
29
  private _confirmInstance;
@@ -26,7 +26,7 @@ class HeadlessConfirm {
26
26
  askInPopup(key, dialogText, anchorCallback, durationMs) {
27
27
  console.error(`[Headless] Popup (${key}): ${dialogText}`);
28
28
  }
29
- confirmWithMessage(title, contentMd, buttons, defaultAction, timeout) {
29
+ confirmWithMessage(title, contentMd, buttons, defaultAction, timeout, _actionLayout) {
30
30
  console.error(`[Headless] ${title}: ${contentMd} \u2192 ${defaultAction}`);
31
31
  return Promise.resolve(defaultAction);
32
32
  }