mindwtr-mcp 1.1.6 → 1.1.7
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/index.js +1395 -260
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3049,9 +3049,28 @@ var require_data = __commonJS((exports, module) => {
|
|
|
3049
3049
|
var require_utils = __commonJS((exports, module) => {
|
|
3050
3050
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3051
3051
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
3052
|
+
var isPort = RegExp.prototype.test.bind(/^\d*$/u);
|
|
3052
3053
|
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3053
3054
|
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3054
|
-
var isPathCharacter = RegExp.prototype.test.bind(/^[
|
|
3055
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
|
|
3056
|
+
var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
|
|
3057
|
+
var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
|
|
3058
|
+
var BYTE_HEX = new Array(256);
|
|
3059
|
+
{
|
|
3060
|
+
const HEX_DIGITS = "0123456789ABCDEF";
|
|
3061
|
+
for (let i = 0;i < 256; i++) {
|
|
3062
|
+
BYTE_HEX[i] = "%" + HEX_DIGITS[i >> 4] + HEX_DIGITS[i & 15];
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
function percentEncodeNonAscii(cp) {
|
|
3066
|
+
if (cp < 2048) {
|
|
3067
|
+
return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63];
|
|
3068
|
+
}
|
|
3069
|
+
if (cp < 65536) {
|
|
3070
|
+
return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
3071
|
+
}
|
|
3072
|
+
return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
3073
|
+
}
|
|
3055
3074
|
function stringArrayToHexStripped(input) {
|
|
3056
3075
|
let acc = "";
|
|
3057
3076
|
let code = 0;
|
|
@@ -3076,91 +3095,122 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3076
3095
|
}
|
|
3077
3096
|
return acc;
|
|
3078
3097
|
}
|
|
3098
|
+
var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
|
|
3099
|
+
var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
|
|
3100
|
+
var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
|
|
3079
3101
|
var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
|
|
3080
|
-
function
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
} else {
|
|
3090
|
-
output.error = true;
|
|
3091
|
-
return false;
|
|
3102
|
+
function isZoneIdentifier(zone) {
|
|
3103
|
+
if (zone.length === 0)
|
|
3104
|
+
return false;
|
|
3105
|
+
for (let i = 0;i < zone.length; i++) {
|
|
3106
|
+
if (isZoneCharacter(zone[i]))
|
|
3107
|
+
continue;
|
|
3108
|
+
if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) {
|
|
3109
|
+
i += 2;
|
|
3110
|
+
continue;
|
|
3092
3111
|
}
|
|
3093
|
-
|
|
3112
|
+
return false;
|
|
3094
3113
|
}
|
|
3095
3114
|
return true;
|
|
3096
3115
|
}
|
|
3097
|
-
function
|
|
3098
|
-
let
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
let
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
if (cursor === ":") {
|
|
3111
|
-
if (endipv6Encountered === true) {
|
|
3112
|
-
endIpv6 = true;
|
|
3113
|
-
}
|
|
3114
|
-
if (!consume(buffer, address, output)) {
|
|
3115
|
-
break;
|
|
3116
|
-
}
|
|
3117
|
-
if (++tokenCount > 7) {
|
|
3118
|
-
output.error = true;
|
|
3119
|
-
break;
|
|
3120
|
-
}
|
|
3121
|
-
if (i > 0 && input[i - 1] === ":") {
|
|
3122
|
-
endipv6Encountered = true;
|
|
3123
|
-
}
|
|
3124
|
-
address.push(":");
|
|
3125
|
-
continue;
|
|
3126
|
-
} else if (cursor === "%") {
|
|
3127
|
-
if (!consume(buffer, address, output)) {
|
|
3128
|
-
break;
|
|
3116
|
+
function compressIPv6ZeroRun(hextets) {
|
|
3117
|
+
let bestStart = -1;
|
|
3118
|
+
let bestLength = 0;
|
|
3119
|
+
let runStart = -1;
|
|
3120
|
+
let runLength = 0;
|
|
3121
|
+
for (let i = 0;i < hextets.length; i++) {
|
|
3122
|
+
if (hextets[i] === "0") {
|
|
3123
|
+
if (runStart === -1)
|
|
3124
|
+
runStart = i;
|
|
3125
|
+
runLength++;
|
|
3126
|
+
if (runLength > bestLength) {
|
|
3127
|
+
bestLength = runLength;
|
|
3128
|
+
bestStart = runStart;
|
|
3129
3129
|
}
|
|
3130
|
-
consume = consumeIsZone;
|
|
3131
3130
|
} else {
|
|
3132
|
-
|
|
3133
|
-
|
|
3131
|
+
runStart = -1;
|
|
3132
|
+
runLength = 0;
|
|
3134
3133
|
}
|
|
3135
3134
|
}
|
|
3136
|
-
if (
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3135
|
+
if (bestLength < 2)
|
|
3136
|
+
return hextets.join(":");
|
|
3137
|
+
const head = hextets.slice(0, bestStart).join(":");
|
|
3138
|
+
const tail = hextets.slice(bestStart + bestLength).join(":");
|
|
3139
|
+
return head + "::" + tail;
|
|
3140
|
+
}
|
|
3141
|
+
function normalizeIPv6Address(input) {
|
|
3142
|
+
const compression = input.indexOf("::");
|
|
3143
|
+
if (compression !== -1 && input.indexOf("::", compression + 1) !== -1)
|
|
3144
|
+
return;
|
|
3145
|
+
const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
|
|
3146
|
+
const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
|
|
3147
|
+
if (compression !== -1) {
|
|
3148
|
+
if (left.length === 1 && left[0] === "")
|
|
3149
|
+
left.length = 0;
|
|
3150
|
+
if (right.length === 1 && right[0] === "")
|
|
3151
|
+
right.length = 0;
|
|
3152
|
+
}
|
|
3153
|
+
const parts = left.concat(right);
|
|
3154
|
+
let hextetCount = 0;
|
|
3155
|
+
for (let i = 0;i < parts.length; i++) {
|
|
3156
|
+
const part = parts[i];
|
|
3157
|
+
if (part === "")
|
|
3158
|
+
return;
|
|
3159
|
+
if (part.indexOf(".") !== -1) {
|
|
3160
|
+
if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part))
|
|
3161
|
+
return;
|
|
3162
|
+
hextetCount += 2;
|
|
3163
|
+
continue;
|
|
3143
3164
|
}
|
|
3165
|
+
if (!isHextet(part))
|
|
3166
|
+
return;
|
|
3167
|
+
parts[i] = parseInt(part, 16).toString(16);
|
|
3168
|
+
hextetCount++;
|
|
3144
3169
|
}
|
|
3145
|
-
|
|
3146
|
-
|
|
3170
|
+
if (compression === -1) {
|
|
3171
|
+
if (hextetCount !== 8)
|
|
3172
|
+
return;
|
|
3173
|
+
return compressIPv6ZeroRun(parts);
|
|
3174
|
+
}
|
|
3175
|
+
if (hextetCount >= 8)
|
|
3176
|
+
return;
|
|
3177
|
+
const expanded = parts.slice(0, left.length);
|
|
3178
|
+
for (let i = hextetCount;i < 8; i++)
|
|
3179
|
+
expanded.push("0");
|
|
3180
|
+
for (let i = left.length;i < parts.length; i++)
|
|
3181
|
+
expanded.push(parts[i]);
|
|
3182
|
+
return compressIPv6ZeroRun(expanded);
|
|
3147
3183
|
}
|
|
3148
3184
|
function normalizeIPv6(host) {
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
}
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3185
|
+
const bracketed = host[0] === "[" && host[host.length - 1] === "]";
|
|
3186
|
+
const hasBracket = host[0] === "[" || host[host.length - 1] === "]";
|
|
3187
|
+
if (hasBracket && !bracketed)
|
|
3188
|
+
return { host, isIPV6: false, error: true };
|
|
3189
|
+
let input = bracketed ? host.slice(1, -1) : host;
|
|
3190
|
+
if (bracketed && isIPvFuture(input)) {
|
|
3191
|
+
input = input.toLowerCase();
|
|
3192
|
+
return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true };
|
|
3193
|
+
}
|
|
3194
|
+
if (findToken(input, ":") < 2) {
|
|
3195
|
+
return { host, isIPV6: false, error: bracketed };
|
|
3196
|
+
}
|
|
3197
|
+
let zoneIdentifier = "";
|
|
3198
|
+
const zoneSeparator = input.indexOf("%");
|
|
3199
|
+
if (zoneSeparator !== -1) {
|
|
3200
|
+
const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
|
|
3201
|
+
zoneIdentifier = input.slice(zoneSeparator + separatorLength);
|
|
3202
|
+
if (!isZoneIdentifier(zoneIdentifier))
|
|
3203
|
+
return { host, isIPV6: false, error: true };
|
|
3204
|
+
input = input.slice(0, zoneSeparator);
|
|
3205
|
+
}
|
|
3206
|
+
const address = normalizeIPv6Address(input);
|
|
3207
|
+
if (address === undefined)
|
|
3208
|
+
return { host, isIPV6: false, error: true };
|
|
3209
|
+
return {
|
|
3210
|
+
host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
|
|
3211
|
+
escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
|
|
3212
|
+
isIPV6: true
|
|
3213
|
+
};
|
|
3164
3214
|
}
|
|
3165
3215
|
function findToken(str, token) {
|
|
3166
3216
|
let ind = 0;
|
|
@@ -3280,7 +3330,8 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3280
3330
|
function normalizePathEncoding(input) {
|
|
3281
3331
|
let output = "";
|
|
3282
3332
|
for (let i = 0;i < input.length; i++) {
|
|
3283
|
-
|
|
3333
|
+
const ch = input[i];
|
|
3334
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3284
3335
|
const hex = input.slice(i + 1, i + 3);
|
|
3285
3336
|
if (isHexPair(hex)) {
|
|
3286
3337
|
const normalizedHex = hex.toUpperCase();
|
|
@@ -3294,10 +3345,152 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3294
3345
|
continue;
|
|
3295
3346
|
}
|
|
3296
3347
|
}
|
|
3297
|
-
if (isPathCharacter(
|
|
3298
|
-
output +=
|
|
3348
|
+
if (isPathCharacter(ch)) {
|
|
3349
|
+
output += ch;
|
|
3350
|
+
} else {
|
|
3351
|
+
const code = input.charCodeAt(i);
|
|
3352
|
+
if (code < 128) {
|
|
3353
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
3354
|
+
} else if (code < 55296 || code > 57343) {
|
|
3355
|
+
output += percentEncodeNonAscii(code);
|
|
3356
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3357
|
+
const low = input.charCodeAt(i + 1);
|
|
3358
|
+
if (low >= 56320 && low <= 57343) {
|
|
3359
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3360
|
+
i++;
|
|
3361
|
+
} else {
|
|
3362
|
+
output += percentEncodeNonAscii(65533);
|
|
3363
|
+
}
|
|
3364
|
+
} else {
|
|
3365
|
+
output += percentEncodeNonAscii(65533);
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
return output;
|
|
3370
|
+
}
|
|
3371
|
+
function serializePathEncoding(input, pathNoScheme = false) {
|
|
3372
|
+
let output = "";
|
|
3373
|
+
let firstSegment = pathNoScheme && input[0] !== "/";
|
|
3374
|
+
for (let i = 0;i < input.length; i++) {
|
|
3375
|
+
const ch = input[i];
|
|
3376
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3377
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3378
|
+
if (isHexPair(hex)) {
|
|
3379
|
+
output += "%" + hex.toUpperCase();
|
|
3380
|
+
i += 2;
|
|
3381
|
+
continue;
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
if (ch === "/") {
|
|
3385
|
+
firstSegment = false;
|
|
3386
|
+
}
|
|
3387
|
+
if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) {
|
|
3388
|
+
output += ch;
|
|
3389
|
+
} else {
|
|
3390
|
+
const code = input.charCodeAt(i);
|
|
3391
|
+
if (code < 128) {
|
|
3392
|
+
output += BYTE_HEX[code];
|
|
3393
|
+
} else if (code < 55296 || code > 57343) {
|
|
3394
|
+
output += percentEncodeNonAscii(code);
|
|
3395
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3396
|
+
const low = input.charCodeAt(i + 1);
|
|
3397
|
+
if (low >= 56320 && low <= 57343) {
|
|
3398
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3399
|
+
i++;
|
|
3400
|
+
} else {
|
|
3401
|
+
output += percentEncodeNonAscii(65533);
|
|
3402
|
+
}
|
|
3403
|
+
} else {
|
|
3404
|
+
output += percentEncodeNonAscii(65533);
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
return output;
|
|
3409
|
+
}
|
|
3410
|
+
function encodeComponent(input, isAllowed) {
|
|
3411
|
+
let output = "";
|
|
3412
|
+
for (let i = 0;i < input.length; i++) {
|
|
3413
|
+
const ch = input[i];
|
|
3414
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3415
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3416
|
+
if (isHexPair(hex)) {
|
|
3417
|
+
output += "%" + hex.toUpperCase();
|
|
3418
|
+
i += 2;
|
|
3419
|
+
continue;
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3422
|
+
if (isAllowed(ch)) {
|
|
3423
|
+
output += ch;
|
|
3424
|
+
} else {
|
|
3425
|
+
const code = input.charCodeAt(i);
|
|
3426
|
+
if (code < 128) {
|
|
3427
|
+
output += BYTE_HEX[code];
|
|
3428
|
+
} else if (code < 55296 || code > 57343) {
|
|
3429
|
+
output += percentEncodeNonAscii(code);
|
|
3430
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3431
|
+
const low = input.charCodeAt(i + 1);
|
|
3432
|
+
if (low >= 56320 && low <= 57343) {
|
|
3433
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3434
|
+
i++;
|
|
3435
|
+
} else {
|
|
3436
|
+
output += percentEncodeNonAscii(65533);
|
|
3437
|
+
}
|
|
3438
|
+
} else {
|
|
3439
|
+
output += percentEncodeNonAscii(65533);
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
return output;
|
|
3444
|
+
}
|
|
3445
|
+
function encodeUserinfo(input) {
|
|
3446
|
+
return encodeComponent(input, isUserinfoCharacter);
|
|
3447
|
+
}
|
|
3448
|
+
function encodeQuery(input) {
|
|
3449
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3450
|
+
}
|
|
3451
|
+
function encodeFragment(input) {
|
|
3452
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
3453
|
+
}
|
|
3454
|
+
function isEscapeSafe(cp) {
|
|
3455
|
+
return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 42 || cp === 43 || cp === 45 || cp === 46 || cp === 47 || cp === 64 || cp === 95;
|
|
3456
|
+
}
|
|
3457
|
+
function normalizeQueryFragmentEncoding(input) {
|
|
3458
|
+
let output = "";
|
|
3459
|
+
for (let i = 0;i < input.length; i++) {
|
|
3460
|
+
const ch = input[i];
|
|
3461
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
3462
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3463
|
+
if (isHexPair(hex)) {
|
|
3464
|
+
const normalizedHex = hex.toUpperCase();
|
|
3465
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3466
|
+
if (isUnreserved(decoded)) {
|
|
3467
|
+
output += decoded;
|
|
3468
|
+
} else {
|
|
3469
|
+
output += "%" + normalizedHex;
|
|
3470
|
+
}
|
|
3471
|
+
i += 2;
|
|
3472
|
+
continue;
|
|
3473
|
+
}
|
|
3474
|
+
}
|
|
3475
|
+
if (isQueryFragmentCharacter(ch)) {
|
|
3476
|
+
output += ch;
|
|
3299
3477
|
} else {
|
|
3300
|
-
|
|
3478
|
+
const code = input.charCodeAt(i);
|
|
3479
|
+
if (code < 128) {
|
|
3480
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
3481
|
+
} else if (code < 55296 || code > 57343) {
|
|
3482
|
+
output += percentEncodeNonAscii(code);
|
|
3483
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
3484
|
+
const low = input.charCodeAt(i + 1);
|
|
3485
|
+
if (low >= 56320 && low <= 57343) {
|
|
3486
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
3487
|
+
i++;
|
|
3488
|
+
} else {
|
|
3489
|
+
output += percentEncodeNonAscii(65533);
|
|
3490
|
+
}
|
|
3491
|
+
} else {
|
|
3492
|
+
output += percentEncodeNonAscii(65533);
|
|
3493
|
+
}
|
|
3301
3494
|
}
|
|
3302
3495
|
}
|
|
3303
3496
|
return output;
|
|
@@ -3320,14 +3513,18 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3320
3513
|
function recomposeAuthority(component) {
|
|
3321
3514
|
const uriTokens = [];
|
|
3322
3515
|
if (component.userinfo !== undefined) {
|
|
3323
|
-
uriTokens.push(component.userinfo);
|
|
3516
|
+
uriTokens.push(encodeUserinfo(component.userinfo));
|
|
3324
3517
|
uriTokens.push("@");
|
|
3325
3518
|
}
|
|
3326
3519
|
if (component.host !== undefined) {
|
|
3327
|
-
let host =
|
|
3520
|
+
let host = component.host;
|
|
3328
3521
|
if (!isIPv4(host)) {
|
|
3329
|
-
|
|
3330
|
-
if (ipV6res.isIPV6
|
|
3522
|
+
let ipV6res = normalizeIPv6(host);
|
|
3523
|
+
if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
|
|
3524
|
+
host = normalizePercentEncoding(host, true);
|
|
3525
|
+
ipV6res = normalizeIPv6(host);
|
|
3526
|
+
}
|
|
3527
|
+
if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
|
|
3331
3528
|
host = `[${ipV6res.escapedHost}]`;
|
|
3332
3529
|
} else {
|
|
3333
3530
|
host = reescapeHostDelimiters(host, false);
|
|
@@ -3336,8 +3533,12 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3336
3533
|
uriTokens.push(host);
|
|
3337
3534
|
}
|
|
3338
3535
|
if (typeof component.port === "number" || typeof component.port === "string") {
|
|
3536
|
+
const port = String(component.port);
|
|
3537
|
+
if (!isPort(port)) {
|
|
3538
|
+
throw new TypeError("URI port is malformed.");
|
|
3539
|
+
}
|
|
3339
3540
|
uriTokens.push(":");
|
|
3340
|
-
uriTokens.push(
|
|
3541
|
+
uriTokens.push(port);
|
|
3341
3542
|
}
|
|
3342
3543
|
return uriTokens.length ? uriTokens.join("") : undefined;
|
|
3343
3544
|
}
|
|
@@ -3347,6 +3548,11 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3347
3548
|
reescapeHostDelimiters,
|
|
3348
3549
|
normalizePercentEncoding,
|
|
3349
3550
|
normalizePathEncoding,
|
|
3551
|
+
serializePathEncoding,
|
|
3552
|
+
normalizeQueryFragmentEncoding,
|
|
3553
|
+
encodeUserinfo,
|
|
3554
|
+
encodeQuery,
|
|
3555
|
+
encodeFragment,
|
|
3350
3556
|
escapePreservingEscapes,
|
|
3351
3557
|
removeDotSegments,
|
|
3352
3558
|
isIPv4,
|
|
@@ -3359,7 +3565,7 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
3359
3565
|
// ../../node_modules/fast-uri/lib/schemes.js
|
|
3360
3566
|
var require_schemes = __commonJS((exports, module) => {
|
|
3361
3567
|
var { isUUID } = require_utils();
|
|
3362
|
-
var URN_REG =
|
|
3568
|
+
var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
|
|
3363
3569
|
var supportedSchemeNames = [
|
|
3364
3570
|
"http",
|
|
3365
3571
|
"https",
|
|
@@ -3414,9 +3620,10 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3414
3620
|
wsComponent.secure = undefined;
|
|
3415
3621
|
}
|
|
3416
3622
|
if (wsComponent.resourceName) {
|
|
3417
|
-
const
|
|
3623
|
+
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
3624
|
+
const path = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
3418
3625
|
wsComponent.path = path && path !== "/" ? path : undefined;
|
|
3419
|
-
wsComponent.query =
|
|
3626
|
+
wsComponent.query = queryIndex === -1 ? undefined : wsComponent.resourceName.slice(queryIndex + 1);
|
|
3420
3627
|
wsComponent.resourceName = undefined;
|
|
3421
3628
|
}
|
|
3422
3629
|
wsComponent.fragment = undefined;
|
|
@@ -3428,7 +3635,7 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3428
3635
|
return urnComponent;
|
|
3429
3636
|
}
|
|
3430
3637
|
const matches = urnComponent.path.match(URN_REG);
|
|
3431
|
-
if (matches) {
|
|
3638
|
+
if (matches && matches[0] === urnComponent.path) {
|
|
3432
3639
|
const scheme = options.scheme || urnComponent.scheme || "urn";
|
|
3433
3640
|
urnComponent.nid = matches[1].toLowerCase();
|
|
3434
3641
|
urnComponent.nss = matches[2];
|
|
@@ -3532,8 +3739,17 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
3532
3739
|
|
|
3533
3740
|
// ../../node_modules/fast-uri/index.js
|
|
3534
3741
|
var require_fast_uri = __commonJS((exports, module) => {
|
|
3535
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding,
|
|
3742
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3536
3743
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3744
|
+
var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
|
|
3745
|
+
var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
|
|
3746
|
+
function decodeValidScheme(scheme) {
|
|
3747
|
+
const decodedScheme = unescape(String(scheme));
|
|
3748
|
+
if (!VALID_SCHEME.test(decodedScheme)) {
|
|
3749
|
+
throw new TypeError(MALFORMED_SCHEME_ERROR);
|
|
3750
|
+
}
|
|
3751
|
+
return decodedScheme;
|
|
3752
|
+
}
|
|
3537
3753
|
function normalize(uri, options) {
|
|
3538
3754
|
if (typeof uri === "string") {
|
|
3539
3755
|
uri = normalizeString(uri, options);
|
|
@@ -3544,12 +3760,34 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3544
3760
|
}
|
|
3545
3761
|
function resolve(baseURI, relativeURI, options) {
|
|
3546
3762
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3547
|
-
const {
|
|
3548
|
-
|
|
3549
|
-
|
|
3763
|
+
const {
|
|
3764
|
+
parsed: baseParsed,
|
|
3765
|
+
malformedAuthorityOrPort: baseMalformed,
|
|
3766
|
+
malformedPercentEncoding: baseMalformedPercentEncoding,
|
|
3767
|
+
malformedSchemeSpecific: baseMalformedSchemeSpecific,
|
|
3768
|
+
malformedHost: baseMalformedHost,
|
|
3769
|
+
malformedScheme: baseMalformedScheme
|
|
3770
|
+
} = parseWithStatus(baseURI, schemelessOptions);
|
|
3771
|
+
const {
|
|
3772
|
+
parsed: relativeParsed,
|
|
3773
|
+
malformedAuthorityOrPort: relativeMalformed,
|
|
3774
|
+
malformedPercentEncoding: relativeMalformedPercentEncoding,
|
|
3775
|
+
malformedSchemeSpecific: relativeMalformedSchemeSpecific,
|
|
3776
|
+
malformedHost: relativeMalformedHost,
|
|
3777
|
+
malformedScheme: relativeMalformedScheme
|
|
3778
|
+
} = parseWithStatus(relativeURI, schemelessOptions);
|
|
3779
|
+
if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
|
|
3550
3780
|
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
3551
3781
|
}
|
|
3552
3782
|
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
3783
|
+
const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
|
|
3784
|
+
const resolvedHost = resolved.host;
|
|
3785
|
+
const resolvedHostIsIP = resolvedHost !== undefined && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
|
|
3786
|
+
canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
|
|
3787
|
+
const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !/\P{ASCII}/u.test(resolvedHost);
|
|
3788
|
+
if (resolved.error && !encodedASCIIHost) {
|
|
3789
|
+
throw new Error(resolved.error);
|
|
3790
|
+
}
|
|
3553
3791
|
schemelessOptions.skipEscape = true;
|
|
3554
3792
|
return serialize(resolved, schemelessOptions);
|
|
3555
3793
|
}
|
|
@@ -3609,7 +3847,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3609
3847
|
function equal(uriA, uriB, options) {
|
|
3610
3848
|
const normalizedA = normalizeComparableURI(uriA, options);
|
|
3611
3849
|
const normalizedB = normalizeComparableURI(uriB, options);
|
|
3612
|
-
return normalizedA !== undefined && normalizedB !== undefined && normalizedA
|
|
3850
|
+
return normalizedA !== undefined && normalizedB !== undefined && normalizedA === normalizedB;
|
|
3613
3851
|
}
|
|
3614
3852
|
function serialize(cmpts, opts) {
|
|
3615
3853
|
const component = {
|
|
@@ -3630,20 +3868,23 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3630
3868
|
};
|
|
3631
3869
|
const options = Object.assign({}, opts);
|
|
3632
3870
|
const uriTokens = [];
|
|
3871
|
+
if (component.scheme) {
|
|
3872
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3873
|
+
}
|
|
3633
3874
|
const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
|
|
3634
3875
|
if (schemeHandler && schemeHandler.serialize)
|
|
3635
3876
|
schemeHandler.serialize(component, options);
|
|
3877
|
+
const hasAuthority = component.userinfo !== undefined || component.host !== undefined || component.port !== undefined;
|
|
3878
|
+
const pathNoScheme = !options.skipEscape && component.scheme === undefined && !hasAuthority;
|
|
3636
3879
|
if (component.path !== undefined) {
|
|
3637
3880
|
if (!options.skipEscape) {
|
|
3638
|
-
component.path =
|
|
3639
|
-
if (component.scheme !== undefined) {
|
|
3640
|
-
component.path = component.path.split("%3A").join(":");
|
|
3641
|
-
}
|
|
3881
|
+
component.path = serializePathEncoding(component.path, pathNoScheme);
|
|
3642
3882
|
} else {
|
|
3643
3883
|
component.path = normalizePercentEncoding(component.path);
|
|
3644
3884
|
}
|
|
3645
3885
|
}
|
|
3646
3886
|
if (options.reference !== "suffix" && component.scheme) {
|
|
3887
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
3647
3888
|
uriTokens.push(component.scheme, ":");
|
|
3648
3889
|
}
|
|
3649
3890
|
const authority = recomposeAuthority(component);
|
|
@@ -3661,16 +3902,19 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3661
3902
|
if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
|
|
3662
3903
|
s = removeDotSegments(s);
|
|
3663
3904
|
}
|
|
3905
|
+
if (pathNoScheme) {
|
|
3906
|
+
s = serializePathEncoding(s, true);
|
|
3907
|
+
}
|
|
3664
3908
|
if (authority === undefined && s[0] === "/" && s[1] === "/") {
|
|
3665
3909
|
s = "/%2F" + s.slice(2);
|
|
3666
3910
|
}
|
|
3667
3911
|
uriTokens.push(s);
|
|
3668
3912
|
}
|
|
3669
3913
|
if (component.query !== undefined) {
|
|
3670
|
-
uriTokens.push("?", component.query);
|
|
3914
|
+
uriTokens.push("?", encodeQuery(component.query));
|
|
3671
3915
|
}
|
|
3672
3916
|
if (component.fragment !== undefined) {
|
|
3673
|
-
uriTokens.push("#", component.fragment);
|
|
3917
|
+
uriTokens.push("#", encodeFragment(component.fragment));
|
|
3674
3918
|
}
|
|
3675
3919
|
return uriTokens.join("");
|
|
3676
3920
|
}
|
|
@@ -3686,6 +3930,36 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3686
3930
|
}
|
|
3687
3931
|
return;
|
|
3688
3932
|
}
|
|
3933
|
+
function hasMalformedPercentEncoding(component) {
|
|
3934
|
+
if (component === undefined)
|
|
3935
|
+
return false;
|
|
3936
|
+
let percent = component.indexOf("%");
|
|
3937
|
+
while (percent !== -1) {
|
|
3938
|
+
if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
|
|
3939
|
+
return true;
|
|
3940
|
+
}
|
|
3941
|
+
percent = component.indexOf("%", percent + 3);
|
|
3942
|
+
}
|
|
3943
|
+
return false;
|
|
3944
|
+
}
|
|
3945
|
+
function isIPLiteral(host) {
|
|
3946
|
+
return host[0] === "[" && host[host.length - 1] === "]";
|
|
3947
|
+
}
|
|
3948
|
+
function hasMalformedComponentPercentEncoding(matches) {
|
|
3949
|
+
const host = matches[4];
|
|
3950
|
+
return hasMalformedPercentEncoding(matches[3]) || host !== undefined && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
|
|
3951
|
+
}
|
|
3952
|
+
function canonicalizeHost(parsed, options, schemeHandler, isIP) {
|
|
3953
|
+
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
3954
|
+
try {
|
|
3955
|
+
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
3956
|
+
} catch (e) {
|
|
3957
|
+
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
3958
|
+
return true;
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
return false;
|
|
3962
|
+
}
|
|
3689
3963
|
function parseWithStatus(uri, opts) {
|
|
3690
3964
|
const options = Object.assign({}, opts);
|
|
3691
3965
|
const parsed = {
|
|
@@ -3698,6 +3972,11 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3698
3972
|
fragment: undefined
|
|
3699
3973
|
};
|
|
3700
3974
|
let malformedAuthorityOrPort = false;
|
|
3975
|
+
let malformedPercentEncoding = false;
|
|
3976
|
+
let malformedSchemeSpecific = false;
|
|
3977
|
+
let malformedHost = false;
|
|
3978
|
+
let malformedIPLiteral = false;
|
|
3979
|
+
let malformedScheme = false;
|
|
3701
3980
|
let isIP = false;
|
|
3702
3981
|
if (options.reference === "suffix") {
|
|
3703
3982
|
if (options.scheme) {
|
|
@@ -3734,6 +4013,19 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3734
4013
|
parsed.path = matches[6] || "";
|
|
3735
4014
|
parsed.query = matches[7];
|
|
3736
4015
|
parsed.fragment = matches[8];
|
|
4016
|
+
if (parsed.scheme !== undefined) {
|
|
4017
|
+
const decodedScheme = unescape(parsed.scheme);
|
|
4018
|
+
if (VALID_SCHEME.test(decodedScheme)) {
|
|
4019
|
+
parsed.scheme = decodedScheme.toLowerCase();
|
|
4020
|
+
} else {
|
|
4021
|
+
parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
|
|
4022
|
+
malformedScheme = true;
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
4025
|
+
malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
|
|
4026
|
+
if (malformedPercentEncoding) {
|
|
4027
|
+
parsed.error = parsed.error || "URI contains malformed percent-encoding.";
|
|
4028
|
+
}
|
|
3737
4029
|
if (isNaN(parsed.port)) {
|
|
3738
4030
|
parsed.port = matches[5];
|
|
3739
4031
|
}
|
|
@@ -3745,9 +4037,16 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3745
4037
|
if (parsed.host) {
|
|
3746
4038
|
const ipv4result = isIPv4(parsed.host);
|
|
3747
4039
|
if (ipv4result === false) {
|
|
4040
|
+
const bracketedIPLiteral = isIPLiteral(parsed.host);
|
|
4041
|
+
const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1;
|
|
3748
4042
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
3749
|
-
|
|
3750
|
-
|
|
4043
|
+
isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
|
|
4044
|
+
malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
|
|
4045
|
+
parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
|
|
4046
|
+
if (malformedIPLiteral) {
|
|
4047
|
+
parsed.error = parsed.error || "URI host is malformed.";
|
|
4048
|
+
malformedAuthorityOrPort = true;
|
|
4049
|
+
}
|
|
3751
4050
|
} else {
|
|
3752
4051
|
isIP = true;
|
|
3753
4052
|
}
|
|
@@ -3765,42 +4064,36 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3765
4064
|
parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
|
|
3766
4065
|
}
|
|
3767
4066
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
3768
|
-
if (!
|
|
3769
|
-
|
|
3770
|
-
try {
|
|
3771
|
-
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
3772
|
-
} catch (e) {
|
|
3773
|
-
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
3774
|
-
}
|
|
3775
|
-
}
|
|
4067
|
+
if (!malformedIPLiteral) {
|
|
4068
|
+
malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
|
|
3776
4069
|
}
|
|
3777
4070
|
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
3778
4071
|
if (uri.indexOf("%") !== -1) {
|
|
3779
|
-
if (parsed.
|
|
3780
|
-
parsed.
|
|
3781
|
-
|
|
3782
|
-
if (parsed.host !== undefined) {
|
|
3783
|
-
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
4072
|
+
if (parsed.host !== undefined && !malformedIPLiteral) {
|
|
4073
|
+
const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
4074
|
+
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
3784
4075
|
}
|
|
3785
4076
|
}
|
|
3786
4077
|
if (parsed.path) {
|
|
3787
4078
|
parsed.path = normalizePathEncoding(parsed.path);
|
|
3788
4079
|
}
|
|
4080
|
+
if (parsed.query) {
|
|
4081
|
+
parsed.query = normalizeQueryFragmentEncoding(parsed.query);
|
|
4082
|
+
}
|
|
3789
4083
|
if (parsed.fragment) {
|
|
3790
|
-
|
|
3791
|
-
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
3792
|
-
} catch {
|
|
3793
|
-
parsed.error = parsed.error || "URI malformed";
|
|
3794
|
-
}
|
|
4084
|
+
parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
|
|
3795
4085
|
}
|
|
3796
4086
|
}
|
|
3797
4087
|
if (schemeHandler && schemeHandler.parse) {
|
|
3798
4088
|
schemeHandler.parse(parsed, options);
|
|
4089
|
+
if (schemeHandler === SCHEMES.urn && parsed.nid === undefined) {
|
|
4090
|
+
malformedSchemeSpecific = true;
|
|
4091
|
+
}
|
|
3799
4092
|
}
|
|
3800
4093
|
} else {
|
|
3801
4094
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
3802
4095
|
}
|
|
3803
|
-
return { parsed, malformedAuthorityOrPort };
|
|
4096
|
+
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
3804
4097
|
}
|
|
3805
4098
|
function parse6(uri, opts) {
|
|
3806
4099
|
return parseWithStatus(uri, opts).parsed;
|
|
@@ -3809,20 +4102,28 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
3809
4102
|
return normalizeStringWithStatus(uri, opts).normalized;
|
|
3810
4103
|
}
|
|
3811
4104
|
function normalizeStringWithStatus(uri, opts) {
|
|
3812
|
-
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
4105
|
+
const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
|
|
3813
4106
|
return {
|
|
3814
|
-
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
3815
|
-
malformedAuthorityOrPort
|
|
4107
|
+
normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
|
|
4108
|
+
malformedAuthorityOrPort,
|
|
4109
|
+
malformedPercentEncoding,
|
|
4110
|
+
malformedSchemeSpecific,
|
|
4111
|
+
malformedHost,
|
|
4112
|
+
malformedScheme
|
|
3816
4113
|
};
|
|
3817
4114
|
}
|
|
3818
4115
|
function normalizeComparableURI(uri, opts) {
|
|
3819
|
-
if (typeof uri
|
|
3820
|
-
|
|
3821
|
-
return malformedAuthorityOrPort ? undefined : normalized;
|
|
4116
|
+
if (typeof uri !== "string" && typeof uri !== "object") {
|
|
4117
|
+
return;
|
|
3822
4118
|
}
|
|
3823
|
-
|
|
3824
|
-
|
|
4119
|
+
let value;
|
|
4120
|
+
try {
|
|
4121
|
+
value = typeof uri === "string" ? uri : serialize(uri, opts);
|
|
4122
|
+
} catch {
|
|
4123
|
+
return;
|
|
3825
4124
|
}
|
|
4125
|
+
const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
|
|
4126
|
+
return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? undefined : normalized;
|
|
3826
4127
|
}
|
|
3827
4128
|
var fastUri = {
|
|
3828
4129
|
SCHEMES,
|
|
@@ -14730,6 +15031,8 @@ var init_zh_Hans = __esm(() => {
|
|
|
14730
15031
|
"attachments.fileTooLarge": "文件过大,无法上传。",
|
|
14731
15032
|
"attachments.fileNotReadable": "无法读取此文件,因此未添加附件。请将文件移动到其他文件夹后重试。",
|
|
14732
15033
|
"attachments.linkToFile": "链接到文件…",
|
|
15034
|
+
"attachments.linkedFileElsewhere": "此链接指向另一台设备上的文件:{{path}}。请在那台设备上打开,或改为直接添加该文件作为附件。",
|
|
15035
|
+
"attachments.openLinkFailed": "无法打开此链接。",
|
|
14733
15036
|
"attachments.invalidFileType": "不支持的文件类型。",
|
|
14734
15037
|
"attachments.invalidLink": "请输入有效的链接。",
|
|
14735
15038
|
"attachments.photoUnavailableTitle": "图片选择不可用",
|
|
@@ -15470,6 +15773,8 @@ var init_zh_Hans = __esm(() => {
|
|
|
15470
15773
|
"settings.syncEncryptionUnlock": "输入密码短语",
|
|
15471
15774
|
"settings.syncEncryptionDecline": "暂不",
|
|
15472
15775
|
"settings.syncEncryptionPausedDesc": "在您输入密码短语之前,本设备的自动同步将保持暂停。",
|
|
15776
|
+
"settings.syncEncryptionLockedRecheckHint": "如果该同步位置已不再存放加密文件,请点按“立即同步”,本设备会重新检查该位置并继续同步。",
|
|
15777
|
+
"settings.syncEncryptionNoEncryptedRemote": "该同步位置已没有加密文件,因此本设备的加密现已关闭。如需加密该位置,请重新开启。",
|
|
15473
15778
|
"settings.syncEncryptionRemoteEncrypted": "此同步位置已加密。请输入其同步密码短语以继续同步。",
|
|
15474
15779
|
"settings.syncEncryptionRemotePlaintext": "同步已停止:此同步位置不再加密。请在此设备上关闭同步加密,或在该同步位置重新启用加密。",
|
|
15475
15780
|
"settings.syncEncryptionRemotePlaintextDesc": "另一台设备在此同步位置关闭了加密。此设备上的内容没有被更改或降级。若要以明文继续同步,请在此设备上关闭同步加密;否则请在该同步位置重新启用加密。",
|
|
@@ -16430,6 +16735,12 @@ App Store 已提供更新,是否立即打开应用页面?`,
|
|
|
16430
16735
|
"settings.syncMobile.accountStatus": "账户状态",
|
|
16431
16736
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "请在 Dropbox OAuth 设置里添加以下精确回调地址。",
|
|
16432
16737
|
"settings.syncMobile.backgroundSync": "后台同步",
|
|
16738
|
+
"settings.syncMobile.backgroundSyncInterval": "后台同步间隔",
|
|
16739
|
+
"settings.syncMobile.backgroundSyncIntervalDescription": "应用关闭期间,系统最多按此间隔运行同步任务。“关闭”表示手机仅在应用打开时、离开应用时以及编辑后不久同步。",
|
|
16740
|
+
"settings.syncMobile.backgroundSyncIntervalEvery15Minutes": "每 15 分钟",
|
|
16741
|
+
"settings.syncMobile.backgroundSyncIntervalEvery6Hours": "每 6 小时",
|
|
16742
|
+
"settings.syncMobile.backgroundSyncIntervalEveryHour": "每小时",
|
|
16743
|
+
"settings.syncMobile.backgroundSyncIntervalOff": "关闭",
|
|
16433
16744
|
"settings.syncMobile.clearPendingAttachmentDeletes": "清除待处理的附件删除?",
|
|
16434
16745
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "这台设备上的 CloudKit 已被限制。请检查屏幕使用时间、设备管理或 iCloud 限制后再试。",
|
|
16435
16746
|
"settings.syncMobile.connectedToDropbox": "已连接 Dropbox。",
|
|
@@ -16517,6 +16828,9 @@ App Store 已提供更新,是否立即打开应用页面?`,
|
|
|
16517
16828
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV 端点可访问。",
|
|
16518
16829
|
"settings.persistentCaptureLabel": "通知栏快速收集",
|
|
16519
16830
|
"settings.persistentCaptureDesc": "保留常驻通知,随时随地(包括锁屏)快速收集。",
|
|
16831
|
+
"settings.exactAlarmsLabel": "提醒可能会延迟",
|
|
16832
|
+
"settings.exactAlarmsDesc": "Android 未允许 Mindwtr 设置精确闹钟,提醒可能会晚一分钟才响起。",
|
|
16833
|
+
"settings.exactAlarmsAllow": "允许",
|
|
16520
16834
|
"settings.appSearchLabel": "在系统搜索中显示",
|
|
16521
16835
|
"settings.appSearchDesc": "允许 Android 系统搜索按标题查找你的活动任务、项目和领域。数据不会离开此设备。",
|
|
16522
16836
|
"captureNotification.title": "快速收集",
|
|
@@ -16851,6 +17165,8 @@ App Store 已提供更新,是否立即打开应用页面?`,
|
|
|
16851
17165
|
"settings.gettingStartedContentContinueDesc": "完成此处的设置后,你仍可添加引导式“快速上手”项目和示例收集箱项目。",
|
|
16852
17166
|
"settings.syncSetupGuideTitle": "数据与同步设置指南",
|
|
16853
17167
|
"settings.syncSetupGuideDesc": "Dropbox、iCloud、WebDAV、文件同步和恢复的设置说明。",
|
|
17168
|
+
"settings.syncEncryptionGuideTitle": "同步加密指南",
|
|
17169
|
+
"settings.syncEncryptionGuideDesc": "它保护什么、哪些服务器支持它,以及口令如何工作。",
|
|
16854
17170
|
"settings.importSetupGuideTitle": "导入设置指南",
|
|
16855
17171
|
"settings.importSetupGuideDesc": "支持 Todoist、TickTick、DGT GTD、OmniFocus、Mindwtr CSV、Apple 提醒事项和备份导入路径。",
|
|
16856
17172
|
"settings.backupDiagnostics.newerVersion": "此备份由较新版本的 Mindwtr({{version}})创建。",
|
|
@@ -16873,7 +17189,7 @@ App Store 已提供更新,是否立即打开应用页面?`,
|
|
|
16873
17189
|
"settings.importDiagnostics.unmappedDate": "{{count}} 个日期值无法转换,已省略。",
|
|
16874
17190
|
"settings.importDiagnostics.unmappedStatus": "{{count}} 个状态值无法转换,已使用安全默认值。",
|
|
16875
17191
|
"settings.importDiagnostics.unsupportedRecurrence": "{{count}} 条不支持的重复规则已保留为备注。",
|
|
16876
|
-
"settings.syncRemoteBusy": "
|
|
17192
|
+
"settings.syncRemoteBusy": "另一台 Mindwtr 设备暂时占用了此同步位置。同步将自动重试。",
|
|
16877
17193
|
"settings.syncRemoteCleanupDeferred": "同步操作已完成。Mindwtr 无法移除临时同步锁,但该锁会自动过期。无需重试。",
|
|
16878
17194
|
"settings.syncAttachmentWriteDeferred": "部分附件更改未能完成。请恢复缺失的本地文件或移除受影响的附件,然后再次同步。",
|
|
16879
17195
|
"settings.syncFileAttachmentTooLarge": "Mindwtr 已保留本地附件。File Sync 只能同步小于 100 MB 的附件。请换用较小的文件或移除该附件,然后再次同步。",
|
|
@@ -17223,6 +17539,8 @@ var init_zh_Hant = __esm(() => {
|
|
|
17223
17539
|
"attachments.fileTooLarge": "文件過大,無法上傳。",
|
|
17224
17540
|
"attachments.fileNotReadable": "無法讀取此文件,因此未加入附件。請將文件移至其他資料夾後再試一次。",
|
|
17225
17541
|
"attachments.linkToFile": "連結到文件…",
|
|
17542
|
+
"attachments.linkedFileElsewhere": "此連結指向另一台裝置上的檔案:{{path}}。請在該裝置上開啟,或改為直接加入該檔案作為附件。",
|
|
17543
|
+
"attachments.openLinkFailed": "無法開啟此連結。",
|
|
17226
17544
|
"attachments.invalidFileType": "不支持的文件類型。",
|
|
17227
17545
|
"attachments.invalidLink": "請輸入有效的鏈接。",
|
|
17228
17546
|
"attachments.photoUnavailableTitle": "圖片選擇不可用",
|
|
@@ -17963,6 +18281,8 @@ var init_zh_Hant = __esm(() => {
|
|
|
17963
18281
|
"settings.syncEncryptionUnlock": "輸入密碼短語",
|
|
17964
18282
|
"settings.syncEncryptionDecline": "暫時不要",
|
|
17965
18283
|
"settings.syncEncryptionPausedDesc": "在您輸入密碼短語之前,本裝置的自動同步會保持暫停。",
|
|
18284
|
+
"settings.syncEncryptionLockedRecheckHint": "如果該同步位置已不再存放加密檔案,請點按「立即同步」,本裝置會重新檢查該位置並繼續同步。",
|
|
18285
|
+
"settings.syncEncryptionNoEncryptedRemote": "該同步位置已沒有加密檔案,因此本裝置的加密現已關閉。如需加密該位置,請重新開啟。",
|
|
17966
18286
|
"settings.syncEncryptionRemoteEncrypted": "此同步位置已加密。請輸入其同步密碼短語以繼續同步。",
|
|
17967
18287
|
"settings.syncEncryptionRemotePlaintext": "同步已停止:此同步位置不再加密。請在此裝置上關閉同步加密,或在該同步位置重新啟用加密。",
|
|
17968
18288
|
"settings.syncEncryptionRemotePlaintextDesc": "另一台裝置在此同步位置關閉了加密。此裝置上的內容沒有被變更或降級。若要以純文字繼續同步,請在此裝置上關閉同步加密;否則請在該同步位置重新啟用加密。",
|
|
@@ -18923,6 +19243,12 @@ App Store 已提供更新,是否立即打開應用頁面?`,
|
|
|
18923
19243
|
"settings.syncMobile.accountStatus": "賬戶狀態",
|
|
18924
19244
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "請在 Dropbox OAuth 設置裡添加以下精確回調地址。",
|
|
18925
19245
|
"settings.syncMobile.backgroundSync": "後臺同步",
|
|
19246
|
+
"settings.syncMobile.backgroundSyncInterval": "後臺同步間隔",
|
|
19247
|
+
"settings.syncMobile.backgroundSyncIntervalDescription": "應用程式關閉期間,系統最多按此間隔執行同步工作。「關閉」表示手機僅在應用程式開啟時、離開應用程式時以及編輯後不久同步。",
|
|
19248
|
+
"settings.syncMobile.backgroundSyncIntervalEvery15Minutes": "每 15 分鐘",
|
|
19249
|
+
"settings.syncMobile.backgroundSyncIntervalEvery6Hours": "每 6 小時",
|
|
19250
|
+
"settings.syncMobile.backgroundSyncIntervalEveryHour": "每小時",
|
|
19251
|
+
"settings.syncMobile.backgroundSyncIntervalOff": "關閉",
|
|
18926
19252
|
"settings.syncMobile.clearPendingAttachmentDeletes": "清除待處理的附件刪除?",
|
|
18927
19253
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "這臺設備上的 CloudKit 已被限制。請檢查屏幕使用時間、設備管理或 iCloud 限制後再試。",
|
|
18928
19254
|
"settings.syncMobile.connectedToDropbox": "已連接 Dropbox。",
|
|
@@ -19010,6 +19336,9 @@ App Store 已提供更新,是否立即打開應用頁面?`,
|
|
|
19010
19336
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV 端點可訪問。",
|
|
19011
19337
|
"settings.persistentCaptureLabel": "通知列快速收集",
|
|
19012
19338
|
"settings.persistentCaptureDesc": "保留常駐通知,隨時隨地(包括鎖定畫面)快速收集。",
|
|
19339
|
+
"settings.exactAlarmsLabel": "提醒可能會延遲",
|
|
19340
|
+
"settings.exactAlarmsDesc": "Android 未允許 Mindwtr 設定精確鬧鐘,提醒可能會晚一分鐘才響起。",
|
|
19341
|
+
"settings.exactAlarmsAllow": "允許",
|
|
19013
19342
|
"settings.appSearchLabel": "在系統搜尋中顯示",
|
|
19014
19343
|
"settings.appSearchDesc": "允許 Android 系統搜尋依標題找到你的進行中任務、專案與領域。資料不會離開此裝置。",
|
|
19015
19344
|
"captureNotification.title": "快速收集",
|
|
@@ -19344,6 +19673,8 @@ App Store 已提供更新,是否立即打開應用頁面?`,
|
|
|
19344
19673
|
"settings.gettingStartedContentContinueDesc": "完成這裡的設定後,你仍可加入引導式「快速上手」專案和範例收集箱項目。",
|
|
19345
19674
|
"settings.syncSetupGuideTitle": "資料與同步設定指南",
|
|
19346
19675
|
"settings.syncSetupGuideDesc": "Dropbox、iCloud、WebDAV、檔案同步和還原的設定說明。",
|
|
19676
|
+
"settings.syncEncryptionGuideTitle": "同步加密指南",
|
|
19677
|
+
"settings.syncEncryptionGuideDesc": "它保護什麼、哪些伺服器支援它,以及密語如何運作。",
|
|
19347
19678
|
"settings.importSetupGuideTitle": "匯入設定指南",
|
|
19348
19679
|
"settings.importSetupGuideDesc": "支援 Todoist、TickTick、DGT GTD、OmniFocus、Mindwtr CSV、Apple 提醒事項和備份匯入路徑。",
|
|
19349
19680
|
"settings.backupDiagnostics.newerVersion": "此備份由較新版本的 Mindwtr({{version}})建立。",
|
|
@@ -19366,7 +19697,7 @@ App Store 已提供更新,是否立即打開應用頁面?`,
|
|
|
19366
19697
|
"settings.importDiagnostics.unmappedDate": "{{count}} 個日期值無法轉換,已省略。",
|
|
19367
19698
|
"settings.importDiagnostics.unmappedStatus": "{{count}} 個狀態值無法轉換,已使用安全預設值。",
|
|
19368
19699
|
"settings.importDiagnostics.unsupportedRecurrence": "{{count}} 條不支援的重複規則已保留為備註。",
|
|
19369
|
-
"settings.syncRemoteBusy": "
|
|
19700
|
+
"settings.syncRemoteBusy": "另一台 Mindwtr 裝置暫時佔用了此同步位置。同步將自動重試。",
|
|
19370
19701
|
"settings.syncRemoteCleanupDeferred": "同步作業已完成。Mindwtr 無法移除暫時同步鎖,但該鎖會自動失效。無需重試。",
|
|
19371
19702
|
"settings.syncAttachmentWriteDeferred": "部分附件變更未能完成。請還原缺少的本機檔案或移除受影響的附件,然後再次同步。",
|
|
19372
19703
|
"settings.syncFileAttachmentTooLarge": "Mindwtr 已保留本機附件。File Sync 只能同步小於 100 MB 的附件。請改用較小的檔案或移除該附件,然後再次同步。",
|
|
@@ -23876,7 +24207,7 @@ var init_de = __esm(() => {
|
|
|
23876
24207
|
"quickAdd.help": 'Schnell hinzufügen unterstützt /start:<when>, /due:<when>, /review:<when>, /note:<text>, /link:<url>, /energy:<level>, /priority:<level>, /next, /area:<name> oder !Area, @context, #tag, +Project, %Person (oder %"Full Name").',
|
|
23877
24208
|
"quickAdd.example": "Beispiel: Mama anrufen /due:tomorrow @phone",
|
|
23878
24209
|
"quickAdd.inlineHint": "Tipp: Mama anrufen /due:tomorrow 5pm @phone #family",
|
|
23879
|
-
"quickAdd.syntaxHelp": "Hilfe zur Schnell-
|
|
24210
|
+
"quickAdd.syntaxHelp": "Hilfe zur Schnell-Hinzufügen-Syntax",
|
|
23880
24211
|
"quickAdd.placeholder": "Eine Aufgabe hinzufügen … benutzen Sie @context +Project #tag",
|
|
23881
24212
|
"quickAdd.inputLabel": "Schnelle Eingabe",
|
|
23882
24213
|
"quickAdd.inputHint": "Geben Sie eine Aufgabe ein und drücken Sie Eingabe zum Speichern.",
|
|
@@ -23917,7 +24248,7 @@ var init_de = __esm(() => {
|
|
|
23917
24248
|
"quickAdd.audioSavingSpeechToText": "Aufnahme wird gespeichert und Sprache in Text umgewandelt.",
|
|
23918
24249
|
"quickAdd.audioNoteTitle": "Sprachnotiz",
|
|
23919
24250
|
"quickAdd.audioPermissionTitle": "Zugriff auf Mikrofon ist notwendig",
|
|
23920
|
-
"quickAdd.audioPermissionBody": "
|
|
24251
|
+
"quickAdd.audioPermissionBody": "Mikrofonzugriff erlauben, um Sprachnotizen aufzunehmen.",
|
|
23921
24252
|
"quickAdd.audioErrorTitle": "Aufnahme fehlgeschlagen",
|
|
23922
24253
|
"quickAdd.audioErrorBody": "Wir konnten nichts aufnehmen. Bitte versuchen Sie es nochmals.",
|
|
23923
24254
|
"quickAdd.invalidDateCommand": "Ungültiger Datumsbefehl",
|
|
@@ -23942,7 +24273,7 @@ var init_de = __esm(() => {
|
|
|
23942
24273
|
"keybindings.section.taskList": "Aufgabenliste",
|
|
23943
24274
|
"keybindings.section.quickAddSyntax": "Schnelleingabe-Syntax",
|
|
23944
24275
|
"keybindings.section.global": "Allgemein",
|
|
23945
|
-
"keybindings.openHelp": "
|
|
24276
|
+
"keybindings.openHelp": "Tastaturkürzel anzeigen",
|
|
23946
24277
|
"keybindings.openSettings": "Einstellungen öffnen",
|
|
23947
24278
|
"keybindings.toggleFullscreen": "Vollbild umschalten",
|
|
23948
24279
|
"keybindings.switchArea": "Bereich wechseln",
|
|
@@ -23987,7 +24318,7 @@ var init_de = __esm(() => {
|
|
|
23987
24318
|
"list.todo": "Zu tun",
|
|
23988
24319
|
"list.inProgress": "In Arbeit",
|
|
23989
24320
|
"list.next": "Nächste Aktionen",
|
|
23990
|
-
"list.someday": "Irgendwann/
|
|
24321
|
+
"list.someday": "Irgendwann/Vielleicht",
|
|
23991
24322
|
"list.reference": "Referenz",
|
|
23992
24323
|
"list.waiting": "Abwarten",
|
|
23993
24324
|
"list.done": "Abgeschlossen",
|
|
@@ -24005,7 +24336,7 @@ var init_de = __esm(() => {
|
|
|
24005
24336
|
"list.densityComfortable": "Komfortabel",
|
|
24006
24337
|
"list.densityCompact": "Kompakt",
|
|
24007
24338
|
"list.densityCondensed": "Verdichtet",
|
|
24008
|
-
"reference.empty": "Noch keine
|
|
24339
|
+
"reference.empty": "Noch keine Referenzeinträge.",
|
|
24009
24340
|
"status.inbox": "Posteingang",
|
|
24010
24341
|
"status.todo": "Zu tun",
|
|
24011
24342
|
"status.next": "Nächstes",
|
|
@@ -24043,7 +24374,7 @@ var init_de = __esm(() => {
|
|
|
24043
24374
|
"taskEdit.duplicateDoneBody": "Es wurde eine neue Kopie im Posteingang erstellt.",
|
|
24044
24375
|
"taskEdit.aiClarify": "Klären mit KI",
|
|
24045
24376
|
"taskEdit.aiBreakdown": "KI-Zusammenfassung",
|
|
24046
|
-
"taskEdit.itemNamePlaceholder": "
|
|
24377
|
+
"taskEdit.itemNamePlaceholder": "Elementname",
|
|
24047
24378
|
"taskEdit.titleLabel": "Titel",
|
|
24048
24379
|
"taskEdit.editorLayoutHelpLabel": "Editor-Layout-Hilfe",
|
|
24049
24380
|
"taskEdit.editorLayoutHelpText": "Du kannst in Einstellungen -> GTD -> Aufgaben-Editor-Layout anpassen, welche Felder hier angezeigt werden.",
|
|
@@ -24076,7 +24407,7 @@ var init_de = __esm(() => {
|
|
|
24076
24407
|
"markdown.collapse": "Zusammenklappen",
|
|
24077
24408
|
"markdown.toolbar.heading": "Titel einfügen",
|
|
24078
24409
|
"markdown.toolbar.bold": "Fett",
|
|
24079
|
-
"markdown.toolbar.italic": "
|
|
24410
|
+
"markdown.toolbar.italic": "Kursiv",
|
|
24080
24411
|
"markdown.toolbar.strikethrough": "Durchgestrichen",
|
|
24081
24412
|
"markdown.toolbar.bulletList": "Punkteliste",
|
|
24082
24413
|
"markdown.toolbar.horizontalRule": "Horizontale Linie",
|
|
@@ -24093,7 +24424,7 @@ var init_de = __esm(() => {
|
|
|
24093
24424
|
"attachments.downloadConflict": "Dieser Anhang wurde während des Downloads geändert. Die lokale Datei wurde beibehalten. Synchronisiere erneut, um den Konflikt zu lösen.",
|
|
24094
24425
|
"attachments.unrecoverable": "Dieser Anhang ist im synchronisierten Speicher nicht mehr verfügbar. Der ungültige Verweis wurde entfernt.",
|
|
24095
24426
|
"attachments.remove": "Entfernen",
|
|
24096
|
-
"attachments.transferProgress": "Fortschritt der
|
|
24427
|
+
"attachments.transferProgress": "Fortschritt der Übertragung von Anhängen",
|
|
24097
24428
|
"attachments.linkPlaceholder": "https://beispiel.com",
|
|
24098
24429
|
"attachments.linkInputHint": 'Tipp: eine URL einfügen, oder "Titel | URL" benutzen.',
|
|
24099
24430
|
"attachments.attachObsidianNote": "Obsidian-Notiz anhängen",
|
|
@@ -24103,12 +24434,12 @@ var init_de = __esm(() => {
|
|
|
24103
24434
|
"attachments.fileTooLarge": "Die Datei ist zu groß für das Hochladen.",
|
|
24104
24435
|
"attachments.fileNotReadable": "Diese Datei konnte nicht gelesen werden und wurde daher nicht angehängt. Verschiebe sie in einen anderen Ordner und versuche es erneut.",
|
|
24105
24436
|
"attachments.linkToFile": "Mit Datei verknüpfen…",
|
|
24106
|
-
"attachments.invalidFileType": "Nicht unterstützter
|
|
24437
|
+
"attachments.invalidFileType": "Nicht unterstützter Dateityp.",
|
|
24107
24438
|
"attachments.invalidLink": "Bitte eine gültige URL angeben.",
|
|
24108
|
-
"attachments.photoUnavailableTitle": "
|
|
24439
|
+
"attachments.photoUnavailableTitle": "Fotoauswahl ist nicht verfügbar",
|
|
24109
24440
|
"attachments.photoUnavailableBody": "Die App neu erstellen, um Fotoanhänge zu ermöglichen.",
|
|
24110
24441
|
"taskEdit.locationLabel": "Standort",
|
|
24111
|
-
"taskEdit.locationPlaceholder": "z.B. Büro",
|
|
24442
|
+
"taskEdit.locationPlaceholder": "z. B. Büro",
|
|
24112
24443
|
"taskEdit.projectLabel": "Projekt",
|
|
24113
24444
|
"taskEdit.noProjectOption": "Kein Projekt",
|
|
24114
24445
|
"taskEdit.sectionLabel": "Abschnitt",
|
|
@@ -24118,7 +24449,7 @@ var init_de = __esm(() => {
|
|
|
24118
24449
|
"taskEdit.moreOptions": "Mehr Optionen",
|
|
24119
24450
|
"taskEdit.hideOptions": "Optionen verstecken",
|
|
24120
24451
|
"taskEdit.startDateLabel": "Anfangsdatum",
|
|
24121
|
-
"taskEdit.dueDateLabel": "
|
|
24452
|
+
"taskEdit.dueDateLabel": "Fälligkeitsdatum",
|
|
24122
24453
|
"taskEdit.reviewDateLabel": "Revisions-Datum",
|
|
24123
24454
|
"taskEdit.dateOnly": "Nur Datum",
|
|
24124
24455
|
"taskEdit.startModeLabel": "Startmodus",
|
|
@@ -24195,16 +24526,16 @@ var init_de = __esm(() => {
|
|
|
24195
24526
|
"recurrence.ordinal.second": "Zweiten",
|
|
24196
24527
|
"recurrence.ordinal.third": "Dritten",
|
|
24197
24528
|
"recurrence.ordinal.fourth": "Vierten",
|
|
24198
|
-
"recurrence.ordinal.last": "
|
|
24529
|
+
"recurrence.ordinal.last": "Letzten",
|
|
24199
24530
|
"recurrence.monthlyOnDay": "Der gleiche Tag jeden Monats",
|
|
24200
24531
|
"recurrence.monthlyOnLastWeekday": "Letzter {weekday}",
|
|
24201
|
-
"recurrence.strategyLabel": "
|
|
24532
|
+
"recurrence.strategyLabel": "Strategisch",
|
|
24202
24533
|
"recurrence.strategyStrict": "Strikt",
|
|
24203
24534
|
"recurrence.strategyFluid": "Fliessend",
|
|
24204
|
-
"recurrence.strategyStrictDesc": "Fällig am geplanten Datum (z.B. Rechnungen)",
|
|
24205
|
-
"recurrence.strategyFluidDesc": "Fällig nach Abschluss (z.B. Wäsche)",
|
|
24206
|
-
"recurrence.afterCompletion": "Nach
|
|
24207
|
-
"recurrence.afterCompletionShort": "Nach
|
|
24535
|
+
"recurrence.strategyStrictDesc": "Fällig am geplanten Datum (z. B. Rechnungen)",
|
|
24536
|
+
"recurrence.strategyFluidDesc": "Fällig nach Abschluss (z. B. Wäsche)",
|
|
24537
|
+
"recurrence.afterCompletion": "Nach Abschluss wiederholen",
|
|
24538
|
+
"recurrence.afterCompletionShort": "Nach Abschluss",
|
|
24208
24539
|
"recurrence.showFutureInCalendar": "Künftige Wiederholungen im Kalender anzeigen",
|
|
24209
24540
|
"recurrence.showFutureInCalendarHint": "Nur Planungsvorschau; die nächste echte Aufgabe wird erst erstellt, wenn diese abgeschlossen wird.",
|
|
24210
24541
|
"inbox.title": "Posteingang",
|
|
@@ -24218,7 +24549,7 @@ var init_de = __esm(() => {
|
|
|
24218
24549
|
"inbox.refineHint": "Präzisiere den Titel und die Details, bevor Sie entscheiden, was als Nächstes getan werden soll.",
|
|
24219
24550
|
"inbox.refineNext": "Nächstes",
|
|
24220
24551
|
"inbox.refineDelete": "Löschen",
|
|
24221
|
-
"inbox.isActionable": "Ist
|
|
24552
|
+
"inbox.isActionable": "Ist diese ausführbar?",
|
|
24222
24553
|
"inbox.actionableHint": "Können Sie eine physische Handlung ausführen?",
|
|
24223
24554
|
"inbox.yes": "Ja",
|
|
24224
24555
|
"inbox.no": "Nein",
|
|
@@ -24239,7 +24570,7 @@ var init_de = __esm(() => {
|
|
|
24239
24570
|
"inbox.addContextPlaceholder": "Neuen Kontext hinzufügen ...",
|
|
24240
24571
|
"inbox.waitingQuestion": "Auf wen oder was warten Sie?",
|
|
24241
24572
|
"inbox.waitingHint": "Fügen Sie eine Notiz hinzu, um sich zu erinnern, auf was Sie warten",
|
|
24242
|
-
"inbox.waitingPlaceholder": "Z.B. Auf Jonathan's Revision warten ...",
|
|
24573
|
+
"inbox.waitingPlaceholder": "Z. B. Auf Jonathan's Revision warten ...",
|
|
24243
24574
|
"inbox.assignProjectQuestion": "Zu einem Projekt hinzufügen? (Optional)",
|
|
24244
24575
|
"inbox.noProject": "Kein Projekt",
|
|
24245
24576
|
"inbox.skip": "Überspringen",
|
|
@@ -24251,7 +24582,7 @@ var init_de = __esm(() => {
|
|
|
24251
24582
|
"next.noTasks": "Keine Aufgaben in Zu Tun. Fügen Sie sie in den Posteingang ein und verarbeiten Sie diese zuerst.",
|
|
24252
24583
|
"next.noContext": "Keine Nächsten Aktionen mit",
|
|
24253
24584
|
"next.warningCount": "Elemente in Nächste Aktionen",
|
|
24254
|
-
"next.warningHint": "Überlegen Sie sich, sich auf weniger Projekte zu
|
|
24585
|
+
"next.warningHint": "Überlegen Sie sich, sich auf weniger Projekte zu konzentrieren. GTD empfiehlt, höchstens 10-15 Elemente in Nächste Aktionen zu lassen für eine besser Übersicht.",
|
|
24255
24586
|
"contexts.title": "Kontexte",
|
|
24256
24587
|
"contexts.filter": "Aufgaben nach Kontexten filtern",
|
|
24257
24588
|
"filters.label": "Filter",
|
|
@@ -24281,7 +24612,7 @@ var init_de = __esm(() => {
|
|
|
24281
24612
|
"filters.noMatch": " Diesem Filter entsprechen keine Aufgaben.",
|
|
24282
24613
|
"contexts.all": "Alle Kontexte",
|
|
24283
24614
|
"contexts.none": "Keine Kontexte",
|
|
24284
|
-
"contexts.noContexts": "Keine Kontexte gefunden. Fügen Sie Ihren Aufgaben Kontexte wie z.B. @home, @work, @computer hinzu.",
|
|
24615
|
+
"contexts.noContexts": "Keine Kontexte gefunden. Fügen Sie Ihren Aufgaben Kontexte wie z. B. @home, @work, @computer hinzu.",
|
|
24285
24616
|
"contexts.noTasks": "Keine aktiven Aufgaben für diesen Kontext",
|
|
24286
24617
|
"board.title": "Tafelansicht",
|
|
24287
24618
|
"board.next": "Nächste Aktionen",
|
|
@@ -24289,11 +24620,11 @@ var init_de = __esm(() => {
|
|
|
24289
24620
|
"board.inProgress": "In Arbeit",
|
|
24290
24621
|
"board.done": "Erledigt",
|
|
24291
24622
|
"board.noTasks": "Keine Aufgaben",
|
|
24292
|
-
"board.hint": "Halten zum Verschieben •
|
|
24623
|
+
"board.hint": "Halten zum Verschieben • Zum Löschen nach links wischen",
|
|
24293
24624
|
"board.dragTask": "Aufgabe verschieben",
|
|
24294
24625
|
"board.delete": "Löschen",
|
|
24295
24626
|
"calendar.title": "Kalender",
|
|
24296
|
-
"calendar.addTask": "Neue Aufgabe
|
|
24627
|
+
"calendar.addTask": "Neue Aufgabe hinzufügen ...",
|
|
24297
24628
|
"calendar.schedulePlaceholder": "Aufgaben suchen zum Einplanen ...",
|
|
24298
24629
|
"calendar.scheduleResults": "Zeitplan",
|
|
24299
24630
|
"calendar.scheduleAction": "Zeitplan",
|
|
@@ -24351,10 +24682,10 @@ var init_de = __esm(() => {
|
|
|
24351
24682
|
"project.notes": "Projektnotizen",
|
|
24352
24683
|
"projects.notesPlaceholder": "Kontexte, Pläne oder Referenzen zu diesem Projekt hinzufügen ...",
|
|
24353
24684
|
"projects.sectionNotes": "Abschnitts-Notizen",
|
|
24354
|
-
"projects.sectionNotesPlaceholder": "Notizen zu diesem Abschnitt
|
|
24355
|
-
"projects.reviewAt": "
|
|
24685
|
+
"projects.sectionNotesPlaceholder": "Notizen zu diesem Abschnitt hinzufügen ...",
|
|
24686
|
+
"projects.reviewAt": "Revisionsdatum",
|
|
24356
24687
|
"projects.areaLabel": "Bereich",
|
|
24357
|
-
"projects.areaPlaceholder": "Z.B. Arbeit",
|
|
24688
|
+
"projects.areaPlaceholder": "Z. B. Arbeit",
|
|
24358
24689
|
"projects.sectionsLabel": "Abschnitte",
|
|
24359
24690
|
"projects.addSection": "Abschnitt hinzufügen",
|
|
24360
24691
|
"projects.sectionPlaceholder": "Titel für den Abschnitt",
|
|
@@ -24407,7 +24738,7 @@ var init_de = __esm(() => {
|
|
|
24407
24738
|
"dailyReview.todayStep": "Heute & Kalender",
|
|
24408
24739
|
"dailyReview.todayDesc": "Überprüfen, was heute ansteht und welche Verpflichtungen im Kalender stehen.",
|
|
24409
24740
|
"dailyReview.focusStep": "Heutiger Fokus",
|
|
24410
|
-
"dailyReview.focusDesc": "
|
|
24741
|
+
"dailyReview.focusDesc": "Optional: Aufgaben markieren, die heute im Fokus sichtbar bleiben sollen.",
|
|
24411
24742
|
"dailyReview.inboxStep": "Posteingang verarbeiten",
|
|
24412
24743
|
"dailyReview.inboxDesc": "Neue Eingaben klären in der Rechte-Liste.",
|
|
24413
24744
|
"dailyReview.waitingStep": "Warten auf",
|
|
@@ -24430,9 +24761,9 @@ var init_de = __esm(() => {
|
|
|
24430
24761
|
"review.calendarStep": "Kalender-Revision",
|
|
24431
24762
|
"review.calendarStepDesc": "Revidieren Sie Ihren Kalender für die nächste 7 Tage.",
|
|
24432
24763
|
"review.past14": "Letzte 14 Tage",
|
|
24433
|
-
"review.past14Desc": "Revidieren Sie Ihren Kalender für die
|
|
24764
|
+
"review.past14Desc": "Revidieren Sie Ihren Kalender für die letzten zwei Wochen. Haben Sie irgendetwas vermisst? Benötigen irgendwelche abgeschlossen Termine eine nachfolgende Aktion?",
|
|
24434
24765
|
"review.upcoming14": "Nächste 7 Tage",
|
|
24435
|
-
"review.upcoming14Desc": "Schauen Sie auf die nächste Woche. Auf
|
|
24766
|
+
"review.upcoming14Desc": "Schauen Sie auf die nächste Woche. Auf was müssen Sie sich vorbereiten? Erfassen Sie alle neuen nächsten Aktionen.",
|
|
24436
24767
|
"review.waitingStep": "Warten auf",
|
|
24437
24768
|
"review.waitingStepDesc": "Verfolgen Sie die delegierten Aufgaben.",
|
|
24438
24769
|
"review.waitingHint": "Revidieren Sie diese Elemente. Haben Sie erhalten, auf was Sie warten? Müssen Sie eine Erinnerung absenden?",
|
|
@@ -24442,8 +24773,8 @@ var init_de = __esm(() => {
|
|
|
24442
24773
|
"review.staleStep": "Liegengebliebene Aufgaben",
|
|
24443
24774
|
"review.staleStepDesc": "Keine Aktivität in letzter Zeit. Aktualisieren, abschließen oder loslassen.",
|
|
24444
24775
|
"review.staleDaysInactive": "{{days}} Tage inaktiv",
|
|
24445
|
-
"review.advanceWeek": "In
|
|
24446
|
-
"review.advanceWeekDone": "Nächste Durchsicht in
|
|
24776
|
+
"review.advanceWeek": "In einer Woche prüfen",
|
|
24777
|
+
"review.advanceWeekDone": "Nächste Durchsicht in einer Woche",
|
|
24447
24778
|
"review.aiStep": "KI-Einblick",
|
|
24448
24779
|
"review.aiStepDesc": "Veraltete Elemente hervorheben und Bereinigungsvorschläge anzeigen.",
|
|
24449
24780
|
"review.aiTitle": "KI-Revision",
|
|
@@ -24451,14 +24782,14 @@ var init_de = __esm(() => {
|
|
|
24451
24782
|
"review.aiRunning": "Analysieren ...",
|
|
24452
24783
|
"review.aiEmpty": "Keine veralteten Elemente gefunden.",
|
|
24453
24784
|
"review.aiApply": "Ausgewählte anwenden",
|
|
24454
|
-
"review.aiAction.someday": "Nach
|
|
24785
|
+
"review.aiAction.someday": "Nach Irgendwann verschieben",
|
|
24455
24786
|
"review.aiAction.archive": "Archiv",
|
|
24456
24787
|
"review.aiAction.breakdown": "Benötigt eine Aufschlüsselung",
|
|
24457
24788
|
"review.aiAction.keep": "Behalten",
|
|
24458
24789
|
"review.notDueYet": "Noch nicht fällig",
|
|
24459
24790
|
"review.projectsStep": "Projekte revidieren",
|
|
24460
24791
|
"review.projectsStepDesc": "Sicherstellen, dass jedes aktive Projekt eine nächste Aktion enthält.",
|
|
24461
|
-
"review.projectsHint": "Jedes Projekt revidieren.
|
|
24792
|
+
"review.projectsHint": "Jedes Projekt revidieren. Enthält es zumindest eine konkrete nächste Aktion? Wenn nicht, Fügen Sie jetzt eine hinzu. Markieren Sie abgeschlossen Projekte als erledigt.",
|
|
24462
24793
|
"review.hasNextAction": "Enthält eine nächste Aktion",
|
|
24463
24794
|
"review.needsAction": "Benötigt eine nächste Aktion",
|
|
24464
24795
|
"review.noActiveTasks": "Keine aktiven Aufgaben",
|
|
@@ -24469,7 +24800,7 @@ var init_de = __esm(() => {
|
|
|
24469
24800
|
"review.allDone": "Alles erledigt!",
|
|
24470
24801
|
"review.allDoneDesc": "Sie sind für bereit für die kommende Woche.",
|
|
24471
24802
|
"review.complete": "Revision abgeschlossen!",
|
|
24472
|
-
"review.completeDesc": "Sie habe Ihren Posteingang abgeklärt, Ihre Listen aktualisiert und sind bereit, Ihre Arbeit zu
|
|
24803
|
+
"review.completeDesc": "Sie habe Ihren Posteingang abgeklärt, Ihre Listen aktualisiert und sind bereit, Ihre Arbeit zu beginnen.",
|
|
24473
24804
|
"review.summaryInboxEmpty": "Eingang ist leer",
|
|
24474
24805
|
"review.summaryInboxCount": "{{count}} Element(e) noch im Eingang",
|
|
24475
24806
|
"review.summaryProjectsOk": "Jedes aktive Projekt hat eine nächste Aktion",
|
|
@@ -24512,10 +24843,10 @@ var init_de = __esm(() => {
|
|
|
24512
24843
|
"process.nextStepDesc": "Sollen Sie es tun oder an jemanden delegieren?",
|
|
24513
24844
|
"process.doIt": "\uD83D\uDCCB Ich werde es selber erledigen",
|
|
24514
24845
|
"process.delegate": "Delegieren",
|
|
24515
|
-
"process.delegateTitle": "
|
|
24846
|
+
"process.delegateTitle": "Delegieren",
|
|
24516
24847
|
"process.delegateDesc": "Optional: Notieren Sie, wer beteiligt ist, und einen Termin für die Weiterverfolgung.",
|
|
24517
24848
|
"process.delegateWhoLabel": "Wer? (Optional)",
|
|
24518
|
-
"process.delegateWhoPlaceholder": "Z.B. Alex",
|
|
24849
|
+
"process.delegateWhoPlaceholder": "Z. B. Alex",
|
|
24519
24850
|
"process.delegateFollowUpLabel": "Weiterverfolgungs-Termin (Optional)",
|
|
24520
24851
|
"process.delegateSendRequest": "Anfrage senden ...",
|
|
24521
24852
|
"process.delegateMoveToWaiting": "Nach Warten verschieben",
|
|
@@ -24526,7 +24857,7 @@ var init_de = __esm(() => {
|
|
|
24526
24857
|
"process.ifNotActionable": "Wenn es nicht ausführbar ist:",
|
|
24527
24858
|
"process.waitingFor": "Auf wen oder was warten Sie?",
|
|
24528
24859
|
"process.waitingForDesc": "Fügen Sie eine Notiz hinzu, um sich zu erinnern, auf was Sie warten",
|
|
24529
|
-
"process.waitingPlaceholder": "Z.B. Auf Jonathan's Revision des Dokumentes warten ...",
|
|
24860
|
+
"process.waitingPlaceholder": "Z. B. Auf Jonathan's Revision des Dokumentes warten ...",
|
|
24530
24861
|
"process.next": "Nächste",
|
|
24531
24862
|
"process.noContext": "Kein Kontext",
|
|
24532
24863
|
"process.project": "Zu einem Projekt hinzufügen?",
|
|
@@ -24576,7 +24907,7 @@ var init_de = __esm(() => {
|
|
|
24576
24907
|
"settings.calendarSystemJalali": "Jalali (Sonnen-Hidschra)",
|
|
24577
24908
|
"settings.keybindingsDesc": "Tastaturbelegung-Stil für den Desktop auswählen.",
|
|
24578
24909
|
"settings.closeBehaviorDesc": "Wählen Sie, was beim Schließen des Fensters passieren soll.",
|
|
24579
|
-
"settings.closeBehaviorAsk": "
|
|
24910
|
+
"settings.closeBehaviorAsk": "Jedes Mal fragen",
|
|
24580
24911
|
"settings.closeBehaviorTray": "Im Taskbereich weiterlaufen lassen",
|
|
24581
24912
|
"settings.closeBehaviorQuit": "Die App schließen",
|
|
24582
24913
|
"settings.closeBehaviorPromptTitle": "Mindwtr schließen?",
|
|
@@ -24715,14 +25046,14 @@ var init_de = __esm(() => {
|
|
|
24715
25046
|
"settings.aiApiKeyPlaceholder": "API-Schlüssel einfügen",
|
|
24716
25047
|
"settings.speechTitle": "Sprache zu Text",
|
|
24717
25048
|
"settings.speechDesc": "Sprachaufnahmen transkribieren und sie in Aufgabenfelder einteilen.",
|
|
24718
|
-
"settings.speechEnable": "Sprache zu Text
|
|
25049
|
+
"settings.speechEnable": "Sprache zu Text aktivieren",
|
|
24719
25050
|
"settings.speechProvider": "Spracherkennungs-Provider",
|
|
24720
25051
|
"settings.speechProviderOffline": "Auf dem Gerät (Whisper)",
|
|
24721
25052
|
"settings.speechModel": "Sprachmodell",
|
|
24722
25053
|
"settings.speechBaseUrl": "Transkriptionsserver-URL",
|
|
24723
25054
|
"settings.speechBaseUrlHint": "Für offizielles OpenAI leer lassen. Für einen selbst gehosteten OpenAI-kompatiblen Transkriptionsserver festlegen. API-Schlüssel optional.",
|
|
24724
25055
|
"settings.speechOfflineModel": "Offline Modell",
|
|
24725
|
-
"settings.speechOfflineModelDesc": "Einmal
|
|
25056
|
+
"settings.speechOfflineModelDesc": "Einmal herunterladen, um dann völlig offline zu transkribieren.",
|
|
24726
25057
|
"settings.speechOfflineReady": "Modell heruntergeladen",
|
|
24727
25058
|
"settings.speechOfflineNotDownloaded": "Modell nicht heruntergeladen",
|
|
24728
25059
|
"settings.speechOfflineDownload": "Herunterladen",
|
|
@@ -24732,13 +25063,13 @@ var init_de = __esm(() => {
|
|
|
24732
25063
|
"settings.speechOfflineDeleteError": "Offline-Modell löschen ist fehlgeschlagen",
|
|
24733
25064
|
"settings.speechOfflineDeleteErrorBody": "Bitte nochmals versuchen.",
|
|
24734
25065
|
"settings.speechLanguage": "Audio-Sprache",
|
|
24735
|
-
"settings.speechLanguageHint": "Einen
|
|
25066
|
+
"settings.speechLanguageHint": "Einen Sprachnamen oder Code angeben, oder frei lassen zur automatischen Bestimmung.",
|
|
24736
25067
|
"settings.speechLanguageAuto": "Automatisch (Sprache bestimmen)",
|
|
24737
25068
|
"settings.speechMode": "Verarbeitungs-Modus",
|
|
24738
|
-
"settings.speechModeHint": "Smart parse extrahiert automatisch Felder und Daten; Nur
|
|
24739
|
-
"settings.speechModeTranscript": "Nur
|
|
25069
|
+
"settings.speechModeHint": "'Smart parse' extrahiert automatisch Felder und Daten; 'Nur Transkribieren' transkribiert lediglich.",
|
|
25070
|
+
"settings.speechModeTranscript": "Nur Transkribieren",
|
|
24740
25071
|
"settings.speechFieldStrategy": "Felder bestimmen",
|
|
24741
|
-
"settings.speechFieldStrategyHint": "Auswählen, wo die
|
|
25072
|
+
"settings.speechFieldStrategyHint": "Auswählen, wo die Transkription standardmäßig gespeichert werden soll.",
|
|
24742
25073
|
"settings.speechFieldTitle": "Titel",
|
|
24743
25074
|
"settings.speechFieldDescription": "Beschreibung",
|
|
24744
25075
|
"settings.aiReasoning": "Begründungsaufwand",
|
|
@@ -24899,8 +25230,8 @@ var init_de = __esm(() => {
|
|
|
24899
25230
|
"sort.label": "Sortieren",
|
|
24900
25231
|
"sort.default": "Standard",
|
|
24901
25232
|
"sort.due": "Fälligkeitsdatum",
|
|
24902
|
-
"sort.start": "
|
|
24903
|
-
"sort.review": "
|
|
25233
|
+
"sort.start": "Beginndatum",
|
|
25234
|
+
"sort.review": "Revisionsdatum",
|
|
24904
25235
|
"sort.title": "Titel",
|
|
24905
25236
|
"sort.timeEstimate": "Zeitabschätzung",
|
|
24906
25237
|
"sort.created": "Älteste",
|
|
@@ -24923,7 +25254,7 @@ var init_de = __esm(() => {
|
|
|
24923
25254
|
"agenda.focusHint": "Tippen Sie auf den Stern irgendeiner untenstehenden Aufgabe, um sie zum heutigen Fokus hinzuzufügen (max. 3).",
|
|
24924
25255
|
"agenda.addToFocus": "Zum heutigen Fokus hinzufügen",
|
|
24925
25256
|
"agenda.removeFromFocus": "Aus dem Fokus entfernen",
|
|
24926
|
-
"agenda.maxFocusItems": "Max.
|
|
25257
|
+
"agenda.maxFocusItems": "Max. {{count}} Fokus-Element(e)",
|
|
24927
25258
|
"agenda.inProgress": "In Arbeit",
|
|
24928
25259
|
"agenda.overdue": "Überfällig",
|
|
24929
25260
|
"agenda.dueToday": "Heute fällig",
|
|
@@ -24953,7 +25284,7 @@ var init_de = __esm(() => {
|
|
|
24953
25284
|
"waiting.moveToNext": "Nach Nächste verschieben",
|
|
24954
25285
|
"waiting.markDone": "Als Erledigt markieren",
|
|
24955
25286
|
"waiting.empty": "Es gibt nichts, worauf Sie warten müssten",
|
|
24956
|
-
"waiting.emptyHint": "
|
|
25287
|
+
"waiting.emptyHint": "Speichern Sie Aufgaben hier, wenn der nächste Schritt bei jemand anderem liegt – Sie werden sie sehen, bis sie erledigt sind",
|
|
24957
25288
|
"someday.title": "Irgendwann/Vielleicht",
|
|
24958
25289
|
"someday.subtitle": "Ideen und Ziele, die Sie in Zukunft vielleicht verfolgen möchten",
|
|
24959
25290
|
"someday.ideas": "Ideen",
|
|
@@ -24961,7 +25292,7 @@ var init_de = __esm(() => {
|
|
|
24961
25292
|
"someday.moveToNext": "Zu Nächste verschieben",
|
|
24962
25293
|
"someday.archive": "Archiv",
|
|
24963
25294
|
"someday.empty": "Keine Irgendwann/Vielleicht-Elemente",
|
|
24964
|
-
"someday.emptyHint": "
|
|
25295
|
+
"someday.emptyHint": "Sammeln Sie hier Ideen und Ziele, die Sie vielleicht später verfolgen möchten – aus dem Blickfeld, aber nicht aus dem Kopf verlieren",
|
|
24965
25296
|
"search.title": "Suchen",
|
|
24966
25297
|
"search.placeholder": "Aufgaben and Projekte suchen ...",
|
|
24967
25298
|
"search.scopeHint": "Aufgaben, Projekte, Personen",
|
|
@@ -24974,10 +25305,10 @@ var init_de = __esm(() => {
|
|
|
24974
25305
|
"search.showingFirst": "Zeigt {shown} von {total} Ergebnissen",
|
|
24975
25306
|
"search.saveSearch": "Diese Suchabfrage speichern",
|
|
24976
25307
|
"search.saveSearchPrompt": "Diese Suchabfrage benennen",
|
|
24977
|
-
"search.savedSearches": "
|
|
25308
|
+
"search.savedSearches": "Suchabfrage gespeichert",
|
|
24978
25309
|
"search.noSavedSearches": "Noch keine gespeicherte Suchabfragen.",
|
|
24979
25310
|
"search.deleteConfirm": "Diese gespeicherte Suchabfrage löschen?",
|
|
24980
|
-
"search.helpOperators": "Sie können Operatoren benutzen wie z.B. status:, context:, tag:, project:, due:<=7d.",
|
|
25311
|
+
"search.helpOperators": "Sie können Operatoren benutzen wie z. B. status:, context:, tag:, project:, due:<=7d.",
|
|
24981
25312
|
"search.hiddenCompletedMatches": "{{count}} weitere in Erledigt und Archiviert",
|
|
24982
25313
|
"search.completedDate": "Abgeschlossen {{date}}",
|
|
24983
25314
|
"search.dueDate": "Fällig {{date}}",
|
|
@@ -25046,7 +25377,7 @@ var init_de = __esm(() => {
|
|
|
25046
25377
|
"settings.sync": "Synchronisieren",
|
|
25047
25378
|
"settings.syncDescription": "Richten Sie einen sekundären Ordner ein, mit dem Ihre Daten synchronisiert werden sollen (z. B. Dropbox, Syncthing). Für eine nahezu in Echtzeit erfolgende Synchronisierung auf mehreren Geräten wird WebDAV gegenüber Ordnersynchronisierungstools empfohlen.",
|
|
25048
25379
|
"settings.attachmentsCleanup": "Bereinigung von Anhängen",
|
|
25049
|
-
"settings.attachmentsCleanupDesc": "Entfernen Sie gelöschte oder verwaiste
|
|
25380
|
+
"settings.attachmentsCleanupDesc": "Entfernen Sie gelöschte oder verwaiste Anhänge von Ihrem Gerät und synchronisieren Sie den Speicher.",
|
|
25050
25381
|
"settings.attachmentsCleanupLastRun": "Letzte Bereinigung",
|
|
25051
25382
|
"settings.attachmentsCleanupNever": "Nie",
|
|
25052
25383
|
"settings.attachmentsCleanupRun": "Führen Sie die Bereinigung durch",
|
|
@@ -25075,7 +25406,7 @@ var init_de = __esm(() => {
|
|
|
25075
25406
|
"settings.cloudProviderDropbox": "Dropbox",
|
|
25076
25407
|
"settings.dropboxAppKey": "Dropbox-Konto",
|
|
25077
25408
|
"settings.dropboxAppKeyHint": "Der Dropbox-App-Schlüssel wird zum Zeitpunkt der Erstellung/Veröffentlichung eingefügt.",
|
|
25078
|
-
"settings.dropboxRedirectUri": "
|
|
25409
|
+
"settings.dropboxRedirectUri": "Redirect-URI",
|
|
25079
25410
|
"settings.dropboxConnected": "Verbunden",
|
|
25080
25411
|
"settings.dropboxNotConnected": "Nicht verbunden",
|
|
25081
25412
|
"settings.dropboxConnect": "Dropbox verbinden",
|
|
@@ -25128,7 +25459,7 @@ var init_de = __esm(() => {
|
|
|
25128
25459
|
"settings.downloadStarting": "Download wird geöffnet ...",
|
|
25129
25460
|
"settings.downloadStarted": "Der Download wurde in Ihrem Browser gestartet.",
|
|
25130
25461
|
"settings.downloadFailed": "Der Download-Link konnte nicht geöffnet werden.",
|
|
25131
|
-
"settings.downloadChecksumMismatch": "Die
|
|
25462
|
+
"settings.downloadChecksumMismatch": "Die Überprüfung der Prüfsumme ist fehlgeschlagen. Bitte laden Sie die Datei erneut von der Release-Seite herunter.",
|
|
25132
25463
|
"settings.downloadRecommended": "Empfohlenes Paket",
|
|
25133
25464
|
"settings.downloadAURHint": "Arch erkannt: Aktualisierung über AUR",
|
|
25134
25465
|
"settings.changelog": "Änderungsprotokoll",
|
|
@@ -27153,6 +27484,8 @@ var init_ja = __esm(() => {
|
|
|
27153
27484
|
"attachments.fileTooLarge": "ファイルが大きすぎてアップロードできません。",
|
|
27154
27485
|
"attachments.fileNotReadable": "このファイルを読み取れなかったため添付できませんでした。別のフォルダに移してからもう一度お試しください。",
|
|
27155
27486
|
"attachments.linkToFile": "ファイルへのリンク…",
|
|
27487
|
+
"attachments.linkedFileElsewhere": "このリンクは別のデバイス上のファイルを指しています: {{path}}。そのデバイスで開くか、リンクではなくファイルを添付してください。",
|
|
27488
|
+
"attachments.openLinkFailed": "このリンクを開けませんでした。",
|
|
27156
27489
|
"attachments.invalidFileType": "対応していないファイル形式です。",
|
|
27157
27490
|
"attachments.invalidLink": "有効な URL を入力してください。",
|
|
27158
27491
|
"attachments.photoUnavailableTitle": "写真の選択が利用できません",
|
|
@@ -27948,6 +28281,8 @@ var init_ja = __esm(() => {
|
|
|
27948
28281
|
"settings.syncEncryptionUnlock": "パスフレーズを入力",
|
|
27949
28282
|
"settings.syncEncryptionDecline": "後で",
|
|
27950
28283
|
"settings.syncEncryptionPausedDesc": "パスフレーズを入力するまで、この端末の自動同期は停止したままになります。",
|
|
28284
|
+
"settings.syncEncryptionLockedRecheckHint": "この同期先に暗号化されたファイルがもうない場合は、「今すぐ同期」をタップしてください。この端末が同期先を再確認して続行します。",
|
|
28285
|
+
"settings.syncEncryptionNoEncryptedRemote": "この同期先には暗号化されたファイルがなくなったため、この端末の暗号化はオフになりました。この場所を暗号化するには、もう一度オンにしてください。",
|
|
27951
28286
|
"settings.syncEncryptionRemoteEncrypted": "この同期先は暗号化されています。同期を続けるには、同期パスフレーズを入力してください。",
|
|
27952
28287
|
"settings.syncEncryptionRemotePlaintext": "同期を停止しました: この同期先はもう暗号化されていません。このデバイスで同期の暗号化をオフにするか、同期先で暗号化をもう一度オンにしてください。",
|
|
27953
28288
|
"settings.syncEncryptionRemotePlaintextDesc": "別のデバイスがこの同期先の暗号化をオフにしました。この端末側では何も変更も解除もされていません。平文のまま同期を続けるにはこのデバイスで同期の暗号化をオフにし、そうでなければ同期先で暗号化をもう一度オンにしてください。",
|
|
@@ -28897,6 +29232,12 @@ App Store に更新があります。アプリのページを開きますか?`
|
|
|
28897
29232
|
"settings.syncMobile.accountStatus": "アカウントの状態",
|
|
28898
29233
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "Dropbox の OAuth 設定に、このリダイレクト URI をそのまま登録してください。",
|
|
28899
29234
|
"settings.syncMobile.backgroundSync": "バックグラウンド同期",
|
|
29235
|
+
"settings.syncMobile.backgroundSyncInterval": "バックグラウンド同期の間隔",
|
|
29236
|
+
"settings.syncMobile.backgroundSyncIntervalDescription": "アプリを閉じている間、システムはこの間隔より頻繁には実行しません。「オフ」にすると、アプリを開いているとき、アプリを離れたとき、編集直後のみ同期します。",
|
|
29237
|
+
"settings.syncMobile.backgroundSyncIntervalEvery15Minutes": "15分ごと",
|
|
29238
|
+
"settings.syncMobile.backgroundSyncIntervalEvery6Hours": "6時間ごと",
|
|
29239
|
+
"settings.syncMobile.backgroundSyncIntervalEveryHour": "1時間ごと",
|
|
29240
|
+
"settings.syncMobile.backgroundSyncIntervalOff": "オフ",
|
|
28900
29241
|
"settings.syncMobile.clearPendingAttachmentDeletes": "保留中の添付ファイル削除を取り消しますか?",
|
|
28901
29242
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "この端末では CloudKit が制限されています。スクリーンタイム、MDM、iCloud の制限を確認してから、もう一度お試しください。",
|
|
28902
29243
|
"settings.syncMobile.connectedToDropbox": "Dropbox に接続しました。",
|
|
@@ -28984,6 +29325,9 @@ App Store に更新があります。アプリのページを開きますか?`
|
|
|
28984
29325
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV のエンドポイントに接続できました。",
|
|
28985
29326
|
"settings.persistentCaptureLabel": "通知バーからクイックキャプチャ",
|
|
28986
29327
|
"settings.persistentCaptureDesc": "常駐する通知を表示して、ロック画面を含めどこからでも書き留められるようにします。",
|
|
29328
|
+
"settings.exactAlarmsLabel": "リマインダーが遅れる可能性があります",
|
|
29329
|
+
"settings.exactAlarmsDesc": "Android が Mindwtr に正確なアラームを許可していないため、リマインダーが最大 1 分遅れることがあります。",
|
|
29330
|
+
"settings.exactAlarmsAllow": "許可",
|
|
28987
29331
|
"settings.appSearchLabel": "システム検索に表示する",
|
|
28988
29332
|
"settings.appSearchDesc": "Android のシステム検索から、進行中のタスク・プロジェクト・エリアをタイトルで探せるようにします。データが端末の外に出ることはありません。",
|
|
28989
29333
|
"captureNotification.title": "クイックキャプチャ",
|
|
@@ -29318,6 +29662,8 @@ App Store に更新があります。アプリのページを開きますか?`
|
|
|
29318
29662
|
"settings.gettingStartedContentContinueDesc": "ここでの作業が終わったあとでも、ガイド付きの「はじめかた」プロジェクトとサンプルのインボックス項目を追加できます。",
|
|
29319
29663
|
"settings.syncSetupGuideTitle": "データと同期の設定ガイド",
|
|
29320
29664
|
"settings.syncSetupGuideDesc": "Dropbox・iCloud・WebDAV・フォルダ同期・復旧についての手引き。",
|
|
29665
|
+
"settings.syncEncryptionGuideTitle": "同期の暗号化ガイド",
|
|
29666
|
+
"settings.syncEncryptionGuideDesc": "何を保護するか、対応するサーバー、パスフレーズの仕組み。",
|
|
29321
29667
|
"settings.importSetupGuideTitle": "読み込みの設定ガイド",
|
|
29322
29668
|
"settings.importSetupGuideDesc": "Todoist・TickTick・DGT GTD・OmniFocus・Mindwtr CSV・Apple リマインダー・バックアップからの読み込み方法。",
|
|
29323
29669
|
"settings.backupDiagnostics.newerVersion": "このバックアップは、より新しいバージョンの Mindwtr({{version}})で作成されています。",
|
|
@@ -29340,7 +29686,7 @@ App Store に更新があります。アプリのページを開きますか?`
|
|
|
29340
29686
|
"settings.importDiagnostics.unmappedDate": "{{count}}件の日付は対応づけられなかったため、取り込みませんでした。",
|
|
29341
29687
|
"settings.importDiagnostics.unmappedStatus": "{{count}}件のステータスは対応づけられなかったため、安全な既定値を使いました。",
|
|
29342
29688
|
"settings.importDiagnostics.unsupportedRecurrence": "対応していない繰り返しルール{{count}}件は、メモとして残しました。",
|
|
29343
|
-
"settings.syncRemoteBusy": "
|
|
29689
|
+
"settings.syncRemoteBusy": "別の Mindwtr デバイスがこの同期先を一時的に確保しています。同期は自動的に再試行されます。",
|
|
29344
29690
|
"settings.syncRemoteCleanupDeferred": "同期処理は完了しました。Mindwtr は一時的な同期ロックを削除できませんでしたが、ロックは自動的に期限切れになります。再試行は不要です。",
|
|
29345
29691
|
"settings.syncAttachmentWriteDeferred": "一部の添付ファイルの変更を完了できませんでした。不足しているローカルファイルを復元するか、該当する添付ファイルを削除してから、もう一度同期してください。",
|
|
29346
29692
|
"settings.syncFileAttachmentTooLarge": "Mindwtr はローカルの添付ファイルを保持しました。File Sync で同期できる添付ファイルは 100 MB 未満です。小さいファイルに置き換えるか添付ファイルを削除してから、もう一度同期してください。",
|
|
@@ -37098,6 +37444,8 @@ var init_ko = __esm(() => {
|
|
|
37098
37444
|
"attachments.fileTooLarge": "파일이 너무 커서 업로드할 수 없습니다.",
|
|
37099
37445
|
"attachments.fileNotReadable": "이 파일을 읽을 수 없어 첨부되지 않았습니다. 파일을 다른 폴더로 옮긴 뒤 다시 시도하세요.",
|
|
37100
37446
|
"attachments.linkToFile": "파일에 연결…",
|
|
37447
|
+
"attachments.linkedFileElsewhere": "이 링크는 다른 기기에 있는 파일을 가리킵니다: {{path}}. 해당 기기에서 열거나, 링크 대신 파일 자체를 첨부하세요.",
|
|
37448
|
+
"attachments.openLinkFailed": "이 링크를 열 수 없습니다.",
|
|
37101
37449
|
"attachments.invalidFileType": "지원되지 않는 파일 형식입니다.",
|
|
37102
37450
|
"attachments.invalidLink": "유효한 URL을 입력하세요.",
|
|
37103
37451
|
"attachments.photoUnavailableTitle": "사진 선택 도구를 사용할 수 없습니다.",
|
|
@@ -38721,6 +39069,9 @@ App Store에 업데이트가 있습니다. 지금 앱 목록을 여시겠습니
|
|
|
38721
39069
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV 엔드포인트에 접근할 수 있습니다.",
|
|
38722
39070
|
"settings.persistentCaptureLabel": "알림 표시줄에서 빠른 수집",
|
|
38723
39071
|
"settings.persistentCaptureDesc": "잠금 화면을 포함해 어디서나 수집할 수 있는 고정 알림을 유지합니다.",
|
|
39072
|
+
"settings.exactAlarmsLabel": "알림이 늦게 도착할 수 있습니다",
|
|
39073
|
+
"settings.exactAlarmsDesc": "Android가 Mindwtr에 정확한 알람을 허용하지 않아 알림이 최대 1분까지 늦게 울릴 수 있습니다.",
|
|
39074
|
+
"settings.exactAlarmsAllow": "허용",
|
|
38724
39075
|
"settings.appSearchLabel": "시스템 검색에 노출",
|
|
38725
39076
|
"settings.appSearchDesc": "Android 시스템 검색이 제목으로 활성 작업, 프로젝트, 영역을 찾을 수 있게 합니다. 어떤 데이터도 이 기기를 벗어나지 않습니다.",
|
|
38726
39077
|
"captureNotification.title": "빠른 수집",
|
|
@@ -43188,6 +43539,8 @@ var init_fa = __esm(() => {
|
|
|
43188
43539
|
"attachments.fileTooLarge": "حجم فایل برای بارگذاری زیاد است.",
|
|
43189
43540
|
"attachments.fileNotReadable": "این فایل خوانده نشد، بنابراین پیوست نگردید. آن را به پوشه دیگری منتقل کرده و دوباره امتحان کنید.",
|
|
43190
43541
|
"attachments.linkToFile": "پیوند به فایل…",
|
|
43542
|
+
"attachments.linkedFileElsewhere": "این پیوند به فایلی روی دستگاه دیگری اشاره میکند: {{path}}. آن را همانجا باز کنید یا بهجای پیوند، خود فایل را پیوست کنید.",
|
|
43543
|
+
"attachments.openLinkFailed": "باز کردن این پیوند ممکن نبود.",
|
|
43191
43544
|
"attachments.invalidFileType": "نوع فایل پشتیبانی نمیشود.",
|
|
43192
43545
|
"attachments.invalidLink": "لطفاً یک آدرس معتبر وارد کنید.",
|
|
43193
43546
|
"attachments.photoUnavailableTitle": "انتخابگر عکس در دسترس نیست",
|
|
@@ -43982,6 +44335,8 @@ var init_fa = __esm(() => {
|
|
|
43982
44335
|
"settings.syncEncryptionUnlock": "وارد کردن عبارت عبور",
|
|
43983
44336
|
"settings.syncEncryptionDecline": "فعلاً نه",
|
|
43984
44337
|
"settings.syncEncryptionPausedDesc": "تا زمانی که عبارت عبور را وارد نکنید، همگامسازی خودکار روی این دستگاه متوقف میماند.",
|
|
44338
|
+
"settings.syncEncryptionLockedRecheckHint": "اگر این مکان همگامسازی دیگر فایل رمزگذاریشده ندارد، «همگامسازی اکنون» را بزنید؛ این دستگاه دوباره آن را بررسی میکند و ادامه میدهد.",
|
|
44339
|
+
"settings.syncEncryptionNoEncryptedRemote": "دیگر هیچ فایل رمزگذاریشدهای در این مکان همگامسازی وجود ندارد، بنابراین رمزگذاری روی این دستگاه اکنون خاموش است. برای رمزگذاری این مکان دوباره آن را روشن کنید.",
|
|
43985
44340
|
"settings.syncEncryptionRemoteEncrypted": "این محل همگامسازی رمزگذاری شده است. برای ادامه همگامسازی، عبارت عبور آن را وارد کنید.",
|
|
43986
44341
|
"settings.syncEncryptionRemotePlaintext": "همگامسازی متوقف شد: این محل همگامسازی دیگر رمزگذاریشده نیست. رمزگذاری همگامسازی را در این دستگاه خاموش کنید یا دوباره در محل همگامسازی روشن کنید.",
|
|
43987
44342
|
"settings.syncEncryptionRemotePlaintextDesc": "دستگاه دیگری رمزگذاری را در این محل همگامسازی خاموش کرده است. هیچ چیزی در اینجا تغییر نکرده و از رمزگذاری خارج نشده است. برای ادامهٔ همگامسازی به شکل ساده، رمزگذاری همگامسازی را در این دستگاه خاموش کنید، یا رمزگذاری را دوباره در محل همگامسازی روشن کنید.",
|
|
@@ -44931,6 +45286,12 @@ var init_fa = __esm(() => {
|
|
|
44931
45286
|
"settings.syncMobile.accountStatus": "وضعیت حساب",
|
|
44932
45287
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "دقیقاً همین آدرس بازگشت را در تنظیمات OAuth Dropbox اضافه کنید.",
|
|
44933
45288
|
"settings.syncMobile.backgroundSync": "همگامسازی پسزمینه",
|
|
45289
|
+
"settings.syncMobile.backgroundSyncInterval": "بازه همگامسازی پسزمینه",
|
|
45290
|
+
"settings.syncMobile.backgroundSyncIntervalDescription": "سیستم این کار را حداکثر با این بازه، درحالیکه برنامه بسته است، اجرا میکند. خاموش یعنی گوشی فقط وقتی برنامه باز است، وقتی آن را ترک میکنید و کمی پس از ویرایشها همگامسازی میشود.",
|
|
45291
|
+
"settings.syncMobile.backgroundSyncIntervalEvery15Minutes": "هر ۱۵ دقیقه",
|
|
45292
|
+
"settings.syncMobile.backgroundSyncIntervalEvery6Hours": "هر ۶ ساعت",
|
|
45293
|
+
"settings.syncMobile.backgroundSyncIntervalEveryHour": "هر ساعت",
|
|
45294
|
+
"settings.syncMobile.backgroundSyncIntervalOff": "خاموش",
|
|
44934
45295
|
"settings.syncMobile.clearPendingAttachmentDeletes": "حذفهای در انتظار پیوست پاک شوند؟",
|
|
44935
45296
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "CloudKit روی این دستگاه محدود شده است. Screen Time، MDM یا محدودیتهای iCloud را بررسی کرده و دوباره امتحان کنید.",
|
|
44936
45297
|
"settings.syncMobile.connectedToDropbox": "به Dropbox متصل شد.",
|
|
@@ -45018,6 +45379,9 @@ var init_fa = __esm(() => {
|
|
|
45018
45379
|
"settings.syncMobile.webdavEndpointIsReachable": "نقطه پایانی WebDAV در دسترس است.",
|
|
45019
45380
|
"settings.persistentCaptureLabel": "ثبت سریع در نوار اعلان",
|
|
45020
45381
|
"settings.persistentCaptureDesc": "یک اعلان پایدار برای ثبت از هر جا، از جمله صفحه قفل، نگه دار.",
|
|
45382
|
+
"settings.exactAlarmsLabel": "یادآورها ممکن است دیر برسند",
|
|
45383
|
+
"settings.exactAlarmsDesc": "اندروید به Mindwtr اجازهی تنظیم زنگ دقیق نمیدهد، بنابراین یادآورها ممکن است تا یک دقیقه دیرتر اجرا شوند.",
|
|
45384
|
+
"settings.exactAlarmsAllow": "اجازه بده",
|
|
45021
45385
|
"settings.appSearchLabel": "نمایش در جستجوی سیستم",
|
|
45022
45386
|
"settings.appSearchDesc": "به جستجوی سیستم اندروید اجازه بده کارها، پروژهها و حوزههای فعال شما را بر اساس عنوان پیدا کند. هیچ دادهای از این دستگاه خارج نمیشود.",
|
|
45023
45387
|
"captureNotification.title": "ثبت سریع",
|
|
@@ -45352,6 +45716,8 @@ var init_fa = __esm(() => {
|
|
|
45352
45716
|
"settings.gettingStartedContentContinueDesc": "پس از پایان کار در اینجا نیز میتوانید پروژه راهنمای «شروع کار» و موارد نمونه صندوق ورودی را اضافه کنید.",
|
|
45353
45717
|
"settings.syncSetupGuideTitle": "راهنمای راهاندازی داده و همگامسازی",
|
|
45354
45718
|
"settings.syncSetupGuideDesc": "نکات راهاندازی برای Dropbox، iCloud، WebDAV، همگامسازی فایل و بازیابی.",
|
|
45719
|
+
"settings.syncEncryptionGuideTitle": "راهنمای رمزگذاری همگامسازی",
|
|
45720
|
+
"settings.syncEncryptionGuideDesc": "چه چیزی را محافظت میکند، کدام سرورها از آن پشتیبانی میکنند و عبارت عبور چگونه کار میکند.",
|
|
45355
45721
|
"settings.importSetupGuideTitle": "راهنمای راهاندازی واردکردن",
|
|
45356
45722
|
"settings.importSetupGuideDesc": "روشهای واردکردن پشتیبانیشده برای Todoist، TickTick، DGT GTD، OmniFocus، Mindwtr CSV، یادآورهای Apple و نسخههای پشتیبان.",
|
|
45357
45723
|
"settings.backupDiagnostics.newerVersion": "این نسخه پشتیبان با نسخه جدیدتری از Mindwtr ({{version}}) ساخته شده است.",
|
|
@@ -45374,7 +45740,7 @@ var init_fa = __esm(() => {
|
|
|
45374
45740
|
"settings.importDiagnostics.unmappedDate": "{{count}} مقدار تاریخ قابل تبدیل نبود و حذف شد.",
|
|
45375
45741
|
"settings.importDiagnostics.unmappedStatus": "{{count}} مقدار وضعیت قابل تبدیل نبود و مقدار پیشفرض امن استفاده شد.",
|
|
45376
45742
|
"settings.importDiagnostics.unsupportedRecurrence": "{{count}} قانون تکرار پشتیبانینشده بهصورت یادداشت نگه داشته شد.",
|
|
45377
|
-
"settings.syncRemoteBusy": "
|
|
45743
|
+
"settings.syncRemoteBusy": "دستگاه Mindwtr دیگری این مکان همگامسازی را برای لحظهای در اختیار دارد. همگامسازی بهطور خودکار دوباره تلاش میکند.",
|
|
45378
45744
|
"settings.syncRemoteCleanupDeferred": "عملیات همگامسازی کامل شد. Mindwtr نتوانست قفل موقت همگامسازی را حذف کند، اما این قفل خودکار منقضی میشود. نیازی به تلاش دوباره نیست.",
|
|
45379
45745
|
"settings.syncAttachmentWriteDeferred": "برخی تغییرات پیوستها کامل نشد. فایلهای محلی گمشده را بازیابی کنید یا پیوستهای مربوط را حذف کنید، سپس دوباره همگامسازی کنید.",
|
|
45380
45746
|
"settings.syncFileAttachmentTooLarge": "Mindwtr پیوست محلی را نگه داشت. File Sync فقط میتواند پیوستهای کوچکتر از ۱۰۰ مگابایت را همگامسازی کند. آن را با فایل کوچکتری جایگزین کنید یا پیوست را حذف کنید، سپس دوباره همگامسازی کنید.",
|
|
@@ -45681,6 +46047,8 @@ var init_sv = __esm(() => {
|
|
|
45681
46047
|
"attachments.fileTooLarge": "Filen är för stor för att laddas upp.",
|
|
45682
46048
|
"attachments.fileNotReadable": "Kunde inte läsa filen, så den bifogades inte. Flytta den till en annan mapp och försök igen.",
|
|
45683
46049
|
"attachments.linkToFile": "Länk till fil…",
|
|
46050
|
+
"attachments.linkedFileElsewhere": "Den här länken pekar på en fil på en annan enhet: {{path}}. Öppna den där, eller bifoga filen i stället för att länka till den.",
|
|
46051
|
+
"attachments.openLinkFailed": "Kunde inte öppna den här länken.",
|
|
45684
46052
|
"attachments.invalidFileType": "Filtypen stöds inte.",
|
|
45685
46053
|
"attachments.invalidLink": "Ange en giltig URL.",
|
|
45686
46054
|
"attachments.photoUnavailableTitle": "Bildväljaren är inte tillgänglig",
|
|
@@ -46475,6 +46843,8 @@ var init_sv = __esm(() => {
|
|
|
46475
46843
|
"settings.syncEncryptionUnlock": "Ange lösenfras",
|
|
46476
46844
|
"settings.syncEncryptionDecline": "Inte nu",
|
|
46477
46845
|
"settings.syncEncryptionPausedDesc": "Automatisk synkronisering är pausad på den här enheten tills du anger lösenfrasen.",
|
|
46846
|
+
"settings.syncEncryptionLockedRecheckHint": "Om den här synkroniseringsplatsen inte längre innehåller krypterade filer trycker du på Synka nu. Enheten kontrollerar platsen på nytt och fortsätter.",
|
|
46847
|
+
"settings.syncEncryptionNoEncryptedRemote": "Det finns inga krypterade filer kvar på den här synkroniseringsplatsen, så krypteringen är nu av på den här enheten. Slå på den igen för att kryptera platsen.",
|
|
46478
46848
|
"settings.syncEncryptionRemoteEncrypted": "Den här synkplatsen är krypterad. Ange synklösenfrasen för att fortsätta synka.",
|
|
46479
46849
|
"settings.syncEncryptionRemotePlaintext": "Synkningen stoppades: den här synkplatsen är inte längre krypterad. Stäng av synkkryptering på den här enheten, eller slå på den igen på synkplatsen.",
|
|
46480
46850
|
"settings.syncEncryptionRemotePlaintextDesc": "En annan enhet stängde av krypteringen på den här synkplatsen. Ingenting här har ändrats eller nedgraderats. Stäng av synkkryptering på den här enheten för att fortsätta synka i klartext, eller slå på krypteringen igen på synkplatsen.",
|
|
@@ -47424,6 +47794,12 @@ En uppdatering finns i App Store. Öppna appsidan nu?`,
|
|
|
47424
47794
|
"settings.syncMobile.accountStatus": "Kontostatus",
|
|
47425
47795
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "Lägg till exakt den här omdirigerings-URI:n i Dropboxs OAuth-inställningar.",
|
|
47426
47796
|
"settings.syncMobile.backgroundSync": "Bakgrundssynk",
|
|
47797
|
+
"settings.syncMobile.backgroundSyncInterval": "Intervall för bakgrundssynk",
|
|
47798
|
+
"settings.syncMobile.backgroundSyncIntervalDescription": "Systemet kör jobbet högst så här ofta medan appen är stängd. Av innebär att telefonen bara synkar när appen är öppen, när du lämnar den och strax efter ändringar.",
|
|
47799
|
+
"settings.syncMobile.backgroundSyncIntervalEvery15Minutes": "Var 15:e minut",
|
|
47800
|
+
"settings.syncMobile.backgroundSyncIntervalEvery6Hours": "Var 6:e timme",
|
|
47801
|
+
"settings.syncMobile.backgroundSyncIntervalEveryHour": "Varje timme",
|
|
47802
|
+
"settings.syncMobile.backgroundSyncIntervalOff": "Av",
|
|
47427
47803
|
"settings.syncMobile.clearPendingAttachmentDeletes": "Rensa väntande bilageborttagningar?",
|
|
47428
47804
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "CloudKit är begränsat på den här enheten. Kontrollera Skärmtid, MDM eller iCloud-begränsningar, och försök sedan igen.",
|
|
47429
47805
|
"settings.syncMobile.connectedToDropbox": "Ansluten till Dropbox.",
|
|
@@ -47511,6 +47887,9 @@ En uppdatering finns i App Store. Öppna appsidan nu?`,
|
|
|
47511
47887
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV-slutpunkten är nåbar.",
|
|
47512
47888
|
"settings.persistentCaptureLabel": "Snabbinspelning i aviseringsfältet",
|
|
47513
47889
|
"settings.persistentCaptureDesc": "Behåll en beständig avisering för att spela in varifrån som helst, inklusive låsskärmen.",
|
|
47890
|
+
"settings.exactAlarmsLabel": "Påminnelser kan komma sent",
|
|
47891
|
+
"settings.exactAlarmsDesc": "Android låter inte Mindwtr ställa in exakta alarm, så påminnelser kan komma upp till en minut för sent.",
|
|
47892
|
+
"settings.exactAlarmsAllow": "Tillåt",
|
|
47514
47893
|
"settings.appSearchLabel": "Exponera för systemsökning",
|
|
47515
47894
|
"settings.appSearchDesc": "Låt Androids systemsökning hitta dina aktiva uppgifter, projekt och områden via titel. Inget lämnar den här enheten.",
|
|
47516
47895
|
"captureNotification.title": "Snabbinspelning",
|
|
@@ -47845,6 +48224,8 @@ En uppdatering finns i App Store. Öppna appsidan nu?`,
|
|
|
47845
48224
|
"settings.gettingStartedContentContinueDesc": "När du är klar här kan du fortfarande lägga till det guidade Kom igång-projektet och exempelposter i inkorgen.",
|
|
47846
48225
|
"settings.syncSetupGuideTitle": "Guide för data- och synkroniseringsinställning",
|
|
47847
48226
|
"settings.syncSetupGuideDesc": "Inställningsanteckningar för Dropbox, iCloud, WebDAV, filsynkronisering och återställning.",
|
|
48227
|
+
"settings.syncEncryptionGuideTitle": "Guide till synkroniseringskryptering",
|
|
48228
|
+
"settings.syncEncryptionGuideDesc": "Vad den skyddar, vilka servrar som stöder den och hur lösenfrasen fungerar.",
|
|
47848
48229
|
"settings.importSetupGuideTitle": "Guide för importinställning",
|
|
47849
48230
|
"settings.importSetupGuideDesc": "Importvägar som stöds för Todoist, TickTick, DGT GTD, OmniFocus, Mindwtr CSV, Apple Påminnelser och säkerhetskopior.",
|
|
47850
48231
|
"settings.backupDiagnostics.newerVersion": "Den här säkerhetskopian skapades med en nyare version av Mindwtr ({{version}}).",
|
|
@@ -47867,7 +48248,7 @@ En uppdatering finns i App Store. Öppna appsidan nu?`,
|
|
|
47867
48248
|
"settings.importDiagnostics.unmappedDate": "{{count}} datumvärden kunde inte mappas och utelämnades.",
|
|
47868
48249
|
"settings.importDiagnostics.unmappedStatus": "{{count}} statusvärden kunde inte mappas; ett säkert standardvärde användes.",
|
|
47869
48250
|
"settings.importDiagnostics.unsupportedRecurrence": "{{count}} upprepningsregler som inte stöds sparades som anteckningar.",
|
|
47870
|
-
"settings.syncRemoteBusy": "En annan
|
|
48251
|
+
"settings.syncRemoteBusy": "En annan Mindwtr-enhet håller den här synkroniseringsplatsen en kort stund. Synkroniseringen försöker igen av sig själv.",
|
|
47871
48252
|
"settings.syncRemoteCleanupDeferred": "Synkroniseringen slutfördes. Mindwtr kunde inte ta bort det tillfälliga synkroniseringslåset, men det upphör automatiskt. Du behöver inte försöka igen.",
|
|
47872
48253
|
"settings.syncAttachmentWriteDeferred": "Vissa ändringar av bilagor kunde inte slutföras. Återställ saknade lokala filer eller ta bort de berörda bilagorna och synkronisera sedan igen.",
|
|
47873
48254
|
"settings.syncFileAttachmentTooLarge": "Mindwtr behöll den lokala bilagan. File Sync kan bara synkronisera bilagor som är mindre än 100 MB. Ersätt den med en mindre fil eller ta bort bilagan och synkronisera igen.",
|
|
@@ -48030,7 +48411,7 @@ var init_i18n_locales = __esm(() => {
|
|
|
48030
48411
|
mode: "overrides",
|
|
48031
48412
|
native: "한국어",
|
|
48032
48413
|
nonLatin: true,
|
|
48033
|
-
translatedKeyFloor:
|
|
48414
|
+
translatedKeyFloor: 2240
|
|
48034
48415
|
},
|
|
48035
48416
|
it: {
|
|
48036
48417
|
loadSync: () => (init_it(), __toCommonJS(exports_it)),
|
|
@@ -48297,7 +48678,9 @@ var init_settings_options = __esm(() => {
|
|
|
48297
48678
|
});
|
|
48298
48679
|
|
|
48299
48680
|
// ../../packages/core/src/async-utils.ts
|
|
48300
|
-
var
|
|
48681
|
+
var sleepBypass = null, setSleepBypass = (predicate) => {
|
|
48682
|
+
sleepBypass = predicate;
|
|
48683
|
+
}, sleep = (ms) => sleepBypass?.() ? Promise.resolve() : new Promise((resolve) => setTimeout(resolve, ms)), decodeUriSafe = (value) => {
|
|
48301
48684
|
try {
|
|
48302
48685
|
return decodeURIComponent(value);
|
|
48303
48686
|
} catch {
|
|
@@ -67433,11 +67816,14 @@ var DEFAULT_TIMEOUT_MS = 30000, SYNC_LOCAL_INSECURE_URL_OPTIONS, isAbortError =
|
|
|
67433
67816
|
onProgress(offset, total);
|
|
67434
67817
|
}
|
|
67435
67818
|
});
|
|
67436
|
-
}, NO_REDIRECT_METHODS, fetchWithTimeoutAndConsume = async (url, init, timeoutMs, fetcher, timeoutMessage, consume) => {
|
|
67819
|
+
}, NO_REDIRECT_METHODS, SUSPENDED_REQUEST_MESSAGE = "the request was interrupted while the app was suspended", SUSPENDED_REQUEST_FACTOR = 3, fetchWithTimeoutAndConsume = async (url, init, timeoutMs, fetcher, timeoutMessage, consume) => {
|
|
67437
67820
|
const abortController = typeof AbortController === "function" ? new AbortController : null;
|
|
67438
67821
|
let didTimeout = false;
|
|
67822
|
+
let firedAfterSuspension = false;
|
|
67823
|
+
const startedAt = Date.now();
|
|
67439
67824
|
const timeoutId = abortController ? setTimeout(() => {
|
|
67440
67825
|
didTimeout = true;
|
|
67826
|
+
firedAfterSuspension = Date.now() - startedAt > timeoutMs * SUSPENDED_REQUEST_FACTOR;
|
|
67441
67827
|
abortController.abort(createAbortError(timeoutMessage));
|
|
67442
67828
|
}, timeoutMs) : null;
|
|
67443
67829
|
const signal = abortController?.signal ?? init.signal ?? undefined;
|
|
@@ -67472,7 +67858,7 @@ var DEFAULT_TIMEOUT_MS = 30000, SYNC_LOCAL_INSECURE_URL_OPTIONS, isAbortError =
|
|
|
67472
67858
|
} catch (error2) {
|
|
67473
67859
|
if (isAbortError(error2)) {
|
|
67474
67860
|
if (didTimeout) {
|
|
67475
|
-
throw new Error(timeoutMessage);
|
|
67861
|
+
throw new Error(firedAfterSuspension ? `${timeoutMessage}; ${SUSPENDED_REQUEST_MESSAGE}` : timeoutMessage);
|
|
67476
67862
|
}
|
|
67477
67863
|
if (externalSignal?.aborted) {
|
|
67478
67864
|
throw getAbortSignalReason(externalSignal, "Request cancelled");
|
|
@@ -71986,6 +72372,8 @@ var init_en = __esm(() => {
|
|
|
71986
72372
|
"attachments.fileTooLarge": "File is too large to upload.",
|
|
71987
72373
|
"attachments.fileNotReadable": "Couldn't read this file, so it was not attached. Move it to a different folder and try again.",
|
|
71988
72374
|
"attachments.linkToFile": "Link to file…",
|
|
72375
|
+
"attachments.linkedFileElsewhere": "This link points to a file on another device: {{path}}. Open it there, or attach the file instead of linking it.",
|
|
72376
|
+
"attachments.openLinkFailed": "Could not open this link.",
|
|
71989
72377
|
"attachments.invalidFileType": "Unsupported file type.",
|
|
71990
72378
|
"attachments.invalidLink": "Please enter a valid URL.",
|
|
71991
72379
|
"attachments.photoUnavailableTitle": "Photo picker unavailable",
|
|
@@ -72781,6 +73169,8 @@ var init_en = __esm(() => {
|
|
|
72781
73169
|
"settings.syncEncryptionUnlock": "Enter passphrase",
|
|
72782
73170
|
"settings.syncEncryptionDecline": "Not now",
|
|
72783
73171
|
"settings.syncEncryptionPausedDesc": "Automatic sync stays paused on this device until you enter the passphrase.",
|
|
73172
|
+
"settings.syncEncryptionLockedRecheckHint": "If this sync location no longer holds encrypted files, tap Sync now. This device re-checks the location and carries on.",
|
|
73173
|
+
"settings.syncEncryptionNoEncryptedRemote": "There are no encrypted files at this sync location any more, so encryption is now off on this device. Turn it on again to encrypt this location.",
|
|
72784
73174
|
"settings.syncEncryptionRemoteEncrypted": "This sync location is encrypted. Enter its sync passphrase to continue syncing.",
|
|
72785
73175
|
"settings.syncEncryptionRemotePlaintext": "Sync stopped: this sync location is no longer encrypted. Turn sync encryption off on this device, or turn it back on at the sync location.",
|
|
72786
73176
|
"settings.syncEncryptionRemotePlaintextDesc": "Another device turned encryption off at this sync location. Nothing here has been changed or downgraded. Turn sync encryption off on this device to keep syncing in plain form, or turn encryption back on at the sync location.",
|
|
@@ -73730,6 +74120,12 @@ Update is available on the App Store. Open app listing now?`,
|
|
|
73730
74120
|
"settings.syncMobile.accountStatus": "Account status",
|
|
73731
74121
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "Add this exact redirect URI in Dropbox OAuth settings.",
|
|
73732
74122
|
"settings.syncMobile.backgroundSync": "Background sync",
|
|
74123
|
+
"settings.syncMobile.backgroundSyncInterval": "Background sync interval",
|
|
74124
|
+
"settings.syncMobile.backgroundSyncIntervalDescription": "The system runs the job at most this often while the app is closed. Off means the phone syncs only while the app is open, when you leave it, and shortly after edits.",
|
|
74125
|
+
"settings.syncMobile.backgroundSyncIntervalEvery15Minutes": "Every 15 minutes",
|
|
74126
|
+
"settings.syncMobile.backgroundSyncIntervalEvery6Hours": "Every 6 hours",
|
|
74127
|
+
"settings.syncMobile.backgroundSyncIntervalEveryHour": "Every hour",
|
|
74128
|
+
"settings.syncMobile.backgroundSyncIntervalOff": "Off",
|
|
73733
74129
|
"settings.syncMobile.clearPendingAttachmentDeletes": "Clear pending attachment deletes?",
|
|
73734
74130
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "CloudKit is restricted on this device. Check Screen Time, MDM, or iCloud restrictions, then try again.",
|
|
73735
74131
|
"settings.syncMobile.connectedToDropbox": "Connected to Dropbox.",
|
|
@@ -73817,6 +74213,9 @@ Update is available on the App Store. Open app listing now?`,
|
|
|
73817
74213
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV endpoint is reachable.",
|
|
73818
74214
|
"settings.persistentCaptureLabel": "Quick capture in notification bar",
|
|
73819
74215
|
"settings.persistentCaptureDesc": "Keep a persistent notification to capture from anywhere, including the lock screen.",
|
|
74216
|
+
"settings.exactAlarmsLabel": "Reminders may arrive late",
|
|
74217
|
+
"settings.exactAlarmsDesc": "Android is not letting Mindwtr set exact alarms, so reminders can fire up to a minute late.",
|
|
74218
|
+
"settings.exactAlarmsAllow": "Allow",
|
|
73820
74219
|
"settings.appSearchLabel": "Expose to system search",
|
|
73821
74220
|
"settings.appSearchDesc": "Let Android system search find your active tasks, projects, and areas by title. Nothing leaves this device.",
|
|
73822
74221
|
"captureNotification.title": "Quick capture",
|
|
@@ -74151,6 +74550,8 @@ Update is available on the App Store. Open app listing now?`,
|
|
|
74151
74550
|
"settings.gettingStartedContentContinueDesc": "When you are done here, you can still add the guided Getting Started project and sample inbox items.",
|
|
74152
74551
|
"settings.syncSetupGuideTitle": "Data & Sync setup guide",
|
|
74153
74552
|
"settings.syncSetupGuideDesc": "Setup notes for Dropbox, iCloud, WebDAV, File Sync, and recovery.",
|
|
74553
|
+
"settings.syncEncryptionGuideTitle": "Sync encryption guide",
|
|
74554
|
+
"settings.syncEncryptionGuideDesc": "What it protects, which servers support it, and how the passphrase works.",
|
|
74154
74555
|
"settings.importSetupGuideTitle": "Import setup guide",
|
|
74155
74556
|
"settings.importSetupGuideDesc": "Supported Todoist, TickTick, DGT GTD, OmniFocus, Mindwtr CSV, Apple Reminders, and backup import paths.",
|
|
74156
74557
|
"settings.backupDiagnostics.newerVersion": "This backup was created by a newer Mindwtr version ({{version}}).",
|
|
@@ -74173,7 +74574,7 @@ Update is available on the App Store. Open app listing now?`,
|
|
|
74173
74574
|
"settings.importDiagnostics.unmappedDate": "{{count}} date value(s) could not be mapped and were omitted.",
|
|
74174
74575
|
"settings.importDiagnostics.unmappedStatus": "{{count}} status value(s) could not be mapped and used a safe default.",
|
|
74175
74576
|
"settings.importDiagnostics.unsupportedRecurrence": "{{count}} unsupported repeat rule(s) were kept as notes.",
|
|
74176
|
-
"settings.syncRemoteBusy": "Another
|
|
74577
|
+
"settings.syncRemoteBusy": "Another Mindwtr device is holding this sync location for a moment. Sync will retry on its own.",
|
|
74177
74578
|
"settings.syncRemoteCleanupDeferred": "The sync operation completed. Mindwtr could not remove the temporary sync lock, but it expires automatically. No retry is needed.",
|
|
74178
74579
|
"settings.syncAttachmentWriteDeferred": "Some attachment changes could not finish. Restore any missing local files or remove the affected attachments, then sync again.",
|
|
74179
74580
|
"settings.syncFileAttachmentTooLarge": "Mindwtr kept the local attachment. File Sync can only sync attachments under 100 MB. Replace it with a smaller file or remove the attachment, then sync again.",
|
|
@@ -87719,6 +88120,7 @@ var init_sync_service_utils = __esm(() => {
|
|
|
87719
88120
|
READONLY_ERROR_PATTERN = /isn't writable|not writable|read-only|read only|permission denied|EACCES/i;
|
|
87720
88121
|
OFFLINE_ERROR_PATTERNS = [
|
|
87721
88122
|
/offline state detected/i,
|
|
88123
|
+
/interrupted while the app was suspended/i,
|
|
87722
88124
|
/network request failed/i,
|
|
87723
88125
|
/internet connection appears to be offline/i,
|
|
87724
88126
|
/airplane mode/i,
|
|
@@ -88093,6 +88495,56 @@ var MISSING_ATTACHMENT_TIMESTAMP_SENTINEL = "1970-01-01T00:00:00.000Z", MISSING_
|
|
|
88093
88495
|
delete comparable[key];
|
|
88094
88496
|
}
|
|
88095
88497
|
return computeStableValueFingerprint(comparable);
|
|
88498
|
+
}, isDeepJsonEqual = (left, right) => {
|
|
88499
|
+
if (left === right)
|
|
88500
|
+
return true;
|
|
88501
|
+
if (left === null || right === null)
|
|
88502
|
+
return false;
|
|
88503
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
88504
|
+
if (!Array.isArray(left) || !Array.isArray(right))
|
|
88505
|
+
return false;
|
|
88506
|
+
if (left.length !== right.length)
|
|
88507
|
+
return false;
|
|
88508
|
+
for (let index = 0;index < left.length; index += 1) {
|
|
88509
|
+
if (!isDeepJsonEqual(left[index], right[index]))
|
|
88510
|
+
return false;
|
|
88511
|
+
}
|
|
88512
|
+
return true;
|
|
88513
|
+
}
|
|
88514
|
+
if (typeof left !== "object" || typeof right !== "object")
|
|
88515
|
+
return false;
|
|
88516
|
+
const leftRecord = left;
|
|
88517
|
+
const rightRecord = right;
|
|
88518
|
+
let definedInLeft = 0;
|
|
88519
|
+
for (const key of Object.keys(leftRecord)) {
|
|
88520
|
+
const leftValue = leftRecord[key];
|
|
88521
|
+
if (leftValue === undefined) {
|
|
88522
|
+
if (rightRecord[key] !== undefined)
|
|
88523
|
+
return false;
|
|
88524
|
+
continue;
|
|
88525
|
+
}
|
|
88526
|
+
if (!isDeepJsonEqual(leftValue, rightRecord[key]))
|
|
88527
|
+
return false;
|
|
88528
|
+
definedInLeft += 1;
|
|
88529
|
+
}
|
|
88530
|
+
let definedInRight = 0;
|
|
88531
|
+
for (const key of Object.keys(rightRecord)) {
|
|
88532
|
+
if (rightRecord[key] !== undefined)
|
|
88533
|
+
definedInRight += 1;
|
|
88534
|
+
}
|
|
88535
|
+
return definedInLeft === definedInRight;
|
|
88536
|
+
}, withoutSyncStatusBookkeeping = (settings) => {
|
|
88537
|
+
const comparable = { ...settings ?? {} };
|
|
88538
|
+
for (const key of SYNC_STATUS_BOOKKEEPING_SETTINGS_KEYS) {
|
|
88539
|
+
delete comparable[key];
|
|
88540
|
+
}
|
|
88541
|
+
return comparable;
|
|
88542
|
+
}, isLocalPersistEquivalent = (candidate, stored) => {
|
|
88543
|
+
if (candidate === stored)
|
|
88544
|
+
return true;
|
|
88545
|
+
if (!isDeepJsonEqual(withoutSyncStatusBookkeeping(candidate.settings), withoutSyncStatusBookkeeping(stored.settings)))
|
|
88546
|
+
return false;
|
|
88547
|
+
return isDeepJsonEqual({ ...candidate, settings: undefined }, { ...stored, settings: undefined });
|
|
88096
88548
|
}, appendEntityRevisions = (parts, entities) => {
|
|
88097
88549
|
parts.push(String(entities?.length ?? 0));
|
|
88098
88550
|
for (const entity of entities ?? []) {
|
|
@@ -88544,6 +88996,17 @@ var hasOwnField2 = (value, field) => Object.prototype.hasOwnProperty.call(value,
|
|
|
88544
88996
|
sequentialWithinSectionProjectIds,
|
|
88545
88997
|
focusedProjectCount
|
|
88546
88998
|
};
|
|
88999
|
+
}, isTaskCountedAsFocused = (task) => !task.deletedAt && task.isFocusedToday === true && task.status !== "done" && task.status !== "reference" && task.status !== "archived", focusedCountCache = null, selectFocusedCount = (tasks) => {
|
|
89000
|
+
if (focusedCountCache && focusedCountCache.tasks === tasks) {
|
|
89001
|
+
return focusedCountCache.count;
|
|
89002
|
+
}
|
|
89003
|
+
let count = 0;
|
|
89004
|
+
for (const task of tasks) {
|
|
89005
|
+
if (isTaskCountedAsFocused(task))
|
|
89006
|
+
count += 1;
|
|
89007
|
+
}
|
|
89008
|
+
focusedCountCache = { tasks, count };
|
|
89009
|
+
return count;
|
|
88547
89010
|
}, computeTaskDerivedState = (tasks, tasksById) => {
|
|
88548
89011
|
const resolvedTasksById = tasksById ?? new Map;
|
|
88549
89012
|
const activeTasksByStatus = new Map;
|
|
@@ -88594,7 +89057,7 @@ var hasOwnField2 = (value, field) => Object.prototype.hasOwnProperty.call(value,
|
|
|
88594
89057
|
if (dateCoherenceIssues.length > 0) {
|
|
88595
89058
|
dateCoherenceIssuesByTaskId.set(task.id, dateCoherenceIssues);
|
|
88596
89059
|
}
|
|
88597
|
-
if (task
|
|
89060
|
+
if (isTaskCountedAsFocused(task)) {
|
|
88598
89061
|
focusedCount += 1;
|
|
88599
89062
|
focusedTasks.push(task);
|
|
88600
89063
|
}
|
|
@@ -89806,6 +90269,7 @@ var normalizeAppData = (data) => ({
|
|
|
89806
90269
|
isFocused: normalizeSyncedBoolean(project.isFocused),
|
|
89807
90270
|
attachments: normalizeAttachmentsForSyncMerge(project.attachments),
|
|
89808
90271
|
dueDate: normalizeOptionalString2(project.dueDate),
|
|
90272
|
+
startDate: normalizeOptionalString2(project.startDate),
|
|
89809
90273
|
reviewAt: normalizeOptionalString2(project.reviewAt),
|
|
89810
90274
|
areaId: normalizeOptionalString2(project.areaId),
|
|
89811
90275
|
areaTitle: normalizeOptionalString2(project.areaTitle)
|
|
@@ -92012,6 +92476,23 @@ function createEmptyEntityStats(localTotal, incomingTotal) {
|
|
|
92012
92476
|
conflictSamples: []
|
|
92013
92477
|
};
|
|
92014
92478
|
}
|
|
92479
|
+
function createLocalOnlyMergeStats(data) {
|
|
92480
|
+
const forCollection = (items) => {
|
|
92481
|
+
const stats = createEmptyEntityStats(items?.length ?? 0, 0);
|
|
92482
|
+
stats.mergedTotal = stats.localTotal;
|
|
92483
|
+
stats.localOnly = stats.localTotal;
|
|
92484
|
+
stats.resolvedUsingLocal = stats.localTotal;
|
|
92485
|
+
return stats;
|
|
92486
|
+
};
|
|
92487
|
+
return {
|
|
92488
|
+
tasks: forCollection(data.tasks),
|
|
92489
|
+
projects: forCollection(data.projects),
|
|
92490
|
+
sections: forCollection(data.sections),
|
|
92491
|
+
areas: forCollection(data.areas),
|
|
92492
|
+
people: forCollection(data.people),
|
|
92493
|
+
tombstoneRepairs: 0
|
|
92494
|
+
};
|
|
92495
|
+
}
|
|
92015
92496
|
function mergeEntitiesWithStats(local, incoming, mergeConflict, normalizeForComparison, entityType = "entity", nowIso) {
|
|
92016
92497
|
const localMap = new Map(local.map((item) => [item.id, item]));
|
|
92017
92498
|
const incomingMap = new Map(incoming.map((item) => [item.id, item]));
|
|
@@ -92666,7 +93147,8 @@ async function performSyncCycleUnlocked(io) {
|
|
|
92666
93147
|
const remoteData = purgeExpiredTombstones(remoteDocument.data, nowIso, io.tombstoneRetentionDays).data;
|
|
92667
93148
|
io.onStep?.("merge");
|
|
92668
93149
|
await yieldToUi();
|
|
92669
|
-
const
|
|
93150
|
+
const remoteIsEmpty = remoteData.tasks.length === 0 && remoteData.projects.length === 0 && remoteData.sections.length === 0 && remoteData.areas.length === 0 && (remoteData.people?.length ?? 0) === 0;
|
|
93151
|
+
const mergeResult = io.skipEmptyRemoteMerge?.() === true && remoteIsEmpty ? { data: localData, stats: createLocalOnlyMergeStats(localData) } : mergeAppDataWithStats(localData, remoteData, {
|
|
92670
93152
|
nowIso,
|
|
92671
93153
|
preferIncomingAttachmentCloudKeys: io.preferIncomingAttachmentCloudKeys
|
|
92672
93154
|
});
|
|
@@ -92754,6 +93236,34 @@ async function performSyncCycleUnlocked(io) {
|
|
|
92754
93236
|
throw new Error(`Sync validation failed: ${sample}`);
|
|
92755
93237
|
}
|
|
92756
93238
|
}
|
|
93239
|
+
if (!pendingRemoteWriteMeta && typeof io.isLocalPersistUnchanged === "function" && typeof io.persistSyncStatusOnly === "function" && io.isLocalPersistUnchanged(finalData)) {
|
|
93240
|
+
io.onStep?.("write-remote");
|
|
93241
|
+
await yieldToUi();
|
|
93242
|
+
try {
|
|
93243
|
+
await io.writeRemote(finalData);
|
|
93244
|
+
} catch (error2) {
|
|
93245
|
+
if (!isLocalSyncAbortError2(error2)) {
|
|
93246
|
+
io.onStep?.("write-local");
|
|
93247
|
+
await yieldToUi();
|
|
93248
|
+
await io.writeLocal(withPendingRemoteWriteRetry(finalData, nowIso, error2));
|
|
93249
|
+
}
|
|
93250
|
+
throw error2;
|
|
93251
|
+
}
|
|
93252
|
+
try {
|
|
93253
|
+
await io.persistSyncStatusOnly(finalData);
|
|
93254
|
+
} catch (error2) {
|
|
93255
|
+
logWarn("Failed to persist sync status after an unchanged local write", {
|
|
93256
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
93257
|
+
});
|
|
93258
|
+
}
|
|
93259
|
+
return {
|
|
93260
|
+
data: finalData,
|
|
93261
|
+
stats: mergeResult.stats,
|
|
93262
|
+
status: nextSyncStatus,
|
|
93263
|
+
clockSkewWarning: mergeResult.clockSkewWarning,
|
|
93264
|
+
localWriteSkipped: true
|
|
93265
|
+
};
|
|
93266
|
+
}
|
|
92757
93267
|
const finalDataWithPendingRemoteWrite = withPendingRemoteWriteFlag(finalData, pendingRemoteWriteMeta?.pendingAt ?? nowIso, pendingRemoteWriteMeta?.attempts);
|
|
92758
93268
|
io.onStep?.("write-local");
|
|
92759
93269
|
await yieldToUi();
|
|
@@ -94587,6 +95097,8 @@ var normalizeStarterTaskTitle = (title) => title.trim().toLowerCase(), STARTER_T
|
|
|
94587
95097
|
order: 0,
|
|
94588
95098
|
tagIds: [],
|
|
94589
95099
|
supportNotes: resolveStarterString(lang, STARTER_PROJECT_NOTES_KEY),
|
|
95100
|
+
isSequential: false,
|
|
95101
|
+
isFocused: false,
|
|
94590
95102
|
rev: 1,
|
|
94591
95103
|
...revisionMeta,
|
|
94592
95104
|
createdAt: nowIso,
|
|
@@ -94610,7 +95122,9 @@ var normalizeStarterTaskTitle = (title) => title.trim().toLowerCase(), STARTER_T
|
|
|
94610
95122
|
projectId,
|
|
94611
95123
|
order: index,
|
|
94612
95124
|
orderNum: index,
|
|
94613
|
-
isFocusedToday: template.isFocusedToday,
|
|
95125
|
+
isFocusedToday: template.isFocusedToday ?? false,
|
|
95126
|
+
suppressMindwtrReminders: false,
|
|
95127
|
+
pushCount: 0,
|
|
94614
95128
|
rev: 1,
|
|
94615
95129
|
...revisionMeta,
|
|
94616
95130
|
createdAt: nowIso,
|
|
@@ -94623,6 +95137,9 @@ var normalizeStarterTaskTitle = (title) => title.trim().toLowerCase(), STARTER_T
|
|
|
94623
95137
|
taskMode: "task",
|
|
94624
95138
|
tags: [],
|
|
94625
95139
|
contexts: [],
|
|
95140
|
+
isFocusedToday: false,
|
|
95141
|
+
suppressMindwtrReminders: false,
|
|
95142
|
+
pushCount: 0,
|
|
94626
95143
|
rev: 1,
|
|
94627
95144
|
...revisionMeta,
|
|
94628
95145
|
createdAt: nowIso,
|
|
@@ -95261,7 +95778,8 @@ var STORAGE_TIMEOUT_MS = 15000, SLOW_FETCH_LOG_THRESHOLD_MS = 1000, getFetchData
|
|
|
95261
95778
|
},
|
|
95262
95779
|
setHighlightTask: (id2) => {
|
|
95263
95780
|
set5({ highlightTaskId: id2, highlightTaskAt: id2 ? Date.now() : null });
|
|
95264
|
-
}
|
|
95781
|
+
},
|
|
95782
|
+
getFocusedCount: () => selectFocusedCount(get().tasks)
|
|
95265
95783
|
});
|
|
95266
95784
|
var init_store_settings = __esm(() => {
|
|
95267
95785
|
init_logger();
|
|
@@ -95514,17 +96032,22 @@ var createAreaActions = ({
|
|
|
95514
96032
|
const nextName = updates.name !== undefined ? updates.name.trim() : area.name;
|
|
95515
96033
|
let projectsChanged = false;
|
|
95516
96034
|
let newAllProjects = state._allProjects;
|
|
95517
|
-
|
|
95518
|
-
|
|
96035
|
+
const repaintColor = "color" in updates;
|
|
96036
|
+
const nextAreaColor = updates.color ?? DEFAULT_PROJECT_COLOR;
|
|
96037
|
+
const nextAreaTitle = nextName.trim() || undefined;
|
|
96038
|
+
if (repaintColor || nextAreaTitle !== area.name?.trim()) {
|
|
95519
96039
|
newAllProjects = state._allProjects.map((project) => {
|
|
95520
96040
|
if (project.areaId !== id2)
|
|
95521
96041
|
return project;
|
|
95522
|
-
|
|
96042
|
+
const wantsColor = repaintColor && project.color !== nextAreaColor;
|
|
96043
|
+
const wantsTitle = project.areaTitle !== nextAreaTitle;
|
|
96044
|
+
if (!wantsColor && !wantsTitle)
|
|
95523
96045
|
return project;
|
|
95524
96046
|
projectsChanged = true;
|
|
95525
96047
|
return {
|
|
95526
96048
|
...project,
|
|
95527
|
-
color: nextAreaColor,
|
|
96049
|
+
...wantsColor ? { color: nextAreaColor } : {},
|
|
96050
|
+
...wantsTitle ? { areaTitle: nextAreaTitle } : {},
|
|
95528
96051
|
updatedAt: now3,
|
|
95529
96052
|
rev: nextRevision(project.rev),
|
|
95530
96053
|
revBy: deviceState.deviceId
|
|
@@ -95601,7 +96124,7 @@ var createAreaActions = ({
|
|
|
95601
96124
|
};
|
|
95602
96125
|
});
|
|
95603
96126
|
const newAllTasks = state._allTasks.map((task) => {
|
|
95604
|
-
if (task.areaId !== id2
|
|
96127
|
+
if (task.areaId !== id2)
|
|
95605
96128
|
return task;
|
|
95606
96129
|
return {
|
|
95607
96130
|
...task,
|
|
@@ -95928,6 +96451,7 @@ var duplicateProjectAttachmentCopy = (attachment, now3) => ({
|
|
|
95928
96451
|
color,
|
|
95929
96452
|
initialProps,
|
|
95930
96453
|
existingProjects,
|
|
96454
|
+
existingAreas,
|
|
95931
96455
|
settings,
|
|
95932
96456
|
deviceId,
|
|
95933
96457
|
now: now3,
|
|
@@ -95935,11 +96459,11 @@ var duplicateProjectAttachmentCopy = (attachment, now3) => ({
|
|
|
95935
96459
|
}) => {
|
|
95936
96460
|
const trimmedTitle = typeof title === "string" ? title.trim() : "";
|
|
95937
96461
|
const targetAreaId = initialProps?.areaId;
|
|
95938
|
-
const maxOrder = existingProjects.filter((
|
|
96462
|
+
const maxOrder = existingProjects.filter((project2) => (project2.areaId ?? undefined) === (targetAreaId ?? undefined)).reduce((max3, project2) => Math.max(max3, Number.isFinite(project2.order) ? project2.order : -1), -1);
|
|
95939
96463
|
const baseOrder = Number.isFinite(initialProps?.order) ? initialProps?.order : maxOrder + 1;
|
|
95940
96464
|
const hasExplicitFlowMode = Boolean(initialProps && Object.prototype.hasOwnProperty.call(initialProps, "isSequential"));
|
|
95941
96465
|
const useSequentialDefault = !hasExplicitFlowMode && settings.gtd?.defaultProjectFlowMode === "sequential";
|
|
95942
|
-
|
|
96466
|
+
const project = {
|
|
95943
96467
|
id: id2 ?? generateUUID(),
|
|
95944
96468
|
title: trimmedTitle,
|
|
95945
96469
|
color: color ?? DEFAULT_PROJECT_COLOR,
|
|
@@ -95949,10 +96473,14 @@ var duplicateProjectAttachmentCopy = (attachment, now3) => ({
|
|
|
95949
96473
|
revBy: deviceId,
|
|
95950
96474
|
createdAt: now3,
|
|
95951
96475
|
updatedAt: now3,
|
|
96476
|
+
isSequential: false,
|
|
96477
|
+
isFocused: false,
|
|
95952
96478
|
...useSequentialDefault ? { isSequential: true } : {},
|
|
95953
96479
|
...initialProps,
|
|
95954
96480
|
tagIds: initialProps?.tagIds ?? []
|
|
95955
96481
|
};
|
|
96482
|
+
const areaTitle = project.areaId ? existingAreas.find((area) => area.id === project.areaId && !area.deletedAt)?.name?.trim() || undefined : undefined;
|
|
96483
|
+
return areaTitle === project.areaTitle ? project : { ...project, areaTitle };
|
|
95956
96484
|
}, createProjectCoreActions = ({
|
|
95957
96485
|
set: set5,
|
|
95958
96486
|
get,
|
|
@@ -95981,6 +96509,7 @@ var duplicateProjectAttachmentCopy = (attachment, now3) => ({
|
|
|
95981
96509
|
color,
|
|
95982
96510
|
initialProps,
|
|
95983
96511
|
existingProjects: state._allProjects,
|
|
96512
|
+
existingAreas: state._allAreas,
|
|
95984
96513
|
settings: state.settings,
|
|
95985
96514
|
deviceId: deviceState.deviceId,
|
|
95986
96515
|
now: now3
|
|
@@ -96662,7 +97191,7 @@ var SLOW_TASK_UPDATE_LOG_THRESHOLD_MS = 500, collectAttachmentCloudKeysForTasks
|
|
|
96662
97191
|
const now3 = new Date().toISOString();
|
|
96663
97192
|
const projectOrderReserver = createProjectOrderReserver(currentState._allTasks);
|
|
96664
97193
|
const focusTaskLimit = normalizeFocusTaskLimit(currentState.settings.gtd?.focusTaskLimit);
|
|
96665
|
-
let focusedCount = currentState.
|
|
97194
|
+
let focusedCount = currentState.getFocusedCount();
|
|
96666
97195
|
const nextAllTasks = [...currentState._allTasks];
|
|
96667
97196
|
const newTasks = [];
|
|
96668
97197
|
for (const item of normalizedItems) {
|
|
@@ -96708,6 +97237,8 @@ var SLOW_TASK_UPDATE_LOG_THRESHOLD_MS = 500, collectAttachmentCloudKeysForTasks
|
|
|
96708
97237
|
updatedAt: now3,
|
|
96709
97238
|
deletedAt: undefined,
|
|
96710
97239
|
purgedAt: undefined,
|
|
97240
|
+
isFocusedToday: initialTaskProps.isFocusedToday ?? false,
|
|
97241
|
+
suppressMindwtrReminders: initialTaskProps.suppressMindwtrReminders ?? false,
|
|
96711
97242
|
...referenceClears,
|
|
96712
97243
|
areaId: resolvedAreaId,
|
|
96713
97244
|
projectId: resolvedProjectId,
|
|
@@ -96776,7 +97307,7 @@ var SLOW_TASK_UPDATE_LOG_THRESHOLD_MS = 500, collectAttachmentCloudKeysForTasks
|
|
|
96776
97307
|
const isPromotingTaskFocus = preparedUpdates.updates.isFocusedToday === true && existingTask.isFocusedToday !== true;
|
|
96777
97308
|
if (isPromotingTaskFocus) {
|
|
96778
97309
|
const focusTaskLimit = normalizeFocusTaskLimit(currentState.settings.gtd?.focusTaskLimit);
|
|
96779
|
-
const focusedCount = currentState.
|
|
97310
|
+
const focusedCount = currentState.getFocusedCount();
|
|
96780
97311
|
if (focusedCount >= focusTaskLimit) {
|
|
96781
97312
|
const message3 = `Focus limit of ${focusTaskLimit} reached`;
|
|
96782
97313
|
set5({ error: message3 });
|
|
@@ -97187,6 +97718,7 @@ var SLOW_TASK_UPDATE_LOG_THRESHOLD_MS = 500, collectAttachmentCloudKeysForTasks
|
|
|
97187
97718
|
tagIds: projectTagIds
|
|
97188
97719
|
},
|
|
97189
97720
|
existingProjects: state._allProjects,
|
|
97721
|
+
existingAreas: state._allAreas,
|
|
97190
97722
|
settings: state.settings,
|
|
97191
97723
|
deviceId: deviceState.deviceId,
|
|
97192
97724
|
now: now3
|
|
@@ -98832,7 +99364,7 @@ var DEFAULT_ATTACHMENT_CLEANUP_INTERVAL_MS, CLOUD_PROVIDER_SELF_HOSTED = "selfho
|
|
|
98832
99364
|
return currentChangeAt;
|
|
98833
99365
|
onStale?.({ localSnapshotChangeAt, currentChangeAt });
|
|
98834
99366
|
requestFollowUp();
|
|
98835
|
-
throw new LocalSyncAbort;
|
|
99367
|
+
throw new LocalSyncAbort("local-data-changed");
|
|
98836
99368
|
}, getInMemoryAppDataSnapshot = () => {
|
|
98837
99369
|
const state = useTaskStore.getState();
|
|
98838
99370
|
return cloneAppData({
|
|
@@ -98913,9 +99445,11 @@ var init_sync_client_helpers = __esm(() => {
|
|
|
98913
99445
|
init_sync_runtime_utils();
|
|
98914
99446
|
DEFAULT_ATTACHMENT_CLEANUP_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
98915
99447
|
LocalSyncAbort = class LocalSyncAbort extends Error {
|
|
98916
|
-
|
|
99448
|
+
reason;
|
|
99449
|
+
constructor(reason = "local-data-changed") {
|
|
98917
99450
|
super("Local changes detected during sync");
|
|
98918
99451
|
this.name = "LocalSyncAbort";
|
|
99452
|
+
this.reason = reason;
|
|
98919
99453
|
}
|
|
98920
99454
|
};
|
|
98921
99455
|
});
|
|
@@ -100996,21 +101530,26 @@ function getSyncEncryptionStatusFromLocalState(localState) {
|
|
|
100996
101530
|
incompleteTransition: persisted.incompleteTransition
|
|
100997
101531
|
};
|
|
100998
101532
|
}
|
|
100999
|
-
function markRemoteEncryptionDiscovered(localState, discovered) {
|
|
101533
|
+
function markRemoteEncryptionDiscovered(localState, discovered, scope) {
|
|
101000
101534
|
const current = localState.read();
|
|
101001
101535
|
if (current && SYNC_ENCRYPTION_KEYED_STATES.includes(current.state) && current.discoveredSalt === bytesToHex(discovered.salt))
|
|
101002
101536
|
return;
|
|
101003
101537
|
localState.write({
|
|
101004
101538
|
state: "remote-encrypted-no-key",
|
|
101005
101539
|
discoveredSalt: bytesToHex(discovered.salt),
|
|
101006
|
-
discoveredParams: discovered.params
|
|
101540
|
+
discoveredParams: discovered.params,
|
|
101541
|
+
...scope ? { discoveredScope: scope } : {}
|
|
101007
101542
|
});
|
|
101008
101543
|
}
|
|
101009
|
-
function markRemotePlaintextDiscovered(localState) {
|
|
101544
|
+
function markRemotePlaintextDiscovered(localState, scope) {
|
|
101010
101545
|
const current = localState.read();
|
|
101011
101546
|
if (!current || current.state !== "enabled")
|
|
101012
101547
|
return;
|
|
101013
|
-
localState.write({
|
|
101548
|
+
localState.write({
|
|
101549
|
+
...current,
|
|
101550
|
+
state: "remote-plaintext",
|
|
101551
|
+
...scope ? { discoveredScope: scope } : {}
|
|
101552
|
+
});
|
|
101014
101553
|
}
|
|
101015
101554
|
function reaffirmRemoteEncryptionNoKey(localState) {
|
|
101016
101555
|
const current = localState.read();
|
|
@@ -101419,6 +101958,10 @@ async function runProvideSyncEncryptionPassphraseOverRemote(passphrase, baseDocu
|
|
|
101419
101958
|
const captured = await remote.read(encName);
|
|
101420
101959
|
const bytes = captured.bytes;
|
|
101421
101960
|
if (!bytes) {
|
|
101961
|
+
if (localState.read()?.state === "remote-encrypted-no-key") {
|
|
101962
|
+
await runDisableSyncEncryptionLocalOnly(keyCache, localState);
|
|
101963
|
+
return "no-encrypted-remote";
|
|
101964
|
+
}
|
|
101422
101965
|
throw new Error(`sync encryption: no encrypted remote artifact found at ${encName}`);
|
|
101423
101966
|
}
|
|
101424
101967
|
requireExistingRemoteVersion(encName, captured);
|
|
@@ -101454,7 +101997,42 @@ async function runProvideSyncEncryptionPassphraseOverRemote(passphrase, baseDocu
|
|
|
101454
101997
|
}
|
|
101455
101998
|
throw new SyncEncryptionRemoteConflictError(`${encName} changed during passphrase validation`);
|
|
101456
101999
|
}
|
|
101457
|
-
var SYNC_ENCRYPTION_KEYED_STATES,
|
|
102000
|
+
var SYNC_ENCRYPTION_KEYED_STATES, scopeValue = (value) => {
|
|
102001
|
+
const trimmed = value?.trim();
|
|
102002
|
+
return trimmed ? trimmed : null;
|
|
102003
|
+
}, buildSyncLocationScope = (input) => {
|
|
102004
|
+
const backend = scopeValue(input.backend) ?? "off";
|
|
102005
|
+
if (backend === "file")
|
|
102006
|
+
return JSON.stringify(["file", scopeValue(input.syncPath)]);
|
|
102007
|
+
if (backend === "webdav") {
|
|
102008
|
+
const url = scopeValue(input.webdavUrl);
|
|
102009
|
+
return JSON.stringify([
|
|
102010
|
+
"webdav",
|
|
102011
|
+
url ? normalizeWebdavUrl(url) : null,
|
|
102012
|
+
scopeValue(input.webdavUsername)
|
|
102013
|
+
]);
|
|
102014
|
+
}
|
|
102015
|
+
if (backend === "cloud") {
|
|
102016
|
+
const provider = scopeValue(input.cloudProvider) ?? "selfhosted";
|
|
102017
|
+
if (provider === "dropbox")
|
|
102018
|
+
return JSON.stringify(["cloud", "dropbox"]);
|
|
102019
|
+
const url = scopeValue(input.cloudUrl);
|
|
102020
|
+
return JSON.stringify(["cloud", provider, url ? normalizeCloudUrl(url) : null]);
|
|
102021
|
+
}
|
|
102022
|
+
return JSON.stringify([backend]);
|
|
102023
|
+
}, isSyncEncryptionStateBlocked = (state, activeScope) => {
|
|
102024
|
+
if (!state)
|
|
102025
|
+
return false;
|
|
102026
|
+
if (state.incompleteTransition)
|
|
102027
|
+
return true;
|
|
102028
|
+
if (state.state !== "remote-encrypted-no-key" && state.state !== "remote-plaintext")
|
|
102029
|
+
return false;
|
|
102030
|
+
if (!state.discoveredScope)
|
|
102031
|
+
return false;
|
|
102032
|
+
if (activeScope === null)
|
|
102033
|
+
return true;
|
|
102034
|
+
return state.discoveredScope === activeScope;
|
|
102035
|
+
}, SYNC_ENCRYPTION_TRANSITION_INCOMPLETE = "SYNC_ENCRYPTION_TRANSITION_INCOMPLETE", SyncEncryptionTransitionIncompleteError, requireMatchingIncompleteTransition = (localState, kind) => {
|
|
101458
102036
|
const current = localState.read();
|
|
101459
102037
|
if (current?.incompleteTransition && current.incompleteTransition !== kind) {
|
|
101460
102038
|
throw new SyncEncryptionTransitionIncompleteError(current.incompleteTransition);
|
|
@@ -101530,6 +102108,7 @@ var SYNC_ENCRYPTION_KEYED_STATES, SYNC_ENCRYPTION_TRANSITION_INCOMPLETE = "SYNC_
|
|
|
101530
102108
|
}, PLAINTEXT_PAD_BYTE = 32, __syncEncryptionTestUtils;
|
|
101531
102109
|
var init_sync_encryption = __esm(() => {
|
|
101532
102110
|
init_sync_crypto();
|
|
102111
|
+
init_sync_helpers();
|
|
101533
102112
|
SYNC_ENCRYPTION_KEYED_STATES = ["enabled", "remote-plaintext"];
|
|
101534
102113
|
SyncEncryptionTransitionIncompleteError = class SyncEncryptionTransitionIncompleteError extends Error {
|
|
101535
102114
|
constructor(kind) {
|
|
@@ -102142,15 +102721,18 @@ var WEBDAV_REMOTE_WRITE_CONFLICT = "WEBDAV_REMOTE_WRITE_CONFLICT", WebDavRemoteW
|
|
|
102142
102721
|
}
|
|
102143
102722
|
}, __webdavTestUtils, getWebdavParentCollectionUrl = (url) => {
|
|
102144
102723
|
try {
|
|
102145
|
-
const
|
|
102146
|
-
const
|
|
102147
|
-
const
|
|
102148
|
-
if (
|
|
102724
|
+
const suffixStart = url.search(/[?#]/);
|
|
102725
|
+
const withoutSuffix = (suffixStart === -1 ? url : url.slice(0, suffixStart)).replace(/\/+$/, "");
|
|
102726
|
+
const schemeEnd = withoutSuffix.indexOf("://");
|
|
102727
|
+
if (schemeEnd === -1)
|
|
102149
102728
|
return null;
|
|
102150
|
-
|
|
102151
|
-
|
|
102152
|
-
|
|
102153
|
-
|
|
102729
|
+
const pathStart = withoutSuffix.indexOf("/", schemeEnd + 3);
|
|
102730
|
+
if (pathStart === -1)
|
|
102731
|
+
return null;
|
|
102732
|
+
const lastSlash = withoutSuffix.lastIndexOf("/");
|
|
102733
|
+
if (lastSlash <= pathStart)
|
|
102734
|
+
return null;
|
|
102735
|
+
return withoutSuffix.slice(0, lastSlash);
|
|
102154
102736
|
} catch {
|
|
102155
102737
|
return null;
|
|
102156
102738
|
}
|
|
@@ -102455,7 +103037,7 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102455
103037
|
if (!Number.isFinite(ttlMs) || ttlMs < MIN_TTL_MS || ttlMs > MAX_TTL_MS) {
|
|
102456
103038
|
throw new Error(`Remote sync mutation fence ttlMs must be between ${MIN_TTL_MS} and ${MAX_TTL_MS}`);
|
|
102457
103039
|
}
|
|
102458
|
-
const heartbeatMs = options.heartbeatMs ?? Math.max(1000, Math.floor(ttlMs / 3));
|
|
103040
|
+
const heartbeatMs = options.heartbeatMs ?? Math.max(1000, Math.min(DEFAULT_HEARTBEAT_MS, Math.floor(ttlMs / 3)));
|
|
102459
103041
|
if (!Number.isFinite(heartbeatMs) || heartbeatMs < 0 || heartbeatMs >= ttlMs) {
|
|
102460
103042
|
throw new Error("Remote sync mutation fence heartbeatMs must be zero or shorter than ttlMs");
|
|
102461
103043
|
}
|
|
@@ -102468,16 +103050,27 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102468
103050
|
throw new Error("Remote sync mutation fence leaseId is too short");
|
|
102469
103051
|
let acquiredVersion = null;
|
|
102470
103052
|
let acquiredRemainingMs = ttlMs;
|
|
103053
|
+
let reclaimedFrom = null;
|
|
102471
103054
|
for (let attempt = 0;attempt < maxAttempts; attempt += 1) {
|
|
102472
103055
|
const snapshot = await port.read();
|
|
102473
103056
|
const serverNowMs = requireServerNow(snapshot);
|
|
103057
|
+
reclaimedFrom = null;
|
|
102474
103058
|
if (snapshot.bytes) {
|
|
102475
103059
|
if (!snapshot.version) {
|
|
102476
103060
|
throw new SyncRemoteMutationFenceUnavailableError("Existing remote sync mutation fence has no safe version");
|
|
102477
103061
|
}
|
|
102478
103062
|
const current = parseRecord(snapshot.bytes);
|
|
102479
103063
|
if (current.expiresAt > serverNowMs && !isImpossibleFutureExpiry(current.expiresAt, serverNowMs)) {
|
|
102480
|
-
|
|
103064
|
+
const holder = {
|
|
103065
|
+
ownerId: current.ownerId,
|
|
103066
|
+
leaseId: current.leaseId,
|
|
103067
|
+
purpose: current.purpose,
|
|
103068
|
+
remainingMs: current.expiresAt - serverNowMs
|
|
103069
|
+
};
|
|
103070
|
+
if (!isAbandonedRecord(current, serverNowMs)) {
|
|
103071
|
+
throw new SyncRemoteMutationFenceBusyError(current.expiresAt - serverNowMs, holder);
|
|
103072
|
+
}
|
|
103073
|
+
reclaimedFrom = holder;
|
|
102481
103074
|
}
|
|
102482
103075
|
} else if (snapshot.version !== null) {
|
|
102483
103076
|
throw new SyncRemoteMutationFenceUnavailableError("Missing remote sync mutation fence unexpectedly has a version");
|
|
@@ -102487,7 +103080,9 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102487
103080
|
leaseId,
|
|
102488
103081
|
ownerId,
|
|
102489
103082
|
purpose: options.purpose,
|
|
102490
|
-
expiresAt: serverNowMs + ttlMs
|
|
103083
|
+
expiresAt: serverNowMs + ttlMs,
|
|
103084
|
+
heartbeatMs,
|
|
103085
|
+
renewedAt: serverNowMs
|
|
102491
103086
|
};
|
|
102492
103087
|
try {
|
|
102493
103088
|
await port.write(encodeRecord(record3), snapshot.version);
|
|
@@ -102559,7 +103154,9 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102559
103154
|
leaseId,
|
|
102560
103155
|
ownerId,
|
|
102561
103156
|
purpose: options.purpose,
|
|
102562
|
-
expiresAt: serverNowMs + ttlMs
|
|
103157
|
+
expiresAt: serverNowMs + ttlMs,
|
|
103158
|
+
heartbeatMs,
|
|
103159
|
+
renewedAt: serverNowMs
|
|
102563
103160
|
};
|
|
102564
103161
|
try {
|
|
102565
103162
|
await port.write(encodeRecord(replacement), snapshot.version);
|
|
@@ -102601,6 +103198,7 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102601
103198
|
};
|
|
102602
103199
|
scheduleHeartbeat();
|
|
102603
103200
|
return {
|
|
103201
|
+
reclaimedFrom,
|
|
102604
103202
|
assertHeld: (minRemainingMs = 0) => serialize(async () => {
|
|
102605
103203
|
if (!Number.isFinite(minRemainingMs) || minRemainingMs < 0 || minRemainingMs >= ttlMs) {
|
|
102606
103204
|
throw new Error("Remote sync mutation fence remaining-time requirement is invalid");
|
|
@@ -102642,12 +103240,19 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102642
103240
|
})
|
|
102643
103241
|
};
|
|
102644
103242
|
}
|
|
102645
|
-
var SYNC_REMOTE_MUTATION_FENCE_NAME = ".mindwtr-sync-fence-v1.json", SYNC_REMOTE_MUTATION_REQUEST_HORIZON_MS = 35000, SyncRemoteMutationFenceBusyError, SyncRemoteMutationFenceLostError, SyncRemoteMutationFenceUnavailableError, isSyncRemoteMutationFenceError = (error2) => error2 instanceof SyncRemoteMutationFenceBusyError || error2 instanceof SyncRemoteMutationFenceLostError || error2 instanceof SyncRemoteMutationFenceUnavailableError, FENCE_SCHEMA = 1, MIN_TTL_MS = 1e4, MAX_TTL_MS, MAX_FUTURE_EXPIRY_TOLERANCE_MS = 60000, MAX_RECORD_BYTES = 4096, DEFAULT_ACQUIRE_ATTEMPTS = 4, encodeUtf8 = (text) => new TextEncoder().encode(text), decodeUtf8 = (bytes) => new TextDecoder("utf-8", { fatal: true }).decode(bytes), requireServerNow = (snapshot) => {
|
|
103243
|
+
var SYNC_REMOTE_MUTATION_FENCE_NAME = ".mindwtr-sync-fence-v1.json", SYNC_REMOTE_MUTATION_REQUEST_HORIZON_MS = 35000, SyncRemoteMutationFenceBusyError, SyncRemoteMutationFenceLostError, SyncRemoteMutationFenceUnavailableError, isSyncRemoteMutationFenceError = (error2) => error2 instanceof SyncRemoteMutationFenceBusyError || error2 instanceof SyncRemoteMutationFenceLostError || error2 instanceof SyncRemoteMutationFenceUnavailableError, FENCE_SCHEMA = 1, MIN_TTL_MS = 1e4, MAX_TTL_MS, MAX_FUTURE_EXPIRY_TOLERANCE_MS = 60000, MAX_RECORD_BYTES = 4096, DEFAULT_ACQUIRE_ATTEMPTS = 4, DEFAULT_HEARTBEAT_MS = 20000, ABANDONED_AFTER_MISSED_HEARTBEATS = 3, ABANDONED_JITTER_MARGIN_MS = 5000, encodeUtf8 = (text) => new TextEncoder().encode(text), decodeUtf8 = (bytes) => new TextDecoder("utf-8", { fatal: true }).decode(bytes), requireServerNow = (snapshot) => {
|
|
102646
103244
|
if (snapshot.serverNowMs === null || !Number.isFinite(snapshot.serverNowMs)) {
|
|
102647
103245
|
throw new SyncRemoteMutationFenceUnavailableError("Remote sync mutation fencing requires a valid provider Date response header");
|
|
102648
103246
|
}
|
|
102649
103247
|
return snapshot.serverNowMs;
|
|
102650
|
-
}, isImpossibleFutureExpiry = (expiresAt, serverNowMs) => expiresAt - serverNowMs > MAX_TTL_MS + MAX_FUTURE_EXPIRY_TOLERANCE_MS,
|
|
103248
|
+
}, isImpossibleFutureExpiry = (expiresAt, serverNowMs) => expiresAt - serverNowMs > MAX_TTL_MS + MAX_FUTURE_EXPIRY_TOLERANCE_MS, isAbandonedRecord = (record3, serverNowMs) => {
|
|
103249
|
+
if (typeof record3.heartbeatMs !== "number" || record3.heartbeatMs <= 0)
|
|
103250
|
+
return false;
|
|
103251
|
+
if (typeof record3.renewedAt !== "number")
|
|
103252
|
+
return false;
|
|
103253
|
+
const silentForMs = serverNowMs - record3.renewedAt;
|
|
103254
|
+
return silentForMs > record3.heartbeatMs * ABANDONED_AFTER_MISSED_HEARTBEATS + ABANDONED_JITTER_MARGIN_MS;
|
|
103255
|
+
}, parseRecord = (bytes) => {
|
|
102651
103256
|
if (bytes.length === 0 || bytes.length > MAX_RECORD_BYTES) {
|
|
102652
103257
|
throw new SyncRemoteMutationFenceUnavailableError("Remote sync mutation fence record is malformed");
|
|
102653
103258
|
}
|
|
@@ -102664,7 +103269,14 @@ var SYNC_REMOTE_MUTATION_FENCE_NAME = ".mindwtr-sync-fence-v1.json", SYNC_REMOTE
|
|
|
102664
103269
|
if (record3.schema !== FENCE_SCHEMA || typeof record3.leaseId !== "string" || record3.leaseId.length < 8 || typeof record3.ownerId !== "string" || record3.ownerId.length < 1 || record3.purpose !== "ordinary-sync" && record3.purpose !== "encryption-transition" || typeof record3.expiresAt !== "number" || !Number.isFinite(record3.expiresAt)) {
|
|
102665
103270
|
throw new SyncRemoteMutationFenceUnavailableError("Remote sync mutation fence record is malformed");
|
|
102666
103271
|
}
|
|
102667
|
-
|
|
103272
|
+
const parsedRecord = record3;
|
|
103273
|
+
if (typeof parsedRecord.heartbeatMs !== "number" || !Number.isFinite(parsedRecord.heartbeatMs) || parsedRecord.heartbeatMs < 0) {
|
|
103274
|
+
delete parsedRecord.heartbeatMs;
|
|
103275
|
+
}
|
|
103276
|
+
if (typeof parsedRecord.renewedAt !== "number" || !Number.isFinite(parsedRecord.renewedAt)) {
|
|
103277
|
+
delete parsedRecord.renewedAt;
|
|
103278
|
+
}
|
|
103279
|
+
return parsedRecord;
|
|
102668
103280
|
}, encodeRecord = (record3) => encodeUtf8(JSON.stringify(record3)), randomLeaseId = () => {
|
|
102669
103281
|
const randomUuid = globalThis.crypto?.randomUUID?.();
|
|
102670
103282
|
if (randomUuid)
|
|
@@ -102674,10 +103286,12 @@ var SYNC_REMOTE_MUTATION_FENCE_NAME = ".mindwtr-sync-fence-v1.json", SYNC_REMOTE
|
|
|
102674
103286
|
var init_sync_remote_fence = __esm(() => {
|
|
102675
103287
|
SyncRemoteMutationFenceBusyError = class SyncRemoteMutationFenceBusyError extends Error {
|
|
102676
103288
|
retryAfterMs;
|
|
102677
|
-
|
|
102678
|
-
|
|
103289
|
+
holder;
|
|
103290
|
+
constructor(retryAfterMs, holder = null) {
|
|
103291
|
+
super(holder ? `Remote sync is temporarily reserved by ${holder.ownerId} (${holder.purpose}, lease ${holder.leaseId}, ${Math.ceil(holder.remainingMs / 1000)}s left)` : "Remote sync is temporarily reserved by another compatible client");
|
|
102679
103292
|
this.name = "SyncRemoteMutationFenceBusyError";
|
|
102680
103293
|
this.retryAfterMs = Math.max(0, Math.floor(retryAfterMs));
|
|
103294
|
+
this.holder = holder;
|
|
102681
103295
|
}
|
|
102682
103296
|
};
|
|
102683
103297
|
SyncRemoteMutationFenceLostError = class SyncRemoteMutationFenceLostError extends Error {
|
|
@@ -102708,6 +103322,7 @@ class SharedSyncRunMachine {
|
|
|
102708
103322
|
performSyncCycleImpl;
|
|
102709
103323
|
io = null;
|
|
102710
103324
|
remoteMutationFence = null;
|
|
103325
|
+
carriedIdleSnapshot = takeIdleCycleSnapshot();
|
|
102711
103326
|
state = {
|
|
102712
103327
|
backend: "off",
|
|
102713
103328
|
cloudProvider: "selfhosted",
|
|
@@ -102715,10 +103330,14 @@ class SharedSyncRunMachine {
|
|
|
102715
103330
|
fastSyncScope: null,
|
|
102716
103331
|
localSnapshotChangeAt: 0,
|
|
102717
103332
|
localDataCache: null,
|
|
103333
|
+
localSnapshotMatchesDisk: false,
|
|
103334
|
+
localDocumentFingerprint: null,
|
|
103335
|
+
fastSyncStateCache: null,
|
|
102718
103336
|
preSyncedLocalData: null,
|
|
102719
103337
|
wroteLocal: false,
|
|
102720
103338
|
remoteDataForCompare: null,
|
|
102721
103339
|
readCheckRemoteData: undefined,
|
|
103340
|
+
localOnlyUploadFingerprint: null,
|
|
102722
103341
|
lastRemoteWriteFingerprint: null,
|
|
102723
103342
|
lastRemoteWriteMergedServerData: false,
|
|
102724
103343
|
webdavRemoteCorrupted: false,
|
|
@@ -102784,10 +103403,14 @@ class SharedSyncRunMachine {
|
|
|
102784
103403
|
await this.runAttachmentPreSyncPhase();
|
|
102785
103404
|
}
|
|
102786
103405
|
let skipResult = null;
|
|
103406
|
+
let localOnlyUpload = false;
|
|
102787
103407
|
if (!this.options.activationProbe) {
|
|
102788
103408
|
skipResult = await this.trySkipUnchangedFastSync();
|
|
103409
|
+
if (!skipResult) {
|
|
103410
|
+
localOnlyUpload = await this.tryArmLocalOnlyUploadFastPath();
|
|
103411
|
+
}
|
|
102789
103412
|
}
|
|
102790
|
-
if (!this.options.activationProbe && !skipResult && this.policy.enableReadCheckSkip) {
|
|
103413
|
+
if (!this.options.activationProbe && !skipResult && !localOnlyUpload && this.policy.enableReadCheckSkip) {
|
|
102791
103414
|
skipResult = await this.trySkipUnchangedReadSync();
|
|
102792
103415
|
}
|
|
102793
103416
|
if (skipResult) {
|
|
@@ -102831,10 +103454,18 @@ class SharedSyncRunMachine {
|
|
|
102831
103454
|
const lease = await this.runRemoteMutationFenceOperation("Remote sync mutation fence acquisition failed", acquire);
|
|
102832
103455
|
if (!lease)
|
|
102833
103456
|
return;
|
|
103457
|
+
if (lease.reclaimedFrom) {
|
|
103458
|
+
const from = lease.reclaimedFrom;
|
|
103459
|
+
this.notifier.logWarning("Reclaimed an abandoned remote sync reservation", new Error(`${from.ownerId} (${from.purpose}, lease ${from.leaseId}) stopped renewing with ${Math.ceil(from.remainingMs / 1000)}s left`));
|
|
103460
|
+
}
|
|
102834
103461
|
this.remoteMutationFence = lease;
|
|
102835
103462
|
this.state.readCheckRemoteData = undefined;
|
|
102836
103463
|
this.state.remoteDataForCompare = null;
|
|
102837
103464
|
}
|
|
103465
|
+
async acquireAndAssertRemoteMutationFence(minRemainingMs) {
|
|
103466
|
+
await this.ensureRemoteMutationFence();
|
|
103467
|
+
await this.assertRemoteMutationFenceHeld(minRemainingMs);
|
|
103468
|
+
}
|
|
102838
103469
|
async assertRemoteMutationFenceHeld(minRemainingMs = SYNC_REMOTE_MUTATION_REQUEST_HORIZON_MS) {
|
|
102839
103470
|
if (!this.remoteMutationFence)
|
|
102840
103471
|
return;
|
|
@@ -102882,7 +103513,7 @@ class SharedSyncRunMachine {
|
|
|
102882
103513
|
attachmentHelpers(phase) {
|
|
102883
103514
|
return {
|
|
102884
103515
|
ensureLocalSnapshotFresh: () => this.ensureLocalSnapshotFresh(),
|
|
102885
|
-
assertRemoteMutationFenceHeld: (minRemainingMs) => this.
|
|
103516
|
+
assertRemoteMutationFenceHeld: (minRemainingMs) => this.acquireAndAssertRemoteMutationFence(minRemainingMs),
|
|
102886
103517
|
activationProbe: this.options.activationProbe === true,
|
|
102887
103518
|
phase
|
|
102888
103519
|
};
|
|
@@ -102918,15 +103549,38 @@ class SharedSyncRunMachine {
|
|
|
102918
103549
|
this.state.localSnapshotChangeAt = currentChangeAt;
|
|
102919
103550
|
return this.state.localDataCache.data;
|
|
102920
103551
|
}
|
|
103552
|
+
const carried = this.policy.carryIdleCycleSnapshot ? this.carriedIdleSnapshot : null;
|
|
103553
|
+
if (carried && carried.scope === this.state.fastSyncScope && carried.changeAt === currentChangeAt && !this.state.preSyncedLocalData && !this.options.activationProbe && (await this.readFastSyncState(carried.scope))?.localFingerprint === carried.fingerprint) {
|
|
103554
|
+
this.state.localSnapshotChangeAt = currentChangeAt;
|
|
103555
|
+
this.state.localDataCache = { changeAt: currentChangeAt, data: carried.data };
|
|
103556
|
+
this.state.localSnapshotMatchesDisk = true;
|
|
103557
|
+
this.state.localDocumentFingerprint = { data: carried.data, fingerprint: carried.fingerprint };
|
|
103558
|
+
this.notifier.logInfo("Sync local reconcile", {
|
|
103559
|
+
reconcile: "idle-cache",
|
|
103560
|
+
durationMs: "0",
|
|
103561
|
+
tasks: String(carried.data.tasks.length)
|
|
103562
|
+
});
|
|
103563
|
+
return carried.data;
|
|
103564
|
+
}
|
|
102921
103565
|
const inMemorySnapshot = this.store.getInMemorySnapshot();
|
|
102922
103566
|
let baseData;
|
|
103567
|
+
let matchesDisk = false;
|
|
102923
103568
|
if (this.state.preSyncedLocalData) {
|
|
102924
|
-
|
|
103569
|
+
const preSynced = this.state.preSyncedLocalData;
|
|
103570
|
+
const reconcileStart = Date.now();
|
|
103571
|
+
const aligned = computeSyncChangeFingerprint(preSynced) === computeSyncChangeFingerprint(inMemorySnapshot) && computeAttachmentIdentityDigest(preSynced) === computeAttachmentIdentityDigest(inMemorySnapshot);
|
|
103572
|
+
baseData = aligned ? preSynced : mergeAppData(preSynced, inMemorySnapshot);
|
|
103573
|
+
this.notifier.logInfo("Sync local reconcile", {
|
|
103574
|
+
reconcile: aligned ? "aligned-skip-presynced" : "merged-presynced",
|
|
103575
|
+
durationMs: String(Date.now() - reconcileStart),
|
|
103576
|
+
tasks: String(baseData.tasks.length)
|
|
103577
|
+
});
|
|
102925
103578
|
} else {
|
|
102926
103579
|
const persisted = await this.storage.readPersistedLocal();
|
|
102927
103580
|
const reconcileStart = Date.now();
|
|
102928
103581
|
const aligned = computeSyncChangeFingerprint(persisted) === computeSyncChangeFingerprint(inMemorySnapshot);
|
|
102929
103582
|
baseData = aligned ? persisted : mergeAppData(persisted, inMemorySnapshot);
|
|
103583
|
+
matchesDisk = aligned;
|
|
102930
103584
|
this.notifier.logInfo("Sync local reconcile", {
|
|
102931
103585
|
reconcile: aligned ? "aligned-skip" : "merged",
|
|
102932
103586
|
durationMs: String(Date.now() - reconcileStart),
|
|
@@ -102939,12 +103593,14 @@ class SharedSyncRunMachine {
|
|
|
102939
103593
|
changeAt: currentChangeAt,
|
|
102940
103594
|
data
|
|
102941
103595
|
};
|
|
103596
|
+
this.state.localSnapshotMatchesDisk = matchesDisk && data === baseData;
|
|
102942
103597
|
return data;
|
|
102943
103598
|
}
|
|
102944
103599
|
async persistLocalDataWithTracking(data) {
|
|
102945
103600
|
await this.assertRemoteMutationFenceHeld();
|
|
102946
103601
|
const persisted = await this.storage.persistLocal(data) ?? data;
|
|
102947
103602
|
this.ensureLocalSnapshotFresh(persisted);
|
|
103603
|
+
this.state.localSnapshotMatchesDisk = false;
|
|
102948
103604
|
if (this.storage.applyDataToStore) {
|
|
102949
103605
|
this.storage.applyDataToStore(persisted);
|
|
102950
103606
|
const currentChangeAt = this.store.getLastDataChangeAt();
|
|
@@ -102975,6 +103631,10 @@ class SharedSyncRunMachine {
|
|
|
102975
103631
|
this.state.remoteDataForCompare = data;
|
|
102976
103632
|
return data;
|
|
102977
103633
|
}
|
|
103634
|
+
if (this.state.localOnlyUploadFingerprint) {
|
|
103635
|
+
this.state.remoteDataForCompare = null;
|
|
103636
|
+
return null;
|
|
103637
|
+
}
|
|
102978
103638
|
await this.ensureNetwork();
|
|
102979
103639
|
try {
|
|
102980
103640
|
const raw = await this.requireIo().readRemote();
|
|
@@ -103005,7 +103665,23 @@ class SharedSyncRunMachine {
|
|
|
103005
103665
|
return null;
|
|
103006
103666
|
return io.readRemoteFingerprint();
|
|
103007
103667
|
}
|
|
103668
|
+
assertLocalOnlyUploadIsCanonical(data) {
|
|
103669
|
+
if (!this.state.localOnlyUploadFingerprint)
|
|
103670
|
+
return;
|
|
103671
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV !== "development")
|
|
103672
|
+
return;
|
|
103673
|
+
const parsedEmpty = parseSyncDocument({}, "remote");
|
|
103674
|
+
const emptyRemote = parsedEmpty.ok ? parsedEmpty.data : { tasks: [], projects: [], sections: [], areas: [], people: [], settings: {} };
|
|
103675
|
+
const asWritten = toStableSyncJson(toRemoteSyncDocument(data));
|
|
103676
|
+
const asMerged = toStableSyncJson(toRemoteSyncDocument(mergeAppData(data, emptyRemote)));
|
|
103677
|
+
if (asWritten === asMerged)
|
|
103678
|
+
return;
|
|
103679
|
+
const message3 = "Sync canonical-read invariant broken: the local-only upload fast path " + "is about to publish a document the normalize pass would still change. A local " + "write path is producing a non-canonical entity; see " + "sync-canonical-reads.contract.test.ts.";
|
|
103680
|
+
this.notifier.logWarning(message3);
|
|
103681
|
+
throw new Error(message3);
|
|
103682
|
+
}
|
|
103008
103683
|
async writeRemoteForCycle(data) {
|
|
103684
|
+
this.assertLocalOnlyUploadIsCanonical(data);
|
|
103009
103685
|
await this.ensureRemoteMutationFence();
|
|
103010
103686
|
await this.assertRemoteMutationFenceHeld();
|
|
103011
103687
|
await this.ensureNetwork();
|
|
@@ -103039,7 +103715,7 @@ class SharedSyncRunMachine {
|
|
|
103039
103715
|
} catch (error2) {
|
|
103040
103716
|
if (error2 instanceof SyncRemoteWriteConflict) {
|
|
103041
103717
|
this.requestFollowUp();
|
|
103042
|
-
throw new LocalSyncAbort;
|
|
103718
|
+
throw new LocalSyncAbort("remote-write-conflict");
|
|
103043
103719
|
}
|
|
103044
103720
|
throw error2;
|
|
103045
103721
|
}
|
|
@@ -103089,8 +103765,8 @@ class SharedSyncRunMachine {
|
|
|
103089
103765
|
this.ensureLocalSnapshotFresh();
|
|
103090
103766
|
if (hasPendingSyncSideEffects(localData))
|
|
103091
103767
|
return null;
|
|
103092
|
-
const localFingerprint =
|
|
103093
|
-
const cached2 = await this.
|
|
103768
|
+
const localFingerprint = this.localDocumentFingerprint(localData);
|
|
103769
|
+
const cached2 = await this.readFastSyncState(scope);
|
|
103094
103770
|
if (!cached2 || cached2.localFingerprint !== localFingerprint)
|
|
103095
103771
|
return null;
|
|
103096
103772
|
let remoteFingerprint = null;
|
|
@@ -103103,16 +103779,64 @@ class SharedSyncRunMachine {
|
|
|
103103
103779
|
if (!remoteFingerprint || remoteFingerprint !== cached2.remoteFingerprint)
|
|
103104
103780
|
return null;
|
|
103105
103781
|
this.ensureLocalSnapshotFresh();
|
|
103106
|
-
await this.
|
|
103782
|
+
await this.writeFastSyncState({
|
|
103107
103783
|
scope,
|
|
103108
103784
|
localFingerprint,
|
|
103109
103785
|
remoteFingerprint,
|
|
103110
103786
|
checkedAt: this.nowIso()
|
|
103111
103787
|
});
|
|
103112
103788
|
await this.persistUnchangedSyncStatus();
|
|
103789
|
+
this.publishIdleCycleSnapshot(localData, localFingerprint);
|
|
103113
103790
|
this.notifier.logInfo("Sync fast check found no changes", { backend: this.backend });
|
|
103791
|
+
this.logUnchangedCycleSkips("fast");
|
|
103114
103792
|
return { success: true, skipped: "unchanged" };
|
|
103115
103793
|
}
|
|
103794
|
+
async tryArmLocalOnlyUploadFastPath() {
|
|
103795
|
+
if (this.options.manual)
|
|
103796
|
+
return false;
|
|
103797
|
+
if (this.options.ignorePendingRemoteWriteBackoff)
|
|
103798
|
+
return false;
|
|
103799
|
+
const scope = this.state.fastSyncScope;
|
|
103800
|
+
if (!scope)
|
|
103801
|
+
return false;
|
|
103802
|
+
const io = this.requireIo();
|
|
103803
|
+
if (!io.adoptRemoteFingerprintForWrite || !io.readRemoteFingerprint)
|
|
103804
|
+
return false;
|
|
103805
|
+
if (io.requiresRemoteRepair?.() === true)
|
|
103806
|
+
return false;
|
|
103807
|
+
if (!this.policy.preSyncAttachmentsBeforeFastCheck)
|
|
103808
|
+
return false;
|
|
103809
|
+
this.setStep("fast-check");
|
|
103810
|
+
await this.yieldToUi();
|
|
103811
|
+
if (this.state.preSyncedLocalData)
|
|
103812
|
+
return false;
|
|
103813
|
+
const localData = await this.readLocalDataForSyncCycle();
|
|
103814
|
+
this.ensureLocalSnapshotFresh();
|
|
103815
|
+
if (hasPendingSyncSideEffects(localData))
|
|
103816
|
+
return false;
|
|
103817
|
+
const cached2 = await this.readFastSyncState(scope);
|
|
103818
|
+
if (!cached2)
|
|
103819
|
+
return false;
|
|
103820
|
+
if (cached2.localFingerprint === this.localDocumentFingerprint(localData))
|
|
103821
|
+
return false;
|
|
103822
|
+
let remoteFingerprint = null;
|
|
103823
|
+
try {
|
|
103824
|
+
remoteFingerprint = await this.readRemoteFingerprint();
|
|
103825
|
+
} catch (error2) {
|
|
103826
|
+
this.notifier.logWarning("Sync fast check failed; falling back to full sync", error2);
|
|
103827
|
+
return false;
|
|
103828
|
+
}
|
|
103829
|
+
if (!remoteFingerprint || remoteFingerprint !== cached2.remoteFingerprint)
|
|
103830
|
+
return false;
|
|
103831
|
+
if (!io.adoptRemoteFingerprintForWrite(remoteFingerprint))
|
|
103832
|
+
return false;
|
|
103833
|
+
this.ensureLocalSnapshotFresh();
|
|
103834
|
+
this.state.localOnlyUploadFingerprint = remoteFingerprint;
|
|
103835
|
+
this.notifier.logInfo("Sync uploading a local-only change without a remote read", {
|
|
103836
|
+
backend: this.backend
|
|
103837
|
+
});
|
|
103838
|
+
return true;
|
|
103839
|
+
}
|
|
103116
103840
|
async trySkipUnchangedReadSync() {
|
|
103117
103841
|
this.setStep("read-check");
|
|
103118
103842
|
await this.yieldToUi();
|
|
@@ -103129,14 +103853,16 @@ class SharedSyncRunMachine {
|
|
|
103129
103853
|
this.state.readCheckRemoteData = remoteData;
|
|
103130
103854
|
if (hasUncompactedPurgedTombstones(remoteData))
|
|
103131
103855
|
return null;
|
|
103132
|
-
const
|
|
103133
|
-
const
|
|
103134
|
-
if (
|
|
103856
|
+
const localFingerprint = this.localDocumentFingerprint(localData);
|
|
103857
|
+
const remoteFingerprint = computeRemoteSyncDocumentFingerprint(toRemoteSyncDocument(remoteData));
|
|
103858
|
+
if (localFingerprint !== remoteFingerprint)
|
|
103135
103859
|
return null;
|
|
103136
103860
|
await this.recordFastSyncState(localData, { allowRemoteFingerprintRead: false });
|
|
103137
103861
|
await this.persistUnchangedSyncStatus();
|
|
103862
|
+
this.publishIdleCycleSnapshot(localData, localFingerprint);
|
|
103138
103863
|
this.state.readCheckRemoteData = undefined;
|
|
103139
103864
|
this.notifier.logInfo("Sync read check found no changes", { backend: this.backend });
|
|
103865
|
+
this.logUnchangedCycleSkips("read");
|
|
103140
103866
|
return { success: true, skipped: "unchanged" };
|
|
103141
103867
|
}
|
|
103142
103868
|
async recordFastSyncState(data, options = {}) {
|
|
@@ -103163,13 +103889,71 @@ class SharedSyncRunMachine {
|
|
|
103163
103889
|
}
|
|
103164
103890
|
if (!remoteFingerprint)
|
|
103165
103891
|
return;
|
|
103166
|
-
await this.
|
|
103892
|
+
await this.writeFastSyncState({
|
|
103167
103893
|
scope,
|
|
103168
|
-
localFingerprint:
|
|
103894
|
+
localFingerprint: this.localDocumentFingerprint(data),
|
|
103169
103895
|
remoteFingerprint,
|
|
103170
103896
|
checkedAt: this.nowIso()
|
|
103171
103897
|
});
|
|
103172
103898
|
}
|
|
103899
|
+
async readFastSyncState(scope) {
|
|
103900
|
+
const cached2 = this.state.fastSyncStateCache;
|
|
103901
|
+
if (cached2 && cached2.scope === scope)
|
|
103902
|
+
return cached2.value;
|
|
103903
|
+
const value = await this.storage.readFastSyncState(scope);
|
|
103904
|
+
this.state.fastSyncStateCache = { scope, value };
|
|
103905
|
+
return value;
|
|
103906
|
+
}
|
|
103907
|
+
async writeFastSyncState(state) {
|
|
103908
|
+
this.state.fastSyncStateCache = { scope: state.scope, value: state };
|
|
103909
|
+
await this.storage.writeFastSyncState(state);
|
|
103910
|
+
}
|
|
103911
|
+
localDocumentFingerprint(data) {
|
|
103912
|
+
const cached2 = this.state.localDocumentFingerprint;
|
|
103913
|
+
if (cached2 && cached2.data === data)
|
|
103914
|
+
return cached2.fingerprint;
|
|
103915
|
+
const fingerprint = computeRemoteSyncDocumentFingerprint(toRemoteSyncDocument(data));
|
|
103916
|
+
this.state.localDocumentFingerprint = { data, fingerprint };
|
|
103917
|
+
return fingerprint;
|
|
103918
|
+
}
|
|
103919
|
+
isLocalPersistUnchanged(data) {
|
|
103920
|
+
if (this.options.activationProbe)
|
|
103921
|
+
return false;
|
|
103922
|
+
if (!this.state.localSnapshotMatchesDisk)
|
|
103923
|
+
return false;
|
|
103924
|
+
const stored = this.state.localDataCache?.data;
|
|
103925
|
+
if (!stored)
|
|
103926
|
+
return false;
|
|
103927
|
+
return isLocalPersistEquivalent(data, stored);
|
|
103928
|
+
}
|
|
103929
|
+
logUnchangedCycleSkips(check2) {
|
|
103930
|
+
const skippedPasses = ["local-persist", "store-refresh", "attachments"];
|
|
103931
|
+
if (!this.remoteMutationFence)
|
|
103932
|
+
skippedPasses.push("remote-fence");
|
|
103933
|
+
this.notifier.logInfo("Sync cycle changed nothing; passes skipped", {
|
|
103934
|
+
releaseCheck: "v1.2.7/cycle-unchanged-skip",
|
|
103935
|
+
backend: this.backend,
|
|
103936
|
+
check: check2,
|
|
103937
|
+
skipped: skippedPasses.join(",")
|
|
103938
|
+
});
|
|
103939
|
+
}
|
|
103940
|
+
publishIdleCycleSnapshot(data, fingerprint) {
|
|
103941
|
+
const scope = this.state.fastSyncScope;
|
|
103942
|
+
if (!this.policy.carryIdleCycleSnapshot)
|
|
103943
|
+
return;
|
|
103944
|
+
if (!scope || this.options.activationProbe)
|
|
103945
|
+
return;
|
|
103946
|
+
if (!this.state.localSnapshotMatchesDisk || this.state.wroteLocal)
|
|
103947
|
+
return;
|
|
103948
|
+
if (this.store.getLastDataChangeAt() !== this.state.localSnapshotChangeAt)
|
|
103949
|
+
return;
|
|
103950
|
+
idleCycleSnapshot = {
|
|
103951
|
+
scope,
|
|
103952
|
+
changeAt: this.state.localSnapshotChangeAt,
|
|
103953
|
+
data,
|
|
103954
|
+
fingerprint
|
|
103955
|
+
};
|
|
103956
|
+
}
|
|
103173
103957
|
async runAttachmentPreSyncPhase() {
|
|
103174
103958
|
if (!this.policy.attachmentPhasesEnabled || this.options.activationProbe)
|
|
103175
103959
|
return;
|
|
@@ -103186,7 +103970,6 @@ class SharedSyncRunMachine {
|
|
|
103186
103970
|
if (isRemoteSyncBackend(this.backend)) {
|
|
103187
103971
|
await this.ensureNetwork();
|
|
103188
103972
|
}
|
|
103189
|
-
await this.ensureRemoteMutationFence();
|
|
103190
103973
|
const result = await io.syncAttachments(localData, this.attachmentHelpers("prepare"));
|
|
103191
103974
|
await this.assertRemoteMutationFenceHeld();
|
|
103192
103975
|
const mutated = result === true || Boolean(result) && typeof result === "object";
|
|
@@ -103241,7 +104024,7 @@ class SharedSyncRunMachine {
|
|
|
103241
104024
|
await this.assertRemoteMutationFenceHeld();
|
|
103242
104025
|
provenData = result2 && typeof result2 === "object" ? result2 : fallbackRetry.data;
|
|
103243
104026
|
}
|
|
103244
|
-
assertActivationAttachmentsProven(provenData, activationSnapshot.expectedIds);
|
|
104027
|
+
assertActivationAttachmentsProven(provenData, activationSnapshot.expectedIds, activationSnapshot.metadataOnlyIds, activationSnapshot.noLocalBytesIds);
|
|
103245
104028
|
this.ensureLocalSnapshotFresh();
|
|
103246
104029
|
this.notifier.onDiagnostic?.({
|
|
103247
104030
|
event: "attachments-prepare-complete",
|
|
@@ -103373,6 +104156,19 @@ class SharedSyncRunMachine {
|
|
|
103373
104156
|
});
|
|
103374
104157
|
},
|
|
103375
104158
|
flushPendingLocalBeforeRetryRead: () => this.options.activationProbe ? Promise.resolve() : this.store.flushPendingSave(),
|
|
104159
|
+
isLocalPersistUnchanged: (data) => this.isLocalPersistUnchanged(data),
|
|
104160
|
+
persistSyncStatusOnly: async (data) => {
|
|
104161
|
+
this.notifier.logInfo("Sync local write skipped; merged document matches stored", {
|
|
104162
|
+
backend: this.backend
|
|
104163
|
+
});
|
|
104164
|
+
await this.storage.persistSyncStatus({
|
|
104165
|
+
lastSyncAt: data.settings.lastSyncAt,
|
|
104166
|
+
lastSyncStatus: data.settings.lastSyncStatus,
|
|
104167
|
+
lastSyncError: data.settings.lastSyncError,
|
|
104168
|
+
lastSyncStats: data.settings.lastSyncStats,
|
|
104169
|
+
lastSyncHistory: data.settings.lastSyncHistory
|
|
104170
|
+
});
|
|
104171
|
+
},
|
|
103376
104172
|
prepareRemoteWrite: (data) => this.prepareRemoteWriteData(data),
|
|
103377
104173
|
writeRemote: async (data) => {
|
|
103378
104174
|
this.notifier.tracePayload?.("write-remote", data, { backend: this.backend });
|
|
@@ -103380,6 +104176,7 @@ class SharedSyncRunMachine {
|
|
|
103380
104176
|
await this.writeRemoteForCycle(data);
|
|
103381
104177
|
},
|
|
103382
104178
|
preferIncomingAttachmentCloudKeys: this.options.ignorePendingRemoteWriteBackoff === true,
|
|
104179
|
+
skipEmptyRemoteMerge: () => this.state.localOnlyUploadFingerprint !== null,
|
|
103383
104180
|
onStep: (next) => this.setStep(next),
|
|
103384
104181
|
yieldToUi: this.notifier.yieldToUi ? () => this.notifier.yieldToUi() : undefined,
|
|
103385
104182
|
historyContext: {
|
|
@@ -103466,9 +104263,11 @@ class SharedSyncRunMachine {
|
|
|
103466
104263
|
await this.yieldToUi();
|
|
103467
104264
|
this.ensureLocalSnapshotFresh(mergedData);
|
|
103468
104265
|
await this.assertRemoteMutationFenceHeld();
|
|
104266
|
+
const localWriteSkipped = syncResult.localWriteSkipped && !this.state.wroteLocal ? true : undefined;
|
|
103469
104267
|
await this.hooks.finalizeSuccess(mergedData, {
|
|
103470
104268
|
status: syncResult.status,
|
|
103471
104269
|
wroteLocal: this.state.wroteLocal,
|
|
104270
|
+
localWriteSkipped,
|
|
103472
104271
|
getLocalSnapshotChangeAt: () => this.state.localSnapshotChangeAt,
|
|
103473
104272
|
acceptCoveredSnapshot: (expectedData) => this.acceptCoveredLocalSnapshot(expectedData)
|
|
103474
104273
|
});
|
|
@@ -103480,6 +104279,7 @@ class SharedSyncRunMachine {
|
|
|
103480
104279
|
attachmentWriteDeferred: attachmentWriteDeferred || undefined,
|
|
103481
104280
|
fileAttachmentUploadBlocked: this.state.fileAttachmentUploadBlocked ?? undefined,
|
|
103482
104281
|
error: mergedData.settings.lastSyncError,
|
|
104282
|
+
localWriteSkipped,
|
|
103483
104283
|
stats
|
|
103484
104284
|
};
|
|
103485
104285
|
}
|
|
@@ -103487,6 +104287,7 @@ class SharedSyncRunMachine {
|
|
|
103487
104287
|
success: true,
|
|
103488
104288
|
attachmentWriteDeferred: attachmentWriteDeferred || undefined,
|
|
103489
104289
|
fileAttachmentUploadBlocked: this.state.fileAttachmentUploadBlocked ?? undefined,
|
|
104290
|
+
localWriteSkipped,
|
|
103490
104291
|
stats
|
|
103491
104292
|
};
|
|
103492
104293
|
}
|
|
@@ -103512,6 +104313,7 @@ class SharedSyncRunMachine {
|
|
|
103512
104313
|
};
|
|
103513
104314
|
}
|
|
103514
104315
|
if (error2 instanceof SyncRemoteMutationFenceBusyError) {
|
|
104316
|
+
this.notifier.logWarning("Remote sync location is reserved; retrying after the lease lapses", error2);
|
|
103515
104317
|
if (!this.options.activationProbe)
|
|
103516
104318
|
this.requestFollowUpAfter(error2.retryAfterMs);
|
|
103517
104319
|
return {
|
|
@@ -103533,6 +104335,12 @@ class SharedSyncRunMachine {
|
|
|
103533
104335
|
if (!this.options.activationProbe) {
|
|
103534
104336
|
await this.persistPreSyncedDataAfterAbort();
|
|
103535
104337
|
}
|
|
104338
|
+
this.notifier.logInfo("Sync cycle requeued", {
|
|
104339
|
+
backend: this.backend,
|
|
104340
|
+
step: this.state.step ?? "-",
|
|
104341
|
+
reason: error2.reason,
|
|
104342
|
+
activationProbe: String(this.options.activationProbe === true)
|
|
104343
|
+
});
|
|
103536
104344
|
this.notifier.onDiagnostic?.({
|
|
103537
104345
|
event: "requeued",
|
|
103538
104346
|
extra: {
|
|
@@ -103615,7 +104423,28 @@ var normalizeRemoteWriteResult = (source, result) => {
|
|
|
103615
104423
|
fingerprint,
|
|
103616
104424
|
serverMergedRemoteData: result.serverMergedRemoteData === true
|
|
103617
104425
|
};
|
|
103618
|
-
}, DEFAULT_CLEANUP_INTERVAL_MS,
|
|
104426
|
+
}, DEFAULT_CLEANUP_INTERVAL_MS, computeAttachmentIdentityDigest = (data) => {
|
|
104427
|
+
const parts = [];
|
|
104428
|
+
const append = (items) => {
|
|
104429
|
+
for (const item of items ?? []) {
|
|
104430
|
+
const attachments = item.attachments;
|
|
104431
|
+
if (!attachments || attachments.length === 0)
|
|
104432
|
+
continue;
|
|
104433
|
+
const ordered = [...attachments].sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0);
|
|
104434
|
+
parts.push(`${item.id}:${toStableSyncJson(ordered)}`);
|
|
104435
|
+
}
|
|
104436
|
+
};
|
|
104437
|
+
append(data.tasks);
|
|
104438
|
+
append(data.projects);
|
|
104439
|
+
return parts.join(`
|
|
104440
|
+
`);
|
|
104441
|
+
}, idleCycleSnapshot = null, takeIdleCycleSnapshot = () => {
|
|
104442
|
+
const carried = idleCycleSnapshot;
|
|
104443
|
+
idleCycleSnapshot = null;
|
|
104444
|
+
return carried;
|
|
104445
|
+
}, clearIdleSyncCycleSnapshot = () => {
|
|
104446
|
+
idleCycleSnapshot = null;
|
|
104447
|
+
}, withoutInheritedPendingRemoteWrite = (data) => {
|
|
103619
104448
|
if (!data.settings.pendingRemoteWriteAt && data.settings.pendingRemoteWriteRetryAt === undefined && data.settings.pendingRemoteWriteAttempts === undefined) {
|
|
103620
104449
|
return data;
|
|
103621
104450
|
}
|
|
@@ -103696,9 +104525,17 @@ var normalizeRemoteWriteResult = (source, result) => {
|
|
|
103696
104525
|
const candidate = cloneAppData(data);
|
|
103697
104526
|
const expectedIds = new Set;
|
|
103698
104527
|
const localFallbacks = new Map;
|
|
104528
|
+
const metadataOnlyIds = new Set;
|
|
104529
|
+
const noLocalBytesIds = new Set;
|
|
103699
104530
|
const count = visitLiveFileAttachments(candidate, (attachment) => {
|
|
103700
104531
|
expectedIds.add(attachment.id);
|
|
103701
104532
|
const candidateAttachment = candidateAttachments.get(attachment.id);
|
|
104533
|
+
const localAttachment = localAttachments.get(attachment.id);
|
|
104534
|
+
const noLocalBytes = !localAttachment?.cloudKey && (!localAttachment || !localAttachment.uri?.trim() || localAttachment.localStatus === "missing");
|
|
104535
|
+
if (noLocalBytes)
|
|
104536
|
+
noLocalBytesIds.add(attachment.id);
|
|
104537
|
+
if (noLocalBytes && !candidateAttachment?.cloudKey)
|
|
104538
|
+
metadataOnlyIds.add(attachment.id);
|
|
103702
104539
|
const mustReplaceCandidateBlob = Boolean(candidateAttachment?.cloudKey && mergedContentMustReplaceCandidateBlob(attachment, candidateAttachment));
|
|
103703
104540
|
if (!mustReplaceCandidateBlob) {
|
|
103704
104541
|
const fallback = buildExactLocalActivationFallback(attachment, localAttachments.get(attachment.id), candidateAttachment);
|
|
@@ -103712,7 +104549,7 @@ var normalizeRemoteWriteResult = (source, result) => {
|
|
|
103712
104549
|
}
|
|
103713
104550
|
attachment.localStatus = "missing";
|
|
103714
104551
|
});
|
|
103715
|
-
return { data: candidate, count, expectedIds, localFallbacks };
|
|
104552
|
+
return { data: candidate, count, expectedIds, localFallbacks, metadataOnlyIds, noLocalBytesIds };
|
|
103716
104553
|
}, prepareActivationFallbackRetry = (data, localFallbacks) => {
|
|
103717
104554
|
if (localFallbacks.size === 0)
|
|
103718
104555
|
return { data, count: 0 };
|
|
@@ -103732,7 +104569,7 @@ var normalizeRemoteWriteResult = (source, result) => {
|
|
|
103732
104569
|
}
|
|
103733
104570
|
}
|
|
103734
104571
|
return count > 0 ? { data: retryData, count } : { data, count: 0 };
|
|
103735
|
-
}, assertActivationAttachmentsProven = (data, expectedIds) => {
|
|
104572
|
+
}, assertActivationAttachmentsProven = (data, expectedIds, metadataOnlyIds, noLocalBytesIds) => {
|
|
103736
104573
|
const resolved = new Set;
|
|
103737
104574
|
for (const owner of [...data.tasks, ...data.projects]) {
|
|
103738
104575
|
for (const attachment of owner.attachments ?? []) {
|
|
@@ -103740,10 +104577,18 @@ var normalizeRemoteWriteResult = (source, result) => {
|
|
|
103740
104577
|
continue;
|
|
103741
104578
|
if (owner.deletedAt || attachment.deletedAt) {
|
|
103742
104579
|
if (expectedIds.has(attachment.id)) {
|
|
103743
|
-
|
|
104580
|
+
if (!noLocalBytesIds.has(attachment.id)) {
|
|
104581
|
+
throw new Error(`Candidate attachment proof failed for ${attachment.id}`);
|
|
104582
|
+
}
|
|
104583
|
+
resolved.add(attachment.id);
|
|
103744
104584
|
}
|
|
103745
104585
|
continue;
|
|
103746
104586
|
}
|
|
104587
|
+
if (metadataOnlyIds.has(attachment.id) && !attachment.cloudKey && attachment.localStatus === "missing" && attachment.pendingContentUpload !== true) {
|
|
104588
|
+
if (expectedIds.has(attachment.id))
|
|
104589
|
+
resolved.add(attachment.id);
|
|
104590
|
+
continue;
|
|
104591
|
+
}
|
|
103747
104592
|
if (!attachment.cloudKey || attachment.localStatus !== "available" || attachment.pendingContentUpload === true) {
|
|
103748
104593
|
throw new Error(`Candidate attachment proof failed for ${attachment.id}`);
|
|
103749
104594
|
}
|
|
@@ -104416,8 +105261,19 @@ var DROPBOX_SYNC_PATH = "/data.json", DOWNLOAD_ENDPOINT = "https://content.dropb
|
|
|
104416
105261
|
throw new Error(`Dropbox download failed: HTTP ${response.status}`);
|
|
104417
105262
|
}
|
|
104418
105263
|
return "ok";
|
|
105264
|
+
}, DROPBOX_ATTACHMENTS_PATH, createDropboxAttachmentPresenceIndex = (entries) => {
|
|
105265
|
+
const names = new Set(entries.map((entry) => entry.name.toLowerCase()));
|
|
105266
|
+
return (cloudKey) => {
|
|
105267
|
+
const segments = cloudKey.split("/");
|
|
105268
|
+
if (segments.length !== 2)
|
|
105269
|
+
return null;
|
|
105270
|
+
if (segments[0] !== ATTACHMENTS_DIR_NAME || !segments[1])
|
|
105271
|
+
return null;
|
|
105272
|
+
return names.has(segments[1].toLowerCase());
|
|
105273
|
+
};
|
|
104419
105274
|
};
|
|
104420
105275
|
var init_dropbox = __esm(() => {
|
|
105276
|
+
init_attachment_paths();
|
|
104421
105277
|
init_dropbox_sync_utils();
|
|
104422
105278
|
init_http_utils();
|
|
104423
105279
|
init_sync_encryption();
|
|
@@ -104441,6 +105297,7 @@ var init_dropbox = __esm(() => {
|
|
|
104441
105297
|
this.name = "DropboxFileNotFoundError";
|
|
104442
105298
|
}
|
|
104443
105299
|
};
|
|
105300
|
+
DROPBOX_ATTACHMENTS_PATH = `/${ATTACHMENTS_DIR_NAME}`;
|
|
104444
105301
|
});
|
|
104445
105302
|
|
|
104446
105303
|
// ../../packages/core/src/sync-backend-io.ts
|
|
@@ -104484,6 +105341,28 @@ function createSyncBackendIO(ctx, transport) {
|
|
|
104484
105341
|
},
|
|
104485
105342
|
getSyncUrl: () => ctx.syncUrl,
|
|
104486
105343
|
getCachedRemoteFingerprint: () => ctx.backend === "cloud" && ctx.cloudProvider === "dropbox" && ctx.dropboxRev ? buildDropboxRevFingerprint(ctx.dropboxRev) : null,
|
|
105344
|
+
adoptRemoteFingerprintForWrite: (fingerprint) => {
|
|
105345
|
+
if (ctx.backend === "webdav") {
|
|
105346
|
+
if (ctx.allowLegacyWebdavPlaintext)
|
|
105347
|
+
return false;
|
|
105348
|
+
const strongEtag = strongEtagFromWebdavFingerprint(fingerprint);
|
|
105349
|
+
if (!strongEtag)
|
|
105350
|
+
return false;
|
|
105351
|
+
webdavDocumentVersion = { exists: true, strongEtag };
|
|
105352
|
+
webdavDocumentSnapshot = null;
|
|
105353
|
+
return true;
|
|
105354
|
+
}
|
|
105355
|
+
if (ctx.backend === "cloud" && ctx.cloudProvider === "dropbox") {
|
|
105356
|
+
if (!fingerprint.startsWith(DROPBOX_REV_FINGERPRINT_PREFIX))
|
|
105357
|
+
return false;
|
|
105358
|
+
const rev = fingerprint.slice(DROPBOX_REV_FINGERPRINT_PREFIX.length);
|
|
105359
|
+
if (!rev)
|
|
105360
|
+
return false;
|
|
105361
|
+
ctx.dropboxRev = rev;
|
|
105362
|
+
return true;
|
|
105363
|
+
}
|
|
105364
|
+
return false;
|
|
105365
|
+
},
|
|
104487
105366
|
readRemote: async () => {
|
|
104488
105367
|
if (ctx.backend === "cloudkit") {
|
|
104489
105368
|
return transport.cloudKitRead();
|
|
@@ -104497,6 +105376,9 @@ function createSyncBackendIO(ctx, transport) {
|
|
|
104497
105376
|
const remote2 = await transport.webdavGet();
|
|
104498
105377
|
webdavDocumentVersion = { exists: remote2.exists, strongEtag: remote2.strongEtag };
|
|
104499
105378
|
webdavDocumentSnapshot = snapshotWebdavRead(remote2);
|
|
105379
|
+
if (ctx.syncEncryptionOff && !ctx.allowLegacyWebdavPlaintext && remote2.exists && !remote2.strongEtag) {
|
|
105380
|
+
ctx.allowLegacyWebdavPlaintext = true;
|
|
105381
|
+
}
|
|
104500
105382
|
return remote2.data;
|
|
104501
105383
|
} catch (error2) {
|
|
104502
105384
|
webdavDocumentVersion = getWebdavDocumentVersionFromError(error2);
|
|
@@ -104651,7 +105533,7 @@ function createSyncBackendIO(ctx, transport) {
|
|
|
104651
105533
|
}
|
|
104652
105534
|
};
|
|
104653
105535
|
}
|
|
104654
|
-
var DROPBOX_REV_FINGERPRINT_PREFIX = "dropbox:v1:rev=", buildDropboxRevFingerprint = (rev) => `${DROPBOX_REV_FINGERPRINT_PREFIX}${rev}`, isFileSyncReadResult = (value) => typeof value === "object" && value !== null && ("data" in value) && ("fingerprint" in value) && typeof value.fingerprint === "string";
|
|
105536
|
+
var DROPBOX_REV_FINGERPRINT_PREFIX = "dropbox:v1:rev=", WEBDAV_ETAG_FINGERPRINT_PREFIX = "webdav:v1:etag=", buildDropboxRevFingerprint = (rev) => `${DROPBOX_REV_FINGERPRINT_PREFIX}${rev}`, strongEtagFromWebdavFingerprint = (fingerprint) => fingerprint.startsWith(WEBDAV_ETAG_FINGERPRINT_PREFIX) ? normalizeStrongWebdavEtag(fingerprint.slice(WEBDAV_ETAG_FINGERPRINT_PREFIX.length)) : null, isFileSyncReadResult = (value) => typeof value === "object" && value !== null && ("data" in value) && ("fingerprint" in value) && typeof value.fingerprint === "string";
|
|
104655
105537
|
var init_sync_backend_io = __esm(() => {
|
|
104656
105538
|
init_dropbox();
|
|
104657
105539
|
init_sync_helpers();
|
|
@@ -104704,14 +105586,162 @@ var init_sync_fast_sync = __esm(() => {
|
|
|
104704
105586
|
init_sync_helpers();
|
|
104705
105587
|
});
|
|
104706
105588
|
|
|
105589
|
+
// ../../packages/core/src/sync-encryption-diagnostics.ts
|
|
105590
|
+
var SYNC_ENCRYPTION_LOG_PREFIX = "[sync-encryption]", SYNC_ENCRYPTION_LOG_EVENTS, syncEncryptionLogMessage = (event) => `${SYNC_ENCRYPTION_LOG_PREFIX} ${event}`, SYNC_ENCRYPTION_LOG_ABSENT = "-", MAX_LOGGED_MESSAGE_CHARS = 200, HEX_ONLY, finalize = (fields) => sanitizeLogContext(fields) ?? {}, flag = (value) => value === null || value === undefined ? SYNC_ENCRYPTION_LOG_ABSENT : String(value === true), syncEncryptionSaltPrefix = (salt) => {
|
|
105591
|
+
if (!salt)
|
|
105592
|
+
return SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105593
|
+
if (typeof salt === "string") {
|
|
105594
|
+
const trimmed = salt.trim();
|
|
105595
|
+
if (!trimmed || !HEX_ONLY.test(trimmed))
|
|
105596
|
+
return SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105597
|
+
return trimmed.slice(0, 8).toLowerCase();
|
|
105598
|
+
}
|
|
105599
|
+
if (salt.length === 0)
|
|
105600
|
+
return SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105601
|
+
let out = "";
|
|
105602
|
+
for (let index = 0;index < salt.length && out.length < 8; index += 1) {
|
|
105603
|
+
out += salt[index].toString(16).padStart(2, "0");
|
|
105604
|
+
}
|
|
105605
|
+
return out.slice(0, 8);
|
|
105606
|
+
}, syncEncryptionKdfLabel = (params) => {
|
|
105607
|
+
if (!params)
|
|
105608
|
+
return SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105609
|
+
return `m=${params.mKib},t=${params.t},p=${params.p}`;
|
|
105610
|
+
}, digest32 = (value) => {
|
|
105611
|
+
let hash = 2166136261;
|
|
105612
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
105613
|
+
hash ^= value.charCodeAt(index);
|
|
105614
|
+
hash = Math.imul(hash, 16777619) >>> 0;
|
|
105615
|
+
}
|
|
105616
|
+
return hash.toString(16).padStart(8, "0");
|
|
105617
|
+
}, syncEncryptionScopeLabel = (scope) => {
|
|
105618
|
+
if (!scope)
|
|
105619
|
+
return SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105620
|
+
let backend = "scope";
|
|
105621
|
+
try {
|
|
105622
|
+
const parsed = JSON.parse(scope);
|
|
105623
|
+
if (Array.isArray(parsed) && typeof parsed[0] === "string" && parsed[0]) {
|
|
105624
|
+
backend = parsed[0];
|
|
105625
|
+
}
|
|
105626
|
+
} catch {}
|
|
105627
|
+
return `${backend}#${digest32(scope)}`;
|
|
105628
|
+
}, syncEncryptionArtifactLabel = (name) => {
|
|
105629
|
+
if (!name)
|
|
105630
|
+
return SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105631
|
+
const stripped = name.split("?")[0].split("#")[0].replace(/[\\/]+$/, "");
|
|
105632
|
+
if (!stripped)
|
|
105633
|
+
return SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105634
|
+
const lastSeparator = Math.max(stripped.lastIndexOf("/"), stripped.lastIndexOf("\\"));
|
|
105635
|
+
const leaf = lastSeparator >= 0 ? stripped.slice(lastSeparator + 1) : stripped;
|
|
105636
|
+
return leaf || SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105637
|
+
}, URL_IN_MESSAGE, clampMessage = (message3) => {
|
|
105638
|
+
const trimmed = message3?.trim();
|
|
105639
|
+
if (!trimmed)
|
|
105640
|
+
return SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105641
|
+
const safe = sanitizeForLog(trimmed.replace(URL_IN_MESSAGE, (url) => sanitizeUrl(url) ?? "[redacted]"));
|
|
105642
|
+
return safe.length > MAX_LOGGED_MESSAGE_CHARS ? `${safe.slice(0, MAX_LOGGED_MESSAGE_CHARS)}…` : safe;
|
|
105643
|
+
}, buildSyncEncryptionStateExtra = (input) => finalize({
|
|
105644
|
+
backend: input.backend || SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105645
|
+
trigger: input.trigger,
|
|
105646
|
+
state: input.state,
|
|
105647
|
+
hasMaterial: flag(input.hasMaterial),
|
|
105648
|
+
saltPrefix: syncEncryptionSaltPrefix(input.salt),
|
|
105649
|
+
kdf: syncEncryptionKdfLabel(input.kdf),
|
|
105650
|
+
incompleteTransition: input.incompleteTransition ?? SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105651
|
+
discoveredScope: input.discoveredScopeLabel?.trim() || syncEncryptionScopeLabel(input.discoveredScope),
|
|
105652
|
+
activeScope: syncEncryptionScopeLabel(input.activeScope),
|
|
105653
|
+
decision: input.decision
|
|
105654
|
+
}), buildSyncEncryptionRemoteReadExtra = (input) => finalize({
|
|
105655
|
+
artifact: syncEncryptionArtifactLabel(input.artifact),
|
|
105656
|
+
exists: flag(input.exists),
|
|
105657
|
+
kind: input.kind,
|
|
105658
|
+
headerSaltPrefix: syncEncryptionSaltPrefix(input.headerSalt),
|
|
105659
|
+
headerKdf: syncEncryptionKdfLabel(input.headerKdf),
|
|
105660
|
+
bytes: input.bytes === null || input.bytes === undefined ? SYNC_ENCRYPTION_LOG_ABSENT : String(input.bytes),
|
|
105661
|
+
version: input.version ?? SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105662
|
+
foreignSalt: flag(input.foreignSalt),
|
|
105663
|
+
decision: input.decision
|
|
105664
|
+
}), buildSyncEncryptionTransitionExtra = (input) => finalize({
|
|
105665
|
+
kind: input.kind,
|
|
105666
|
+
backend: input.backend || SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105667
|
+
phase: input.phase,
|
|
105668
|
+
artifact: input.artifact ? syncEncryptionArtifactLabel(input.artifact) : SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105669
|
+
planned: input.planned === null || input.planned === undefined ? SYNC_ENCRYPTION_LOG_ABSENT : String(input.planned),
|
|
105670
|
+
done: input.done === null || input.done === undefined ? SYNC_ENCRYPTION_LOG_ABSENT : String(input.done),
|
|
105671
|
+
outcome: input.outcome ?? SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105672
|
+
errorName: input.errorName || SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105673
|
+
errorMessage: input.errorName ? clampMessage(input.errorMessage) : SYNC_ENCRYPTION_LOG_ABSENT
|
|
105674
|
+
}), SYNC_ENCRYPTION_LOG_SENTINELS, findSyncEncryptionSentinel = (message3) => {
|
|
105675
|
+
if (!message3)
|
|
105676
|
+
return SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105677
|
+
for (const sentinel of [...SYNC_ENCRYPTION_LOG_SENTINELS].sort((a, b) => b.length - a.length)) {
|
|
105678
|
+
if (message3.includes(sentinel))
|
|
105679
|
+
return sentinel;
|
|
105680
|
+
}
|
|
105681
|
+
return SYNC_ENCRYPTION_LOG_ABSENT;
|
|
105682
|
+
}, lastSyncEncryptionError = null, getLastSyncEncryptionError = () => lastSyncEncryptionError, resetLastSyncEncryptionError = () => {
|
|
105683
|
+
lastSyncEncryptionError = null;
|
|
105684
|
+
}, buildSyncEncryptionErrorExtra = (input) => {
|
|
105685
|
+
const at = input.at ?? new Date().toISOString();
|
|
105686
|
+
lastSyncEncryptionError = { name: input.errorName, at };
|
|
105687
|
+
return finalize({
|
|
105688
|
+
errorName: input.errorName || SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105689
|
+
sentinel: findSyncEncryptionSentinel(input.errorMessage),
|
|
105690
|
+
backend: input.backend || SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105691
|
+
step: input.step || SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105692
|
+
classification: input.classification || SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105693
|
+
errorMessage: clampMessage(input.errorMessage)
|
|
105694
|
+
});
|
|
105695
|
+
}, buildSyncEncryptionActivationExtra = (input) => finalize({
|
|
105696
|
+
activationProof: input.activationProof ?? SYNC_ENCRYPTION_LOG_ABSENT,
|
|
105697
|
+
stateBefore: input.stateBefore,
|
|
105698
|
+
stateAfter: input.stateAfter,
|
|
105699
|
+
backend: input.backend || SYNC_ENCRYPTION_LOG_ABSENT
|
|
105700
|
+
}), formatSyncEncryptionDiagnostics = (input) => {
|
|
105701
|
+
const lastError = getLastSyncEncryptionError();
|
|
105702
|
+
return [
|
|
105703
|
+
`state: ${input.state}`,
|
|
105704
|
+
`location: ${syncEncryptionScopeLabel(input.activeScope)}`,
|
|
105705
|
+
`material: ${flag(input.hasMaterial)}`,
|
|
105706
|
+
`salt: ${syncEncryptionSaltPrefix(input.salt)}`,
|
|
105707
|
+
`kdf: ${syncEncryptionKdfLabel(input.kdf)}`,
|
|
105708
|
+
`transition: ${input.incompleteTransition ?? SYNC_ENCRYPTION_LOG_ABSENT}`,
|
|
105709
|
+
`lastError: ${lastError ? `${lastError.name} @ ${lastError.at}` : SYNC_ENCRYPTION_LOG_ABSENT}`
|
|
105710
|
+
];
|
|
105711
|
+
};
|
|
105712
|
+
var init_sync_encryption_diagnostics = __esm(() => {
|
|
105713
|
+
init_log_sanitize();
|
|
105714
|
+
SYNC_ENCRYPTION_LOG_EVENTS = {
|
|
105715
|
+
state: "state",
|
|
105716
|
+
remoteRead: "remote-read",
|
|
105717
|
+
transition: "transition",
|
|
105718
|
+
error: "error",
|
|
105719
|
+
activation: "activation"
|
|
105720
|
+
};
|
|
105721
|
+
HEX_ONLY = /^[0-9a-f]*$/i;
|
|
105722
|
+
URL_IN_MESSAGE = /[a-z][a-z0-9+.-]*:\/\/\S+/gi;
|
|
105723
|
+
SYNC_ENCRYPTION_LOG_SENTINELS = [
|
|
105724
|
+
"SYNC_ENCRYPTION_REMOTE_ENCRYPTED",
|
|
105725
|
+
"SYNC_ENCRYPTION_REMOTE_PLAINTEXT",
|
|
105726
|
+
"SYNC_ENCRYPTION_REMOTE_VERSION_UNAVAILABLE",
|
|
105727
|
+
"SYNC_ENCRYPTION_TRANSITION_INCOMPLETE",
|
|
105728
|
+
"SYNC_ENCRYPTION_STATE_UNAVAILABLE",
|
|
105729
|
+
"SYNC_ENCRYPTION_TERMINAL",
|
|
105730
|
+
"SYNC_ENCRYPTION_WRONG_PASSPHRASE",
|
|
105731
|
+
"SYNC_ENCRYPTION_BACKEND_REQUIRED"
|
|
105732
|
+
];
|
|
105733
|
+
});
|
|
105734
|
+
|
|
104707
105735
|
// ../../packages/core/src/sync-remote-fence-providers.ts
|
|
104708
105736
|
var FENCE_MAX_BYTES = 4096, webdavMutationFenceUrl = (documentUrl) => {
|
|
104709
|
-
const
|
|
104710
|
-
const
|
|
104711
|
-
|
|
104712
|
-
|
|
104713
|
-
|
|
104714
|
-
|
|
105737
|
+
const suffixStart = documentUrl.search(/[?#]/);
|
|
105738
|
+
const withoutSuffix = suffixStart === -1 ? documentUrl : documentUrl.slice(0, suffixStart);
|
|
105739
|
+
const pathStart = withoutSuffix.indexOf("/", withoutSuffix.indexOf("://") + 3);
|
|
105740
|
+
const slash = withoutSuffix.lastIndexOf("/");
|
|
105741
|
+
if (pathStart === -1 || slash < pathStart) {
|
|
105742
|
+
return `${withoutSuffix}/${SYNC_REMOTE_MUTATION_FENCE_NAME}`;
|
|
105743
|
+
}
|
|
105744
|
+
return `${withoutSuffix.slice(0, slash + 1)}${SYNC_REMOTE_MUTATION_FENCE_NAME}`;
|
|
104715
105745
|
}, createWebdavSyncRemoteMutationFencePort = (documentUrl, options = {}) => {
|
|
104716
105746
|
const url = webdavMutationFenceUrl(documentUrl);
|
|
104717
105747
|
const readOptions = { ...options, maxBytes: FENCE_MAX_BYTES, treatOversizeAsAbsent: true };
|
|
@@ -107261,7 +108291,7 @@ async function undoTaskCompletion(taskId, previousStatus, wasFocusedToday, optio
|
|
|
107261
108291
|
return;
|
|
107262
108292
|
const current = useTaskStore.getState();
|
|
107263
108293
|
const focusTaskLimit = normalizeFocusTaskLimit(current.settings.gtd?.focusTaskLimit);
|
|
107264
|
-
if (current.
|
|
108294
|
+
if (current.getFocusedCount() >= focusTaskLimit)
|
|
107265
108295
|
return;
|
|
107266
108296
|
const focusResult = await Promise.resolve(current.updateTask(taskId, {
|
|
107267
108297
|
isFocusedToday: true,
|
|
@@ -108541,6 +109571,30 @@ async function cloudGetFile(url, options = {}) {
|
|
|
108541
109571
|
return await readResponseBody(res, options.onProgress, options.maxBytes ?? MAX_DOWNLOAD_BYTES, signal);
|
|
108542
109572
|
});
|
|
108543
109573
|
}
|
|
109574
|
+
async function cloudAttachmentExists(url, options = {}) {
|
|
109575
|
+
try {
|
|
109576
|
+
return (await cloudHeadJson(url, options)).exists;
|
|
109577
|
+
} catch (error2) {
|
|
109578
|
+
if (isAbortError(error2))
|
|
109579
|
+
throw error2;
|
|
109580
|
+
if (!(error2 instanceof CloudHttpError) || error2.status !== 405)
|
|
109581
|
+
return null;
|
|
109582
|
+
if (!options.partialBodyReads) {
|
|
109583
|
+
options.onHeadUnsupported?.();
|
|
109584
|
+
return null;
|
|
109585
|
+
}
|
|
109586
|
+
}
|
|
109587
|
+
try {
|
|
109588
|
+
await cloudGetFile(url, { ...options, maxBytes: 1, onProgress: undefined });
|
|
109589
|
+
return true;
|
|
109590
|
+
} catch (error2) {
|
|
109591
|
+
if (isAbortError(error2))
|
|
109592
|
+
throw error2;
|
|
109593
|
+
if (error2 instanceof ResponseTooLargeError)
|
|
109594
|
+
return true;
|
|
109595
|
+
return error2 instanceof CloudHttpError && error2.status === 404 ? false : null;
|
|
109596
|
+
}
|
|
109597
|
+
}
|
|
108544
109598
|
async function cloudDeleteFile(url, options = {}) {
|
|
108545
109599
|
assertCloudUrl(url, options);
|
|
108546
109600
|
const fetcher = options.fetcher ?? fetch;
|
|
@@ -108623,6 +109677,35 @@ var CLOUDKIT_ATTACHMENT_RECORD_TYPE = "MindwtrAttachment", CLOUDKIT_ATTACHMENT_A
|
|
|
108623
109677
|
return recordName || null;
|
|
108624
109678
|
};
|
|
108625
109679
|
|
|
109680
|
+
// ../../packages/core/src/attachment-presence-repair.ts
|
|
109681
|
+
async function repairMissingRemoteAttachments(options) {
|
|
109682
|
+
const { candidates, probe, clear, maxChecks, log } = options;
|
|
109683
|
+
let checked = 0;
|
|
109684
|
+
let cleared = 0;
|
|
109685
|
+
let complete = true;
|
|
109686
|
+
for (const attachment of candidates) {
|
|
109687
|
+
if (maxChecks !== undefined && checked >= maxChecks) {
|
|
109688
|
+
log?.("Attachment presence pass reached the per-pass limit", { limit: String(maxChecks) });
|
|
109689
|
+
break;
|
|
109690
|
+
}
|
|
109691
|
+
checked += 1;
|
|
109692
|
+
const present = await probe(attachment);
|
|
109693
|
+
if (present === null) {
|
|
109694
|
+
complete = false;
|
|
109695
|
+
break;
|
|
109696
|
+
}
|
|
109697
|
+
if (present !== false)
|
|
109698
|
+
continue;
|
|
109699
|
+
clear(attachment);
|
|
109700
|
+
cleared += 1;
|
|
109701
|
+
log?.("Attachment is missing from the sync location; clearing its cloud reference", {
|
|
109702
|
+
id: attachment.id
|
|
109703
|
+
});
|
|
109704
|
+
}
|
|
109705
|
+
return { checked, cleared, complete };
|
|
109706
|
+
}
|
|
109707
|
+
var isAttachmentPresenceRepairCandidate = (attachment) => attachment.kind === "file" && !attachment.deletedAt && Boolean(attachment.cloudKey) && attachment.pendingContentUpload !== true;
|
|
109708
|
+
|
|
108626
109709
|
// ../../packages/core/src/attachment-draft-settlement.ts
|
|
108627
109710
|
function planAttachmentDraftSettlement({
|
|
108628
109711
|
baselineAttachments = [],
|
|
@@ -110840,7 +111923,8 @@ CREATE TABLE IF NOT EXISTS projects (
|
|
|
110840
111923
|
createdAt TEXT NOT NULL,
|
|
110841
111924
|
updatedAt TEXT NOT NULL,
|
|
110842
111925
|
deletedAt TEXT,
|
|
110843
|
-
purgedAt TEXT
|
|
111926
|
+
purgedAt TEXT,
|
|
111927
|
+
startDate TEXT
|
|
110844
111928
|
);
|
|
110845
111929
|
|
|
110846
111930
|
CREATE TABLE IF NOT EXISTS areas (
|
|
@@ -111247,7 +112331,7 @@ var toJson = (value) => value === undefined ? null : JSON.stringify(value), from
|
|
|
111247
112331
|
});
|
|
111248
112332
|
return fallback;
|
|
111249
112333
|
}
|
|
111250
|
-
}, toBool = (value) => value ? 1 : 0, fromBool = (value) => Boolean(value), toNullableBool = (value) => value === null || value === undefined ? null : toBool(value), fromNullableBool = (value) => {
|
|
112334
|
+
}, toBool = (value) => value ? 1 : 0, fromBool = (value) => Boolean(value), fromPresentBool = (value) => value ? true : undefined, toNullableBool = (value) => value === null || value === undefined ? null : toBool(value), fromNullableBool = (value) => {
|
|
111251
112335
|
if (value === null)
|
|
111252
112336
|
return null;
|
|
111253
112337
|
if (value === undefined)
|
|
@@ -111377,7 +112461,7 @@ var schema, TASK_SYNC_SCHEMA_VERSION, TASK_SYNC_SCHEMA_VERSION_POLICY, TASK_SYNC
|
|
|
111377
112461
|
relativeStartOffset: fromJson(row.relativeStartOffset, undefined),
|
|
111378
112462
|
dueDate: fromOptional(row.dueDate),
|
|
111379
112463
|
recurrence: fromJson(row.recurrence, null),
|
|
111380
|
-
showFutureRecurrence:
|
|
112464
|
+
showFutureRecurrence: fromPresentBool(row.showFutureRecurrence),
|
|
111381
112465
|
pushCount: row.pushCount === null || row.pushCount === undefined ? undefined : Number(row.pushCount),
|
|
111382
112466
|
repeatReminderMinutes: row.repeatReminderMinutes === null || row.repeatReminderMinutes === undefined ? undefined : Number(row.repeatReminderMinutes),
|
|
111383
112467
|
tags: toStringArray(fromJson(row.tags, [])),
|
|
@@ -111453,7 +112537,8 @@ var init_project_sync_schema_fixture = __esm(() => {
|
|
|
111453
112537
|
{ name: "createdAt", nullability: "required", cloudSynced: true, cloudWrite: "managed", sqliteColumn: "createdAt", sqliteOrder: 18, sqliteType: "TEXT" },
|
|
111454
112538
|
{ name: "updatedAt", nullability: "required", cloudSynced: true, cloudWrite: "managed", sqliteColumn: "updatedAt", sqliteOrder: 19, sqliteType: "TEXT" },
|
|
111455
112539
|
{ name: "deletedAt", nullability: "optional", cloudSynced: true, cloudWrite: "patch", sqliteColumn: "deletedAt", sqliteOrder: 20, sqliteType: "TEXT" },
|
|
111456
|
-
{ name: "purgedAt", nullability: "optional", cloudSynced: true, cloudWrite: "patch", sqliteColumn: "purgedAt", sqliteOrder: 21, sqliteType: "TEXT" }
|
|
112540
|
+
{ name: "purgedAt", nullability: "optional", cloudSynced: true, cloudWrite: "patch", sqliteColumn: "purgedAt", sqliteOrder: 21, sqliteType: "TEXT" },
|
|
112541
|
+
{ name: "startDate", nullability: "optional", cloudSynced: true, cloudWrite: "create-patch", sqliteColumn: "startDate", sqliteOrder: 22, sqliteType: "TEXT" }
|
|
111457
112542
|
],
|
|
111458
112543
|
fixture: {
|
|
111459
112544
|
id: "project-schema-fixture",
|
|
@@ -111484,7 +112569,8 @@ var init_project_sync_schema_fixture = __esm(() => {
|
|
|
111484
112569
|
createdAt: "2026-07-01T10:00:00.000Z",
|
|
111485
112570
|
updatedAt: "2026-07-14T11:00:00.000Z",
|
|
111486
112571
|
deletedAt: "2026-07-14T11:30:00.000Z",
|
|
111487
|
-
purgedAt: "2026-07-14T11:45:00.000Z"
|
|
112572
|
+
purgedAt: "2026-07-14T11:45:00.000Z",
|
|
112573
|
+
startDate: "2026-07-10T09:00:00.000Z"
|
|
111488
112574
|
}
|
|
111489
112575
|
};
|
|
111490
112576
|
});
|
|
@@ -111515,6 +112601,7 @@ var schema2, PROJECT_SYNC_SCHEMA_VERSION, PROJECT_SYNC_FIELD_SCHEMA, PROJECT_SYN
|
|
|
111515
112601
|
supportNotes: project.supportNotes ?? null,
|
|
111516
112602
|
attachments: toJson(project.attachments),
|
|
111517
112603
|
dueDate: project.dueDate ?? null,
|
|
112604
|
+
startDate: project.startDate ?? null,
|
|
111518
112605
|
reviewAt: project.reviewAt ?? null,
|
|
111519
112606
|
areaId: project.areaId ?? null,
|
|
111520
112607
|
areaTitle: project.areaTitle ?? null,
|
|
@@ -111541,6 +112628,7 @@ var schema2, PROJECT_SYNC_SCHEMA_VERSION, PROJECT_SYNC_FIELD_SCHEMA, PROJECT_SYN
|
|
|
111541
112628
|
supportNotes: fromOptional(row.supportNotes),
|
|
111542
112629
|
attachments: toAttachments(fromJson(row.attachments, undefined)),
|
|
111543
112630
|
dueDate: fromOptional(row.dueDate),
|
|
112631
|
+
startDate: fromOptional(row.startDate),
|
|
111544
112632
|
reviewAt: fromOptional(row.reviewAt),
|
|
111545
112633
|
areaId: fromOptional(row.areaId),
|
|
111546
112634
|
areaTitle: fromOptional(row.areaTitle),
|
|
@@ -115681,6 +116769,7 @@ function applyImport(currentData, parsed, opts) {
|
|
|
115681
116769
|
tagIds: project.tagIds ?? [],
|
|
115682
116770
|
supportNotes: project.supportNotes,
|
|
115683
116771
|
dueDate: project.dueDate,
|
|
116772
|
+
startDate: project.startDate,
|
|
115684
116773
|
createdAt,
|
|
115685
116774
|
updatedAt,
|
|
115686
116775
|
rev: nextRevision(),
|
|
@@ -116691,6 +117780,7 @@ var normalizeFolders = (rawFolders) => {
|
|
|
116691
117780
|
areaSourceId: record3.folderId,
|
|
116692
117781
|
color: record3.color,
|
|
116693
117782
|
dueDate: record3.dueDate,
|
|
117783
|
+
startDate: record3.startDate,
|
|
116694
117784
|
supportNotes,
|
|
116695
117785
|
isArchived: Boolean(record3.completedAt),
|
|
116696
117786
|
createdAt: record3.createdAt,
|
|
@@ -117068,6 +118158,7 @@ ${next}`;
|
|
|
117068
118158
|
const project2 = ensureProjectRecord(projectsByKey, row.name, allocateProjectOrder);
|
|
117069
118159
|
project2.status = parseProjectStatus(row.statusText || "");
|
|
117070
118160
|
project2.dueDate = dueMapping.value ?? project2.dueDate;
|
|
118161
|
+
project2.startDate = startMapping.value ?? project2.startDate;
|
|
117071
118162
|
project2.supportNotes = mergeProjectSupportNotes(project2.supportNotes, joinDescription([
|
|
117072
118163
|
row.notes,
|
|
117073
118164
|
plannedMapping.value ? `Planned date in OmniFocus: ${plannedMapping.value}` : undefined,
|
|
@@ -117459,6 +118550,7 @@ ${next}`;
|
|
|
117459
118550
|
areaSourceKey: ensureAreaRecord(project.folderId, project.folderName),
|
|
117460
118551
|
status: project.completed || rootTask?.completed ? "archived" : parseProjectStatus(project.statusText || rootTask?.statusText || ""),
|
|
117461
118552
|
dueDate: dateNotes.dueDate,
|
|
118553
|
+
startDate: dateNotes.startTime,
|
|
117462
118554
|
supportNotes: joinDescription([
|
|
117463
118555
|
project.note,
|
|
117464
118556
|
rootTask?.note,
|
|
@@ -117489,6 +118581,7 @@ ${next}`;
|
|
|
117489
118581
|
order: projects.length,
|
|
117490
118582
|
status: task.completed ? "archived" : parseProjectStatus(task.statusText || ""),
|
|
117491
118583
|
dueDate: dateNotes.dueDate,
|
|
118584
|
+
startDate: dateNotes.startTime,
|
|
117492
118585
|
supportNotes: joinDescription([
|
|
117493
118586
|
task.note,
|
|
117494
118587
|
dateNotes.plannedNote,
|
|
@@ -120338,6 +121431,7 @@ var init_settings_search_keys = __esm(() => {
|
|
|
120338
121431
|
SETTINGS_SEARCH_PAGE_IDS = Object.keys(SETTINGS_SEARCH_PAGE_KEYS);
|
|
120339
121432
|
SETTINGS_SEARCH_INDEX = SETTINGS_SEARCH_PAGE_IDS.flatMap((pageId) => getSettingsSearchEntries(pageId));
|
|
120340
121433
|
SETTINGS_SEARCH_MOBILE_EXCLUSIONS = {
|
|
121434
|
+
featureTimeline: "Timeline view exists on desktop only; the mobile GTD > Features screen has no row for it (#1145).",
|
|
120341
121435
|
density: "No adjustable list density setting on mobile.",
|
|
120342
121436
|
textSize: "Mobile follows the OS text-size setting automatically; no in-app override.",
|
|
120343
121437
|
keybindings: "No hardware-keyboard shortcuts configuration on mobile.",
|
|
@@ -120474,6 +121568,11 @@ __export(exports_src, {
|
|
|
120474
121568
|
taskDraftToChangedUpdatePatch: () => taskDraftToChangedUpdatePatch,
|
|
120475
121569
|
tFallback: () => tFallback,
|
|
120476
121570
|
syncPlaintextArtifactName: () => syncPlaintextArtifactName,
|
|
121571
|
+
syncEncryptionScopeLabel: () => syncEncryptionScopeLabel,
|
|
121572
|
+
syncEncryptionSaltPrefix: () => syncEncryptionSaltPrefix,
|
|
121573
|
+
syncEncryptionLogMessage: () => syncEncryptionLogMessage,
|
|
121574
|
+
syncEncryptionKdfLabel: () => syncEncryptionKdfLabel,
|
|
121575
|
+
syncEncryptionArtifactLabel: () => syncEncryptionArtifactLabel,
|
|
120477
121576
|
syncEncryptedArtifactName: () => syncEncryptedArtifactName,
|
|
120478
121577
|
summarizeTaskLifecycleCounts: () => summarizeTaskLifecycleCounts,
|
|
120479
121578
|
summarizeMergeStats: () => summarizeMergeStats,
|
|
@@ -120513,6 +121612,7 @@ __export(exports_src, {
|
|
|
120513
121612
|
setTaskViewSectionId: () => setTaskViewSectionId,
|
|
120514
121613
|
setTaskDraftField: () => setTaskDraftField,
|
|
120515
121614
|
setStorageAdapter: () => setStorageAdapter,
|
|
121615
|
+
setSleepBypass: () => setSleepBypass,
|
|
120516
121616
|
setSha256HexProvider: () => setSha256HexProvider,
|
|
120517
121617
|
setLogger: () => setLogger,
|
|
120518
121618
|
setComposerTitle: () => setComposerTitle,
|
|
@@ -120539,6 +121639,7 @@ __export(exports_src, {
|
|
|
120539
121639
|
selectVisiblePeople: () => selectVisiblePeople,
|
|
120540
121640
|
selectVisibleAreas: () => selectVisibleAreas,
|
|
120541
121641
|
selectProcessInboxCandidates: () => selectProcessInboxCandidates,
|
|
121642
|
+
selectFocusedCount: () => selectFocusedCount,
|
|
120542
121643
|
selectComposerTask: () => selectComposerTask,
|
|
120543
121644
|
sectionToSqliteRow: () => sectionToSqliteRow,
|
|
120544
121645
|
sectionFromSqliteRow: () => sectionFromSqliteRow,
|
|
@@ -120627,6 +121728,7 @@ __export(exports_src, {
|
|
|
120627
121728
|
resolveAnthropicModel: () => resolveAnthropicModel,
|
|
120628
121729
|
resetUnhashableAttachmentStatsForTests: () => resetUnhashableAttachmentStatsForTests,
|
|
120629
121730
|
resetPomodoroState: () => resetPomodoroState,
|
|
121731
|
+
resetLastSyncEncryptionError: () => resetLastSyncEncryptionError,
|
|
120630
121732
|
resetHeartbeatOptOutMarker: () => resetHeartbeatOptOutMarker,
|
|
120631
121733
|
resetForTests: () => resetForTests,
|
|
120632
121734
|
rescheduleTask: () => rescheduleTask,
|
|
@@ -120634,6 +121736,7 @@ __export(exports_src, {
|
|
|
120634
121736
|
replaceEntityInMap: () => replaceEntityInMap,
|
|
120635
121737
|
replaceEntityInArray: () => replaceEntityInArray,
|
|
120636
121738
|
replaceEntitiesInArray: () => replaceEntitiesInArray,
|
|
121739
|
+
repairMissingRemoteAttachments: () => repairMissingRemoteAttachments,
|
|
120637
121740
|
repairMergedSyncReferences: () => repairMergedSyncReferences,
|
|
120638
121741
|
removeAdvancedFilterCriteriaChip: () => removeAdvancedFilterCriteriaChip,
|
|
120639
121742
|
recordUpdateReminderShown: () => recordUpdateReminderShown,
|
|
@@ -120829,6 +121932,7 @@ __export(exports_src, {
|
|
|
120829
121932
|
isSyncFilePath: () => isSyncFilePath,
|
|
120830
121933
|
isSyncFileLockUnavailableError: () => isSyncFileLockUnavailableError,
|
|
120831
121934
|
isSyncFileGenerationCorruptError: () => isSyncFileGenerationCorruptError,
|
|
121935
|
+
isSyncEncryptionStateBlocked: () => isSyncEncryptionStateBlocked,
|
|
120832
121936
|
isSyncEncryptionRemoteVersionUnavailableError: () => isSyncEncryptionRemoteVersionUnavailableError,
|
|
120833
121937
|
isSupportedLanguage: () => isSupportedLanguage,
|
|
120834
121938
|
isSlotFreeForDay: () => isSlotFreeForDay,
|
|
@@ -120858,6 +121962,7 @@ __export(exports_src, {
|
|
|
120858
121962
|
isMindwtrMirrorEvent: () => isMindwtrMirrorEvent,
|
|
120859
121963
|
isMindwtrMirrorCalendar: () => isMindwtrMirrorCalendar,
|
|
120860
121964
|
isMarkdownEditorAssistEnabled: () => isMarkdownEditorAssistEnabled,
|
|
121965
|
+
isLocalPersistEquivalent: () => isLocalPersistEquivalent,
|
|
120861
121966
|
isLikelyOfflineSyncError: () => isLikelyOfflineSyncError,
|
|
120862
121967
|
isJalaliCalendarLocale: () => isJalaliCalendarLocale,
|
|
120863
121968
|
isFocusSequentialCandidate: () => isFocusSequentialCandidate,
|
|
@@ -120869,12 +121974,14 @@ __export(exports_src, {
|
|
|
120869
121974
|
isDropboxPathNotFoundTag: () => isDropboxPathNotFoundTag,
|
|
120870
121975
|
isDropboxPathConflictTag: () => isDropboxPathConflictTag,
|
|
120871
121976
|
isDropboxConflictError: () => isDropboxConflictError,
|
|
121977
|
+
isDeepJsonEqual: () => isDeepJsonEqual,
|
|
120872
121978
|
isCustomTimeEstimate: () => isCustomTimeEstimate,
|
|
120873
121979
|
isConnectionAllowed: () => isConnectionAllowed,
|
|
120874
121980
|
isCompletedCalendarTask: () => isCompletedCalendarTask,
|
|
120875
121981
|
isCalendarFeedTask: () => isCalendarFeedTask,
|
|
120876
121982
|
isAttachmentUploadTooLargeError: () => isAttachmentUploadTooLargeError,
|
|
120877
121983
|
isAttachmentUploadAdmissionError: () => isAttachmentUploadAdmissionError,
|
|
121984
|
+
isAttachmentPresenceRepairCandidate: () => isAttachmentPresenceRepairCandidate,
|
|
120878
121985
|
isAttachmentLocalResourceReferenced: () => isAttachmentLocalResourceReferenced,
|
|
120879
121986
|
isAttachmentCloudResourceReferenced: () => isAttachmentCloudResourceReferenced,
|
|
120880
121987
|
isAreaFilterSelectionActive: () => isAreaFilterSelectionActive,
|
|
@@ -120986,6 +122093,7 @@ __export(exports_src, {
|
|
|
120986
122093
|
getLocalizedWeekdayLabel: () => getLocalizedWeekdayLabel,
|
|
120987
122094
|
getLocalizedWeekdayButtons: () => getLocalizedWeekdayButtons,
|
|
120988
122095
|
getLocaleCoverageTier: () => getLocaleCoverageTier,
|
|
122096
|
+
getLastSyncEncryptionError: () => getLastSyncEncryptionError,
|
|
120989
122097
|
getInlineMarkdownPreview: () => getInlineMarkdownPreview,
|
|
120990
122098
|
getInMemorySyncChangeFingerprint: () => getInMemorySyncChangeFingerprint,
|
|
120991
122099
|
getInMemoryAppDataSnapshot: () => getInMemoryAppDataSnapshot,
|
|
@@ -121039,6 +122147,7 @@ __export(exports_src, {
|
|
|
121039
122147
|
formatTaskMovedMessage: () => formatTaskMovedMessage,
|
|
121040
122148
|
formatTaskMarkedDoneMessage: () => formatTaskMarkedDoneMessage,
|
|
121041
122149
|
formatSyncErrorMessage: () => formatSyncErrorMessage,
|
|
122150
|
+
formatSyncEncryptionDiagnostics: () => formatSyncEncryptionDiagnostics,
|
|
121042
122151
|
formatSettingsSearchPath: () => formatSettingsSearchPath,
|
|
121043
122152
|
formatRecurrenceLabel: () => formatRecurrenceLabel,
|
|
121044
122153
|
formatRecurrenceCountLabel: () => formatRecurrenceCountLabel,
|
|
@@ -121055,6 +122164,7 @@ __export(exports_src, {
|
|
|
121055
122164
|
formatCalendarDurationLabel: () => formatCalendarDurationLabel,
|
|
121056
122165
|
formatAIErrorAlertBody: () => formatAIErrorAlertBody,
|
|
121057
122166
|
flushPendingSave: () => flushPendingSave,
|
|
122167
|
+
findSyncEncryptionSentinel: () => findSyncEncryptionSentinel,
|
|
121058
122168
|
findSelectableProjectByTitleAndArea: () => findSelectableProjectByTitleAndArea,
|
|
121059
122169
|
findPendingAttachmentUploads: () => findPendingAttachmentUploads,
|
|
121060
122170
|
findOrphanedAttachments: () => findOrphanedAttachments,
|
|
@@ -121132,6 +122242,7 @@ __export(exports_src, {
|
|
|
121132
122242
|
createImportDiagnostic: () => createImportDiagnostic,
|
|
121133
122243
|
createImportArchiveBudget: () => createImportArchiveBudget,
|
|
121134
122244
|
createDropboxSyncRemoteMutationFencePort: () => createDropboxSyncRemoteMutationFencePort,
|
|
122245
|
+
createDropboxAttachmentPresenceIndex: () => createDropboxAttachmentPresenceIndex,
|
|
121135
122246
|
createDefaultSyncRunStoreBridge: () => createDefaultSyncRunStoreBridge,
|
|
121136
122247
|
createCustomTimeEstimate: () => createCustomTimeEstimate,
|
|
121137
122248
|
createCurrentRecurringCalendarTask: () => createCurrentRecurringCalendarTask,
|
|
@@ -121185,9 +122296,11 @@ __export(exports_src, {
|
|
|
121185
122296
|
cloudGetJson: () => cloudGetJson,
|
|
121186
122297
|
cloudGetFile: () => cloudGetFile,
|
|
121187
122298
|
cloudDeleteFile: () => cloudDeleteFile,
|
|
122299
|
+
cloudAttachmentExists: () => cloudAttachmentExists,
|
|
121188
122300
|
cloneSettings: () => cloneSettings,
|
|
121189
122301
|
cloneAppData: () => cloneAppData,
|
|
121190
122302
|
clearProviderModelsCache: () => clearProviderModelsCache,
|
|
122303
|
+
clearIdleSyncCycleSnapshot: () => clearIdleSyncCycleSnapshot,
|
|
121191
122304
|
clearDeletedTaskProjectArchiveMetadata: () => clearDeletedTaskProjectArchiveMetadata,
|
|
121192
122305
|
clearBreadcrumbs: () => clearBreadcrumbs,
|
|
121193
122306
|
checkAttachmentContentChange: () => checkAttachmentContentChange,
|
|
@@ -121205,6 +122318,12 @@ __export(exports_src, {
|
|
|
121205
122318
|
buildSyncPayloadTraceExtra: () => buildSyncPayloadTraceExtra,
|
|
121206
122319
|
buildSyncPayloadSurfaceTraceExtra: () => buildSyncPayloadSurfaceTraceExtra,
|
|
121207
122320
|
buildSyncPayloadDiffTraceExtra: () => buildSyncPayloadDiffTraceExtra,
|
|
122321
|
+
buildSyncLocationScope: () => buildSyncLocationScope,
|
|
122322
|
+
buildSyncEncryptionTransitionExtra: () => buildSyncEncryptionTransitionExtra,
|
|
122323
|
+
buildSyncEncryptionStateExtra: () => buildSyncEncryptionStateExtra,
|
|
122324
|
+
buildSyncEncryptionRemoteReadExtra: () => buildSyncEncryptionRemoteReadExtra,
|
|
122325
|
+
buildSyncEncryptionErrorExtra: () => buildSyncEncryptionErrorExtra,
|
|
122326
|
+
buildSyncEncryptionActivationExtra: () => buildSyncEncryptionActivationExtra,
|
|
121208
122327
|
buildSpeechTranscriptionPrompt: () => buildSpeechTranscriptionPrompt,
|
|
121209
122328
|
buildSpeechToTaskPrompt: () => buildSpeechToTaskPrompt,
|
|
121210
122329
|
buildSettingsSearchResults: () => buildSettingsSearchResults,
|
|
@@ -121359,8 +122478,13 @@ __export(exports_src, {
|
|
|
121359
122478
|
SYNC_FILE_GENERATION_CORRUPT_CODE: () => SYNC_FILE_GENERATION_CORRUPT_CODE,
|
|
121360
122479
|
SYNC_ENCRYPTION_TRANSITION_INCOMPLETE: () => SYNC_ENCRYPTION_TRANSITION_INCOMPLETE,
|
|
121361
122480
|
SYNC_ENCRYPTION_REMOTE_VERSION_UNAVAILABLE: () => SYNC_ENCRYPTION_REMOTE_VERSION_UNAVAILABLE,
|
|
122481
|
+
SYNC_ENCRYPTION_LOG_SENTINELS: () => SYNC_ENCRYPTION_LOG_SENTINELS,
|
|
122482
|
+
SYNC_ENCRYPTION_LOG_PREFIX: () => SYNC_ENCRYPTION_LOG_PREFIX,
|
|
122483
|
+
SYNC_ENCRYPTION_LOG_EVENTS: () => SYNC_ENCRYPTION_LOG_EVENTS,
|
|
122484
|
+
SYNC_ENCRYPTION_LOG_ABSENT: () => SYNC_ENCRYPTION_LOG_ABSENT,
|
|
121362
122485
|
SYNC_ENCRYPTION_KEYED_STATES: () => SYNC_ENCRYPTION_KEYED_STATES,
|
|
121363
122486
|
SYNC_CRYPTO_DEFAULT_KDF_PARAMS: () => SYNC_CRYPTO_DEFAULT_KDF_PARAMS,
|
|
122487
|
+
SUSPENDED_REQUEST_MESSAGE: () => SUSPENDED_REQUEST_MESSAGE,
|
|
121364
122488
|
SUPPORTED_LANGUAGES: () => SUPPORTED_LANGUAGES,
|
|
121365
122489
|
STORE_REVIEW_MIN_DAYS_SINCE_FIRST_SEEN: () => STORE_REVIEW_MIN_DAYS_SINCE_FIRST_SEEN,
|
|
121366
122490
|
STORE_REVIEW_MIN_ACTIVE_DAYS: () => STORE_REVIEW_MIN_ACTIVE_DAYS,
|
|
@@ -121463,6 +122587,7 @@ __export(exports_src, {
|
|
|
121463
122587
|
DropboxFileNotFoundError: () => DropboxFileNotFoundError,
|
|
121464
122588
|
DropboxConflictError: () => DropboxConflictError,
|
|
121465
122589
|
DataTransferRefreshError: () => DataTransferRefreshError,
|
|
122590
|
+
DROPBOX_ATTACHMENTS_PATH: () => DROPBOX_ATTACHMENTS_PATH,
|
|
121466
122591
|
DRACULA_EXTERNAL_CALENDAR_COLOR_MAP: () => DRACULA_EXTERNAL_CALENDAR_COLOR_MAP,
|
|
121467
122592
|
DRACULA_CONTEXT_COLOR_PALETTE: () => DRACULA_CONTEXT_COLOR_PALETTE,
|
|
121468
122593
|
DONATION_PROMPT_SUPPORT_CLICK_COOLDOWN_MS: () => DONATION_PROMPT_SUPPORT_CLICK_COOLDOWN_MS,
|
|
@@ -121569,6 +122694,7 @@ var init_src = __esm(() => {
|
|
|
121569
122694
|
init_sync_fast_sync();
|
|
121570
122695
|
init_sync_crypto();
|
|
121571
122696
|
init_sync_encryption();
|
|
122697
|
+
init_sync_encryption_diagnostics();
|
|
121572
122698
|
init_sync_remote_fence();
|
|
121573
122699
|
init_sync_remote_fence_providers();
|
|
121574
122700
|
init_diceware();
|
|
@@ -135064,6 +136190,7 @@ var createCloudService = (options) => {
|
|
|
135064
136190
|
isSequential: input.isSequential,
|
|
135065
136191
|
isFocused: input.isFocused,
|
|
135066
136192
|
dueDate: input.dueDate ?? undefined,
|
|
136193
|
+
startDate: input.startDate ?? undefined,
|
|
135067
136194
|
reviewAt: input.reviewAt ?? undefined,
|
|
135068
136195
|
supportNotes: input.supportNotes ?? undefined
|
|
135069
136196
|
})
|
|
@@ -135086,6 +136213,8 @@ var createCloudService = (options) => {
|
|
|
135086
136213
|
patch.isFocused = input.isFocused;
|
|
135087
136214
|
if (input.dueDate !== undefined)
|
|
135088
136215
|
patch.dueDate = input.dueDate;
|
|
136216
|
+
if (input.startDate !== undefined)
|
|
136217
|
+
patch.startDate = input.startDate;
|
|
135089
136218
|
if (input.reviewAt !== undefined)
|
|
135090
136219
|
patch.reviewAt = input.reviewAt;
|
|
135091
136220
|
if (input.supportNotes !== undefined)
|
|
@@ -137593,7 +138722,8 @@ var getProjectColumns = (db) => {
|
|
|
137593
138722
|
const names = new Set(columns.map((col) => String(col.name)));
|
|
137594
138723
|
const hasOrderNum = names.has("orderNum");
|
|
137595
138724
|
const hasDueDate = names.has("dueDate");
|
|
137596
|
-
const
|
|
138725
|
+
const hasStartDate = names.has("startDate");
|
|
138726
|
+
const selectColumns = BASE_PROJECT_COLUMNS.filter((name) => names.has(name) && (hasOrderNum || name !== "orderNum") && (hasDueDate || name !== "dueDate") && (hasStartDate || name !== "startDate"));
|
|
137597
138727
|
const resolved = { hasOrderNum, selectColumns };
|
|
137598
138728
|
projectColumnsCache.set(db, resolved);
|
|
137599
138729
|
return resolved;
|
|
@@ -138508,6 +139638,7 @@ var createService = (options, deps = defaultServiceDeps) => {
|
|
|
138508
139638
|
isSequential: input.isSequential,
|
|
138509
139639
|
isFocused: input.isFocused,
|
|
138510
139640
|
dueDate: input.dueDate ?? undefined,
|
|
139641
|
+
startDate: input.startDate ?? undefined,
|
|
138511
139642
|
reviewAt: input.reviewAt ?? undefined,
|
|
138512
139643
|
supportNotes: input.supportNotes ?? undefined
|
|
138513
139644
|
})
|
|
@@ -138529,6 +139660,8 @@ var createService = (options, deps = defaultServiceDeps) => {
|
|
|
138529
139660
|
updates.isFocused = input.isFocused;
|
|
138530
139661
|
if (input.dueDate !== undefined)
|
|
138531
139662
|
updates.dueDate = input.dueDate ?? undefined;
|
|
139663
|
+
if (input.startDate !== undefined)
|
|
139664
|
+
updates.startDate = input.startDate ?? undefined;
|
|
138532
139665
|
if (input.reviewAt !== undefined)
|
|
138533
139666
|
updates.reviewAt = input.reviewAt ?? undefined;
|
|
138534
139667
|
if (input.supportNotes !== undefined)
|
|
@@ -138905,6 +140038,7 @@ var addProjectSchema = objectType({
|
|
|
138905
140038
|
isSequential: booleanType().optional(),
|
|
138906
140039
|
isFocused: booleanType().optional(),
|
|
138907
140040
|
dueDate: isoDateLikeSchema.nullable().optional(),
|
|
140041
|
+
startDate: isoDateLikeSchema.nullable().optional(),
|
|
138908
140042
|
reviewAt: isoDateLikeSchema.nullable().optional(),
|
|
138909
140043
|
supportNotes: stringType().nullable().optional()
|
|
138910
140044
|
});
|
|
@@ -138917,6 +140051,7 @@ var updateProjectSchema = objectType({
|
|
|
138917
140051
|
isSequential: booleanType().optional(),
|
|
138918
140052
|
isFocused: booleanType().optional(),
|
|
138919
140053
|
dueDate: isoDateLikeSchema.nullable().optional(),
|
|
140054
|
+
startDate: isoDateLikeSchema.nullable().optional(),
|
|
138920
140055
|
reviewAt: isoDateLikeSchema.nullable().optional(),
|
|
138921
140056
|
supportNotes: stringType().nullable().optional()
|
|
138922
140057
|
});
|