mindwtr-mcp 1.1.5 → 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 +2061 -331
- 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;
|
|
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;
|
|
3113
3129
|
}
|
|
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;
|
|
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;
|
|
3299
3350
|
} else {
|
|
3300
|
-
|
|
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;
|
|
3477
|
+
} else {
|
|
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,
|
|
@@ -12171,6 +12472,7 @@ var init_vi = __esm(() => {
|
|
|
12171
12472
|
"bulk.keepStatus": "Giữ trạng thái",
|
|
12172
12473
|
"bulk.keepProject": "Giữ dự án",
|
|
12173
12474
|
"bulk.keepArea": "Giữ khu vực",
|
|
12475
|
+
"bulk.keepSection": "Giữ phần",
|
|
12174
12476
|
"bulk.waitingPersonRequired": "Chọn người mà các mục này đang chờ.",
|
|
12175
12477
|
"bulk.deleting": "Đang xóa các nhiệm vụ đã chọn...",
|
|
12176
12478
|
"taskEdit.aiAssistant": "Trợ lý AI",
|
|
@@ -12189,6 +12491,9 @@ var init_vi = __esm(() => {
|
|
|
12189
12491
|
"nav.main": "Chính",
|
|
12190
12492
|
"nav.inbox": "Hộp thư đến",
|
|
12191
12493
|
"nav.board": "Bảng Kanban",
|
|
12494
|
+
"nav.timeline": "Dòng thời gian",
|
|
12495
|
+
"timeline.empty": "Chưa có gì được lên lịch",
|
|
12496
|
+
"timeline.emptyHint": "Các công việc có ngày bắt đầu hoặc ngày đến hạn sẽ hiển thị ở đây dưới dạng thanh.",
|
|
12192
12497
|
"nav.projects": "Dự án",
|
|
12193
12498
|
"nav.contexts": "Ngữ cảnh",
|
|
12194
12499
|
"nav.next": "Hành động tiếp theo",
|
|
@@ -12267,6 +12572,7 @@ var init_vi = __esm(() => {
|
|
|
12267
12572
|
"keybindings.goReference": "Đến Tham khảo",
|
|
12268
12573
|
"keybindings.goCalendar": "Đến Lịch",
|
|
12269
12574
|
"keybindings.goBoard": "Đến Bảng Kanban",
|
|
12575
|
+
"keybindings.goTimeline": "Đến Dòng thời gian",
|
|
12270
12576
|
"keybindings.goDone": "Đến Hoàn thành",
|
|
12271
12577
|
"keybindings.goArchived": "Đến Lưu trữ",
|
|
12272
12578
|
"keybindings.switchArea": "Chuyển sang Khu vực 1-9",
|
|
@@ -12427,6 +12733,7 @@ var init_vi = __esm(() => {
|
|
|
12427
12733
|
"attachments.obsidianLinkPlaceholder": "obsidian://open?vault=Vault&file=Note",
|
|
12428
12734
|
"attachments.obsidianLinkInputHint": 'Dán liên kết ghi chú obsidian:// hoặc dùng "Tiêu đề | obsidian://...".',
|
|
12429
12735
|
"attachments.fileNotSupported": "Tệp đính kèm chỉ được hỗ trợ trên ứng dụng máy tính.",
|
|
12736
|
+
"attachments.webUnavailable": "Tệp đính kèm này không khả dụng trong ứng dụng web.",
|
|
12430
12737
|
"attachments.fileTooLarge": "Tệp quá lớn để tải lên.",
|
|
12431
12738
|
"attachments.fileNotReadable": "Không thể đọc tệp này nên tệp chưa được đính kèm. Hãy chuyển tệp sang thư mục khác và thử lại.",
|
|
12432
12739
|
"attachments.linkToFile": "Liên kết tới tệp…",
|
|
@@ -13348,6 +13655,10 @@ var init_vi = __esm(() => {
|
|
|
13348
13655
|
"settings.featureTimeEstimatesDesc": "Thêm ước tính thời lượng nhanh để chặn thời gian.",
|
|
13349
13656
|
"settings.featurePomodoro": "Hẹn giờ Pomodoro",
|
|
13350
13657
|
"settings.featurePomodoroDesc": "Bật bảng Pomodoro tùy chọn trong chế độ Tập trung.",
|
|
13658
|
+
"settings.featureTimeline": "Chế độ xem Dòng thời gian",
|
|
13659
|
+
"settings.featureTimelineDesc": "Hiển thị dòng thời gian chỉ đọc của các công việc có ngày trong thanh bên.",
|
|
13660
|
+
"settings.sidebarViews": "Chế độ xem trên thanh bên",
|
|
13661
|
+
"settings.sidebarViewsDesc": "Chọn chế độ xem nào hiển thị trên thanh bên. Chế độ xem bị ẩn vẫn mở được qua tìm kiếm.",
|
|
13351
13662
|
"settings.pomodoroCustomPreset": "Cài đặt sẵn tùy chỉnh",
|
|
13352
13663
|
"settings.pomodoroCustomPresetDesc": "Thêm một cài đặt sẵn tập trung/nghỉ thêm. Khớp với cài đặt sẵn tích hợp chỉ giữ các chip tích hợp.",
|
|
13353
13664
|
"settings.pomodoroFocusMinutes": "Phút tập trung",
|
|
@@ -14463,6 +14774,7 @@ var init_zh_Hans = __esm(() => {
|
|
|
14463
14774
|
"bulk.keepStatus": "保留状态",
|
|
14464
14775
|
"bulk.keepProject": "保留项目",
|
|
14465
14776
|
"bulk.keepArea": "保留领域",
|
|
14777
|
+
"bulk.keepSection": "保留分区",
|
|
14466
14778
|
"bulk.waitingPersonRequired": "选择这些事项在等待谁。",
|
|
14467
14779
|
"bulk.deleting": "正在删除所选任务…",
|
|
14468
14780
|
"taskEdit.aiAssistant": "AI 助手",
|
|
@@ -14480,6 +14792,9 @@ var init_zh_Hans = __esm(() => {
|
|
|
14480
14792
|
"nav.main": "主页",
|
|
14481
14793
|
"nav.inbox": "收集箱",
|
|
14482
14794
|
"nav.board": "看板",
|
|
14795
|
+
"nav.timeline": "时间线",
|
|
14796
|
+
"timeline.empty": "还没有排期的任务",
|
|
14797
|
+
"timeline.emptyHint": "设置了开始日期或截止日期的任务会在这里显示为色条。",
|
|
14483
14798
|
"nav.projects": "项目",
|
|
14484
14799
|
"nav.contexts": "情境",
|
|
14485
14800
|
"nav.next": "下一步行动",
|
|
@@ -14557,6 +14872,7 @@ var init_zh_Hans = __esm(() => {
|
|
|
14557
14872
|
"keybindings.goReference": "前往参考",
|
|
14558
14873
|
"keybindings.goCalendar": "前往日历",
|
|
14559
14874
|
"keybindings.goBoard": "前往看板",
|
|
14875
|
+
"keybindings.goTimeline": "前往时间线",
|
|
14560
14876
|
"keybindings.goDone": "前往已完成",
|
|
14561
14877
|
"keybindings.goArchived": "前往归档",
|
|
14562
14878
|
"keybindings.list.nextPrev": "上下移动选中项",
|
|
@@ -14711,9 +15027,12 @@ var init_zh_Hans = __esm(() => {
|
|
|
14711
15027
|
"attachments.obsidianLinkPlaceholder": "obsidian://open?vault=Vault&file=Note",
|
|
14712
15028
|
"attachments.obsidianLinkInputHint": "粘贴 obsidian:// 笔记链接,或使用“标题 | obsidian://...”。",
|
|
14713
15029
|
"attachments.fileNotSupported": "文件附件仅在桌面应用中支持。",
|
|
15030
|
+
"attachments.webUnavailable": "此附件在网页版中无法使用。",
|
|
14714
15031
|
"attachments.fileTooLarge": "文件过大,无法上传。",
|
|
14715
15032
|
"attachments.fileNotReadable": "无法读取此文件,因此未添加附件。请将文件移动到其他文件夹后重试。",
|
|
14716
15033
|
"attachments.linkToFile": "链接到文件…",
|
|
15034
|
+
"attachments.linkedFileElsewhere": "此链接指向另一台设备上的文件:{{path}}。请在那台设备上打开,或改为直接添加该文件作为附件。",
|
|
15035
|
+
"attachments.openLinkFailed": "无法打开此链接。",
|
|
14717
15036
|
"attachments.invalidFileType": "不支持的文件类型。",
|
|
14718
15037
|
"attachments.invalidLink": "请输入有效的链接。",
|
|
14719
15038
|
"attachments.photoUnavailableTitle": "图片选择不可用",
|
|
@@ -15055,7 +15374,7 @@ var init_zh_Hans = __esm(() => {
|
|
|
15055
15374
|
"projects.sectionPlaceholder": "分区标题",
|
|
15056
15375
|
"projects.noSection": "无分区",
|
|
15057
15376
|
"projects.sectionEmpty": "暂无任务",
|
|
15058
|
-
"projects.deleteSectionConfirm": "
|
|
15377
|
+
"projects.deleteSectionConfirm": "删除此分区?其中的任务不会被删除,会移到“无分区”。",
|
|
15059
15378
|
"projects.areaFilter": "领域筛选",
|
|
15060
15379
|
"projects.allAreas": "所有领域",
|
|
15061
15380
|
"projects.noArea": "无领域",
|
|
@@ -15082,6 +15401,8 @@ var init_zh_Hans = __esm(() => {
|
|
|
15082
15401
|
"projects.complete": "完成",
|
|
15083
15402
|
"projects.archive": "归档",
|
|
15084
15403
|
"projects.reactivate": "重新激活",
|
|
15404
|
+
"projects.archivedTaskInspectionHint": "双击查看此任务。重新激活项目后才能编辑。",
|
|
15405
|
+
"projects.archivedReadOnlyHint": "项目已归档。重新激活后才能编辑此任务。",
|
|
15085
15406
|
"projects.actionsLabel": "操作",
|
|
15086
15407
|
"projects.archiveHelp": "归档项目会将其和剩余任务标记为完成,可随时重新激活。",
|
|
15087
15408
|
"projects.completeConfirm": "将此项目标记为完成并结束其所有任务?",
|
|
@@ -15364,6 +15685,7 @@ var init_zh_Hans = __esm(() => {
|
|
|
15364
15685
|
"settings.material3ThemeDesc": "在 Android 上使用 Material 3 配色",
|
|
15365
15686
|
"settings.selectLang": "选择您的首选语言",
|
|
15366
15687
|
"settings.languagePartlyTranslated": "部分翻译",
|
|
15688
|
+
"settings.videoTutorials": "视频教程",
|
|
15367
15689
|
"settings.privacy": "隐私",
|
|
15368
15690
|
"settings.mobile.appLock": "应用锁",
|
|
15369
15691
|
"settings.mobile.appLockDesc": "打开 Mindwtr 或返回应用时需要设备锁验证。它保护应用界面,不加密设备上的数据库。",
|
|
@@ -15451,6 +15773,8 @@ var init_zh_Hans = __esm(() => {
|
|
|
15451
15773
|
"settings.syncEncryptionUnlock": "输入密码短语",
|
|
15452
15774
|
"settings.syncEncryptionDecline": "暂不",
|
|
15453
15775
|
"settings.syncEncryptionPausedDesc": "在您输入密码短语之前,本设备的自动同步将保持暂停。",
|
|
15776
|
+
"settings.syncEncryptionLockedRecheckHint": "如果该同步位置已不再存放加密文件,请点按“立即同步”,本设备会重新检查该位置并继续同步。",
|
|
15777
|
+
"settings.syncEncryptionNoEncryptedRemote": "该同步位置已没有加密文件,因此本设备的加密现已关闭。如需加密该位置,请重新开启。",
|
|
15454
15778
|
"settings.syncEncryptionRemoteEncrypted": "此同步位置已加密。请输入其同步密码短语以继续同步。",
|
|
15455
15779
|
"settings.syncEncryptionRemotePlaintext": "同步已停止:此同步位置不再加密。请在此设备上关闭同步加密,或在该同步位置重新启用加密。",
|
|
15456
15780
|
"settings.syncEncryptionRemotePlaintextDesc": "另一台设备在此同步位置关闭了加密。此设备上的内容没有被更改或降级。若要以明文继续同步,请在此设备上关闭同步加密;否则请在该同步位置重新启用加密。",
|
|
@@ -15680,6 +16004,10 @@ var init_zh_Hans = __esm(() => {
|
|
|
15680
16004
|
"settings.featureTimeEstimatesDesc": "为时间管理添加时长估计。",
|
|
15681
16005
|
"settings.featurePomodoro": "番茄钟",
|
|
15682
16006
|
"settings.featurePomodoroDesc": "在聚焦视图中启用可选的番茄钟面板。",
|
|
16007
|
+
"settings.featureTimeline": "时间线视图",
|
|
16008
|
+
"settings.featureTimelineDesc": "在侧边栏显示有日期任务的只读时间线。",
|
|
16009
|
+
"settings.sidebarViews": "侧边栏视图",
|
|
16010
|
+
"settings.sidebarViewsDesc": "选择侧边栏中显示哪些视图。隐藏的视图仍可通过搜索打开。",
|
|
15683
16011
|
"settings.pomodoroCustomPreset": "自定义预设",
|
|
15684
16012
|
"settings.pomodoroCustomPresetDesc": "添加一个额外的专注/休息预设。若与内置预设相同,将继续只显示内置选项。",
|
|
15685
16013
|
"settings.pomodoroFocusMinutes": "专注分钟",
|
|
@@ -15743,6 +16071,7 @@ var init_zh_Hans = __esm(() => {
|
|
|
15743
16071
|
"tags.title": "标签",
|
|
15744
16072
|
"areas.edit": "编辑领域",
|
|
15745
16073
|
"common.edit": "编辑",
|
|
16074
|
+
"common.view": "查看",
|
|
15746
16075
|
"common.add": "添加",
|
|
15747
16076
|
"common.open": "打开",
|
|
15748
16077
|
"common.ok": "确定",
|
|
@@ -16406,6 +16735,12 @@ App Store 已提供更新,是否立即打开应用页面?`,
|
|
|
16406
16735
|
"settings.syncMobile.accountStatus": "账户状态",
|
|
16407
16736
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "请在 Dropbox OAuth 设置里添加以下精确回调地址。",
|
|
16408
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": "关闭",
|
|
16409
16744
|
"settings.syncMobile.clearPendingAttachmentDeletes": "清除待处理的附件删除?",
|
|
16410
16745
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "这台设备上的 CloudKit 已被限制。请检查屏幕使用时间、设备管理或 iCloud 限制后再试。",
|
|
16411
16746
|
"settings.syncMobile.connectedToDropbox": "已连接 Dropbox。",
|
|
@@ -16493,6 +16828,9 @@ App Store 已提供更新,是否立即打开应用页面?`,
|
|
|
16493
16828
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV 端点可访问。",
|
|
16494
16829
|
"settings.persistentCaptureLabel": "通知栏快速收集",
|
|
16495
16830
|
"settings.persistentCaptureDesc": "保留常驻通知,随时随地(包括锁屏)快速收集。",
|
|
16831
|
+
"settings.exactAlarmsLabel": "提醒可能会延迟",
|
|
16832
|
+
"settings.exactAlarmsDesc": "Android 未允许 Mindwtr 设置精确闹钟,提醒可能会晚一分钟才响起。",
|
|
16833
|
+
"settings.exactAlarmsAllow": "允许",
|
|
16496
16834
|
"settings.appSearchLabel": "在系统搜索中显示",
|
|
16497
16835
|
"settings.appSearchDesc": "允许 Android 系统搜索按标题查找你的活动任务、项目和领域。数据不会离开此设备。",
|
|
16498
16836
|
"captureNotification.title": "快速收集",
|
|
@@ -16827,6 +17165,8 @@ App Store 已提供更新,是否立即打开应用页面?`,
|
|
|
16827
17165
|
"settings.gettingStartedContentContinueDesc": "完成此处的设置后,你仍可添加引导式“快速上手”项目和示例收集箱项目。",
|
|
16828
17166
|
"settings.syncSetupGuideTitle": "数据与同步设置指南",
|
|
16829
17167
|
"settings.syncSetupGuideDesc": "Dropbox、iCloud、WebDAV、文件同步和恢复的设置说明。",
|
|
17168
|
+
"settings.syncEncryptionGuideTitle": "同步加密指南",
|
|
17169
|
+
"settings.syncEncryptionGuideDesc": "它保护什么、哪些服务器支持它,以及口令如何工作。",
|
|
16830
17170
|
"settings.importSetupGuideTitle": "导入设置指南",
|
|
16831
17171
|
"settings.importSetupGuideDesc": "支持 Todoist、TickTick、DGT GTD、OmniFocus、Mindwtr CSV、Apple 提醒事项和备份导入路径。",
|
|
16832
17172
|
"settings.backupDiagnostics.newerVersion": "此备份由较新版本的 Mindwtr({{version}})创建。",
|
|
@@ -16849,7 +17189,7 @@ App Store 已提供更新,是否立即打开应用页面?`,
|
|
|
16849
17189
|
"settings.importDiagnostics.unmappedDate": "{{count}} 个日期值无法转换,已省略。",
|
|
16850
17190
|
"settings.importDiagnostics.unmappedStatus": "{{count}} 个状态值无法转换,已使用安全默认值。",
|
|
16851
17191
|
"settings.importDiagnostics.unsupportedRecurrence": "{{count}} 条不支持的重复规则已保留为备注。",
|
|
16852
|
-
"settings.syncRemoteBusy": "
|
|
17192
|
+
"settings.syncRemoteBusy": "另一台 Mindwtr 设备暂时占用了此同步位置。同步将自动重试。",
|
|
16853
17193
|
"settings.syncRemoteCleanupDeferred": "同步操作已完成。Mindwtr 无法移除临时同步锁,但该锁会自动过期。无需重试。",
|
|
16854
17194
|
"settings.syncAttachmentWriteDeferred": "部分附件更改未能完成。请恢复缺失的本地文件或移除受影响的附件,然后再次同步。",
|
|
16855
17195
|
"settings.syncFileAttachmentTooLarge": "Mindwtr 已保留本地附件。File Sync 只能同步小于 100 MB 的附件。请换用较小的文件或移除该附件,然后再次同步。",
|
|
@@ -16942,6 +17282,7 @@ var init_zh_Hant = __esm(() => {
|
|
|
16942
17282
|
"bulk.keepStatus": "保留狀態",
|
|
16943
17283
|
"bulk.keepProject": "保留項目",
|
|
16944
17284
|
"bulk.keepArea": "保留領域",
|
|
17285
|
+
"bulk.keepSection": "保留分區",
|
|
16945
17286
|
"bulk.waitingPersonRequired": "選擇這些事項在等待誰。",
|
|
16946
17287
|
"bulk.deleting": "正在刪除所選任務…",
|
|
16947
17288
|
"taskEdit.aiAssistant": "AI 助手",
|
|
@@ -16959,6 +17300,9 @@ var init_zh_Hant = __esm(() => {
|
|
|
16959
17300
|
"nav.main": "主頁",
|
|
16960
17301
|
"nav.inbox": "收集箱",
|
|
16961
17302
|
"nav.board": "看板",
|
|
17303
|
+
"nav.timeline": "時間軸",
|
|
17304
|
+
"timeline.empty": "還沒有排期的任務",
|
|
17305
|
+
"timeline.emptyHint": "設定了開始日期或截止日期的任務會在這裡顯示為色條。",
|
|
16962
17306
|
"nav.projects": "項目",
|
|
16963
17307
|
"nav.contexts": "情境",
|
|
16964
17308
|
"nav.next": "下一步行動",
|
|
@@ -17036,6 +17380,7 @@ var init_zh_Hant = __esm(() => {
|
|
|
17036
17380
|
"keybindings.goReference": "前往參考",
|
|
17037
17381
|
"keybindings.goCalendar": "前往日曆",
|
|
17038
17382
|
"keybindings.goBoard": "前往看板",
|
|
17383
|
+
"keybindings.goTimeline": "前往時間軸",
|
|
17039
17384
|
"keybindings.goDone": "前往已完成",
|
|
17040
17385
|
"keybindings.goArchived": "前往歸檔",
|
|
17041
17386
|
"keybindings.list.nextPrev": "上下移動選中項",
|
|
@@ -17190,9 +17535,12 @@ var init_zh_Hant = __esm(() => {
|
|
|
17190
17535
|
"attachments.obsidianLinkPlaceholder": "obsidian://open?vault=Vault&file=Note",
|
|
17191
17536
|
"attachments.obsidianLinkInputHint": "貼上 obsidian:// 筆記連結,或使用「標題 | obsidian://...」。",
|
|
17192
17537
|
"attachments.fileNotSupported": "文件附件僅在桌面應用中支持。",
|
|
17538
|
+
"attachments.webUnavailable": "此附件在網頁版中無法使用。",
|
|
17193
17539
|
"attachments.fileTooLarge": "文件過大,無法上傳。",
|
|
17194
17540
|
"attachments.fileNotReadable": "無法讀取此文件,因此未加入附件。請將文件移至其他資料夾後再試一次。",
|
|
17195
17541
|
"attachments.linkToFile": "連結到文件…",
|
|
17542
|
+
"attachments.linkedFileElsewhere": "此連結指向另一台裝置上的檔案:{{path}}。請在該裝置上開啟,或改為直接加入該檔案作為附件。",
|
|
17543
|
+
"attachments.openLinkFailed": "無法開啟此連結。",
|
|
17196
17544
|
"attachments.invalidFileType": "不支持的文件類型。",
|
|
17197
17545
|
"attachments.invalidLink": "請輸入有效的鏈接。",
|
|
17198
17546
|
"attachments.photoUnavailableTitle": "圖片選擇不可用",
|
|
@@ -17534,7 +17882,7 @@ var init_zh_Hant = __esm(() => {
|
|
|
17534
17882
|
"projects.sectionPlaceholder": "分區標題",
|
|
17535
17883
|
"projects.noSection": "無分區",
|
|
17536
17884
|
"projects.sectionEmpty": "尚無任務",
|
|
17537
|
-
"projects.deleteSectionConfirm": "
|
|
17885
|
+
"projects.deleteSectionConfirm": "刪除此分區?其中的任務不會被刪除,會移到「無分區」。",
|
|
17538
17886
|
"projects.areaFilter": "領域篩選",
|
|
17539
17887
|
"projects.allAreas": "所有領域",
|
|
17540
17888
|
"projects.noArea": "無領域",
|
|
@@ -17561,6 +17909,8 @@ var init_zh_Hant = __esm(() => {
|
|
|
17561
17909
|
"projects.complete": "完成",
|
|
17562
17910
|
"projects.archive": "歸檔",
|
|
17563
17911
|
"projects.reactivate": "重新激活",
|
|
17912
|
+
"projects.archivedTaskInspectionHint": "點兩下檢視此任務。重新激活專案後才能編輯。",
|
|
17913
|
+
"projects.archivedReadOnlyHint": "專案已歸檔。重新激活後才能編輯此任務。",
|
|
17564
17914
|
"projects.actionsLabel": "操作",
|
|
17565
17915
|
"projects.archiveHelp": "歸檔項目會將其和剩餘任務標記為完成,可隨時重新激活。",
|
|
17566
17916
|
"projects.completeConfirm": "將此項目標記爲完成並結束其所有任務?",
|
|
@@ -17843,6 +18193,7 @@ var init_zh_Hant = __esm(() => {
|
|
|
17843
18193
|
"settings.material3ThemeDesc": "在 Android 上使用 Material 3 配色",
|
|
17844
18194
|
"settings.selectLang": "選擇您的首選語言",
|
|
17845
18195
|
"settings.languagePartlyTranslated": "部分翻譯",
|
|
18196
|
+
"settings.videoTutorials": "影片教學",
|
|
17846
18197
|
"settings.privacy": "隱私",
|
|
17847
18198
|
"settings.mobile.appLock": "應用鎖",
|
|
17848
18199
|
"settings.mobile.appLockDesc": "打開 Mindwtr 或返回應用時需要設備鎖驗證。它保護應用界面,不加密設備上的資料庫。",
|
|
@@ -17930,6 +18281,8 @@ var init_zh_Hant = __esm(() => {
|
|
|
17930
18281
|
"settings.syncEncryptionUnlock": "輸入密碼短語",
|
|
17931
18282
|
"settings.syncEncryptionDecline": "暫時不要",
|
|
17932
18283
|
"settings.syncEncryptionPausedDesc": "在您輸入密碼短語之前,本裝置的自動同步會保持暫停。",
|
|
18284
|
+
"settings.syncEncryptionLockedRecheckHint": "如果該同步位置已不再存放加密檔案,請點按「立即同步」,本裝置會重新檢查該位置並繼續同步。",
|
|
18285
|
+
"settings.syncEncryptionNoEncryptedRemote": "該同步位置已沒有加密檔案,因此本裝置的加密現已關閉。如需加密該位置,請重新開啟。",
|
|
17933
18286
|
"settings.syncEncryptionRemoteEncrypted": "此同步位置已加密。請輸入其同步密碼短語以繼續同步。",
|
|
17934
18287
|
"settings.syncEncryptionRemotePlaintext": "同步已停止:此同步位置不再加密。請在此裝置上關閉同步加密,或在該同步位置重新啟用加密。",
|
|
17935
18288
|
"settings.syncEncryptionRemotePlaintextDesc": "另一台裝置在此同步位置關閉了加密。此裝置上的內容沒有被變更或降級。若要以純文字繼續同步,請在此裝置上關閉同步加密;否則請在該同步位置重新啟用加密。",
|
|
@@ -18159,6 +18512,10 @@ var init_zh_Hant = __esm(() => {
|
|
|
18159
18512
|
"settings.featureTimeEstimatesDesc": "爲時間管理添加時長估計。",
|
|
18160
18513
|
"settings.featurePomodoro": "番茄鐘",
|
|
18161
18514
|
"settings.featurePomodoroDesc": "在聚焦視圖中啓用可選的番茄鐘面板。",
|
|
18515
|
+
"settings.featureTimeline": "時間軸視圖",
|
|
18516
|
+
"settings.featureTimelineDesc": "在側邊欄顯示有日期任務的唯讀時間軸。",
|
|
18517
|
+
"settings.sidebarViews": "側邊欄視圖",
|
|
18518
|
+
"settings.sidebarViewsDesc": "選擇側邊欄中顯示哪些視圖。隱藏的視圖仍可透過搜尋開啟。",
|
|
18162
18519
|
"settings.pomodoroCustomPreset": "自定義預設",
|
|
18163
18520
|
"settings.pomodoroCustomPresetDesc": "添加一個額外的專注/休息預設。若與內建預設相同,將繼續只顯示內建選項。",
|
|
18164
18521
|
"settings.pomodoroFocusMinutes": "專注分鐘",
|
|
@@ -18222,6 +18579,7 @@ var init_zh_Hant = __esm(() => {
|
|
|
18222
18579
|
"tags.title": "標籤",
|
|
18223
18580
|
"areas.edit": "編輯領域",
|
|
18224
18581
|
"common.edit": "編輯",
|
|
18582
|
+
"common.view": "檢視",
|
|
18225
18583
|
"common.add": "添加",
|
|
18226
18584
|
"common.open": "打開",
|
|
18227
18585
|
"common.ok": "確定",
|
|
@@ -18885,6 +19243,12 @@ App Store 已提供更新,是否立即打開應用頁面?`,
|
|
|
18885
19243
|
"settings.syncMobile.accountStatus": "賬戶狀態",
|
|
18886
19244
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "請在 Dropbox OAuth 設置裡添加以下精確回調地址。",
|
|
18887
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": "關閉",
|
|
18888
19252
|
"settings.syncMobile.clearPendingAttachmentDeletes": "清除待處理的附件刪除?",
|
|
18889
19253
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "這臺設備上的 CloudKit 已被限制。請檢查屏幕使用時間、設備管理或 iCloud 限制後再試。",
|
|
18890
19254
|
"settings.syncMobile.connectedToDropbox": "已連接 Dropbox。",
|
|
@@ -18972,6 +19336,9 @@ App Store 已提供更新,是否立即打開應用頁面?`,
|
|
|
18972
19336
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV 端點可訪問。",
|
|
18973
19337
|
"settings.persistentCaptureLabel": "通知列快速收集",
|
|
18974
19338
|
"settings.persistentCaptureDesc": "保留常駐通知,隨時隨地(包括鎖定畫面)快速收集。",
|
|
19339
|
+
"settings.exactAlarmsLabel": "提醒可能會延遲",
|
|
19340
|
+
"settings.exactAlarmsDesc": "Android 未允許 Mindwtr 設定精確鬧鐘,提醒可能會晚一分鐘才響起。",
|
|
19341
|
+
"settings.exactAlarmsAllow": "允許",
|
|
18975
19342
|
"settings.appSearchLabel": "在系統搜尋中顯示",
|
|
18976
19343
|
"settings.appSearchDesc": "允許 Android 系統搜尋依標題找到你的進行中任務、專案與領域。資料不會離開此裝置。",
|
|
18977
19344
|
"captureNotification.title": "快速收集",
|
|
@@ -19306,6 +19673,8 @@ App Store 已提供更新,是否立即打開應用頁面?`,
|
|
|
19306
19673
|
"settings.gettingStartedContentContinueDesc": "完成這裡的設定後,你仍可加入引導式「快速上手」專案和範例收集箱項目。",
|
|
19307
19674
|
"settings.syncSetupGuideTitle": "資料與同步設定指南",
|
|
19308
19675
|
"settings.syncSetupGuideDesc": "Dropbox、iCloud、WebDAV、檔案同步和還原的設定說明。",
|
|
19676
|
+
"settings.syncEncryptionGuideTitle": "同步加密指南",
|
|
19677
|
+
"settings.syncEncryptionGuideDesc": "它保護什麼、哪些伺服器支援它,以及密語如何運作。",
|
|
19309
19678
|
"settings.importSetupGuideTitle": "匯入設定指南",
|
|
19310
19679
|
"settings.importSetupGuideDesc": "支援 Todoist、TickTick、DGT GTD、OmniFocus、Mindwtr CSV、Apple 提醒事項和備份匯入路徑。",
|
|
19311
19680
|
"settings.backupDiagnostics.newerVersion": "此備份由較新版本的 Mindwtr({{version}})建立。",
|
|
@@ -19328,7 +19697,7 @@ App Store 已提供更新,是否立即打開應用頁面?`,
|
|
|
19328
19697
|
"settings.importDiagnostics.unmappedDate": "{{count}} 個日期值無法轉換,已省略。",
|
|
19329
19698
|
"settings.importDiagnostics.unmappedStatus": "{{count}} 個狀態值無法轉換,已使用安全預設值。",
|
|
19330
19699
|
"settings.importDiagnostics.unsupportedRecurrence": "{{count}} 條不支援的重複規則已保留為備註。",
|
|
19331
|
-
"settings.syncRemoteBusy": "
|
|
19700
|
+
"settings.syncRemoteBusy": "另一台 Mindwtr 裝置暫時佔用了此同步位置。同步將自動重試。",
|
|
19332
19701
|
"settings.syncRemoteCleanupDeferred": "同步作業已完成。Mindwtr 無法移除暫時同步鎖,但該鎖會自動失效。無需重試。",
|
|
19333
19702
|
"settings.syncAttachmentWriteDeferred": "部分附件變更未能完成。請還原缺少的本機檔案或移除受影響的附件,然後再次同步。",
|
|
19334
19703
|
"settings.syncFileAttachmentTooLarge": "Mindwtr 已保留本機附件。File Sync 只能同步小於 100 MB 的附件。請改用較小的檔案或移除該附件,然後再次同步。",
|
|
@@ -23838,7 +24207,7 @@ var init_de = __esm(() => {
|
|
|
23838
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").',
|
|
23839
24208
|
"quickAdd.example": "Beispiel: Mama anrufen /due:tomorrow @phone",
|
|
23840
24209
|
"quickAdd.inlineHint": "Tipp: Mama anrufen /due:tomorrow 5pm @phone #family",
|
|
23841
|
-
"quickAdd.syntaxHelp": "Hilfe zur Schnell-
|
|
24210
|
+
"quickAdd.syntaxHelp": "Hilfe zur Schnell-Hinzufügen-Syntax",
|
|
23842
24211
|
"quickAdd.placeholder": "Eine Aufgabe hinzufügen … benutzen Sie @context +Project #tag",
|
|
23843
24212
|
"quickAdd.inputLabel": "Schnelle Eingabe",
|
|
23844
24213
|
"quickAdd.inputHint": "Geben Sie eine Aufgabe ein und drücken Sie Eingabe zum Speichern.",
|
|
@@ -23879,7 +24248,7 @@ var init_de = __esm(() => {
|
|
|
23879
24248
|
"quickAdd.audioSavingSpeechToText": "Aufnahme wird gespeichert und Sprache in Text umgewandelt.",
|
|
23880
24249
|
"quickAdd.audioNoteTitle": "Sprachnotiz",
|
|
23881
24250
|
"quickAdd.audioPermissionTitle": "Zugriff auf Mikrofon ist notwendig",
|
|
23882
|
-
"quickAdd.audioPermissionBody": "
|
|
24251
|
+
"quickAdd.audioPermissionBody": "Mikrofonzugriff erlauben, um Sprachnotizen aufzunehmen.",
|
|
23883
24252
|
"quickAdd.audioErrorTitle": "Aufnahme fehlgeschlagen",
|
|
23884
24253
|
"quickAdd.audioErrorBody": "Wir konnten nichts aufnehmen. Bitte versuchen Sie es nochmals.",
|
|
23885
24254
|
"quickAdd.invalidDateCommand": "Ungültiger Datumsbefehl",
|
|
@@ -23904,7 +24273,7 @@ var init_de = __esm(() => {
|
|
|
23904
24273
|
"keybindings.section.taskList": "Aufgabenliste",
|
|
23905
24274
|
"keybindings.section.quickAddSyntax": "Schnelleingabe-Syntax",
|
|
23906
24275
|
"keybindings.section.global": "Allgemein",
|
|
23907
|
-
"keybindings.openHelp": "
|
|
24276
|
+
"keybindings.openHelp": "Tastaturkürzel anzeigen",
|
|
23908
24277
|
"keybindings.openSettings": "Einstellungen öffnen",
|
|
23909
24278
|
"keybindings.toggleFullscreen": "Vollbild umschalten",
|
|
23910
24279
|
"keybindings.switchArea": "Bereich wechseln",
|
|
@@ -23949,7 +24318,7 @@ var init_de = __esm(() => {
|
|
|
23949
24318
|
"list.todo": "Zu tun",
|
|
23950
24319
|
"list.inProgress": "In Arbeit",
|
|
23951
24320
|
"list.next": "Nächste Aktionen",
|
|
23952
|
-
"list.someday": "Irgendwann/
|
|
24321
|
+
"list.someday": "Irgendwann/Vielleicht",
|
|
23953
24322
|
"list.reference": "Referenz",
|
|
23954
24323
|
"list.waiting": "Abwarten",
|
|
23955
24324
|
"list.done": "Abgeschlossen",
|
|
@@ -23967,7 +24336,7 @@ var init_de = __esm(() => {
|
|
|
23967
24336
|
"list.densityComfortable": "Komfortabel",
|
|
23968
24337
|
"list.densityCompact": "Kompakt",
|
|
23969
24338
|
"list.densityCondensed": "Verdichtet",
|
|
23970
|
-
"reference.empty": "Noch keine
|
|
24339
|
+
"reference.empty": "Noch keine Referenzeinträge.",
|
|
23971
24340
|
"status.inbox": "Posteingang",
|
|
23972
24341
|
"status.todo": "Zu tun",
|
|
23973
24342
|
"status.next": "Nächstes",
|
|
@@ -24005,7 +24374,7 @@ var init_de = __esm(() => {
|
|
|
24005
24374
|
"taskEdit.duplicateDoneBody": "Es wurde eine neue Kopie im Posteingang erstellt.",
|
|
24006
24375
|
"taskEdit.aiClarify": "Klären mit KI",
|
|
24007
24376
|
"taskEdit.aiBreakdown": "KI-Zusammenfassung",
|
|
24008
|
-
"taskEdit.itemNamePlaceholder": "
|
|
24377
|
+
"taskEdit.itemNamePlaceholder": "Elementname",
|
|
24009
24378
|
"taskEdit.titleLabel": "Titel",
|
|
24010
24379
|
"taskEdit.editorLayoutHelpLabel": "Editor-Layout-Hilfe",
|
|
24011
24380
|
"taskEdit.editorLayoutHelpText": "Du kannst in Einstellungen -> GTD -> Aufgaben-Editor-Layout anpassen, welche Felder hier angezeigt werden.",
|
|
@@ -24038,7 +24407,7 @@ var init_de = __esm(() => {
|
|
|
24038
24407
|
"markdown.collapse": "Zusammenklappen",
|
|
24039
24408
|
"markdown.toolbar.heading": "Titel einfügen",
|
|
24040
24409
|
"markdown.toolbar.bold": "Fett",
|
|
24041
|
-
"markdown.toolbar.italic": "
|
|
24410
|
+
"markdown.toolbar.italic": "Kursiv",
|
|
24042
24411
|
"markdown.toolbar.strikethrough": "Durchgestrichen",
|
|
24043
24412
|
"markdown.toolbar.bulletList": "Punkteliste",
|
|
24044
24413
|
"markdown.toolbar.horizontalRule": "Horizontale Linie",
|
|
@@ -24055,7 +24424,7 @@ var init_de = __esm(() => {
|
|
|
24055
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.",
|
|
24056
24425
|
"attachments.unrecoverable": "Dieser Anhang ist im synchronisierten Speicher nicht mehr verfügbar. Der ungültige Verweis wurde entfernt.",
|
|
24057
24426
|
"attachments.remove": "Entfernen",
|
|
24058
|
-
"attachments.transferProgress": "Fortschritt der
|
|
24427
|
+
"attachments.transferProgress": "Fortschritt der Übertragung von Anhängen",
|
|
24059
24428
|
"attachments.linkPlaceholder": "https://beispiel.com",
|
|
24060
24429
|
"attachments.linkInputHint": 'Tipp: eine URL einfügen, oder "Titel | URL" benutzen.',
|
|
24061
24430
|
"attachments.attachObsidianNote": "Obsidian-Notiz anhängen",
|
|
@@ -24065,12 +24434,12 @@ var init_de = __esm(() => {
|
|
|
24065
24434
|
"attachments.fileTooLarge": "Die Datei ist zu groß für das Hochladen.",
|
|
24066
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.",
|
|
24067
24436
|
"attachments.linkToFile": "Mit Datei verknüpfen…",
|
|
24068
|
-
"attachments.invalidFileType": "Nicht unterstützter
|
|
24437
|
+
"attachments.invalidFileType": "Nicht unterstützter Dateityp.",
|
|
24069
24438
|
"attachments.invalidLink": "Bitte eine gültige URL angeben.",
|
|
24070
|
-
"attachments.photoUnavailableTitle": "
|
|
24439
|
+
"attachments.photoUnavailableTitle": "Fotoauswahl ist nicht verfügbar",
|
|
24071
24440
|
"attachments.photoUnavailableBody": "Die App neu erstellen, um Fotoanhänge zu ermöglichen.",
|
|
24072
24441
|
"taskEdit.locationLabel": "Standort",
|
|
24073
|
-
"taskEdit.locationPlaceholder": "z.B. Büro",
|
|
24442
|
+
"taskEdit.locationPlaceholder": "z. B. Büro",
|
|
24074
24443
|
"taskEdit.projectLabel": "Projekt",
|
|
24075
24444
|
"taskEdit.noProjectOption": "Kein Projekt",
|
|
24076
24445
|
"taskEdit.sectionLabel": "Abschnitt",
|
|
@@ -24080,7 +24449,7 @@ var init_de = __esm(() => {
|
|
|
24080
24449
|
"taskEdit.moreOptions": "Mehr Optionen",
|
|
24081
24450
|
"taskEdit.hideOptions": "Optionen verstecken",
|
|
24082
24451
|
"taskEdit.startDateLabel": "Anfangsdatum",
|
|
24083
|
-
"taskEdit.dueDateLabel": "
|
|
24452
|
+
"taskEdit.dueDateLabel": "Fälligkeitsdatum",
|
|
24084
24453
|
"taskEdit.reviewDateLabel": "Revisions-Datum",
|
|
24085
24454
|
"taskEdit.dateOnly": "Nur Datum",
|
|
24086
24455
|
"taskEdit.startModeLabel": "Startmodus",
|
|
@@ -24157,16 +24526,16 @@ var init_de = __esm(() => {
|
|
|
24157
24526
|
"recurrence.ordinal.second": "Zweiten",
|
|
24158
24527
|
"recurrence.ordinal.third": "Dritten",
|
|
24159
24528
|
"recurrence.ordinal.fourth": "Vierten",
|
|
24160
|
-
"recurrence.ordinal.last": "
|
|
24529
|
+
"recurrence.ordinal.last": "Letzten",
|
|
24161
24530
|
"recurrence.monthlyOnDay": "Der gleiche Tag jeden Monats",
|
|
24162
24531
|
"recurrence.monthlyOnLastWeekday": "Letzter {weekday}",
|
|
24163
|
-
"recurrence.strategyLabel": "
|
|
24532
|
+
"recurrence.strategyLabel": "Strategisch",
|
|
24164
24533
|
"recurrence.strategyStrict": "Strikt",
|
|
24165
24534
|
"recurrence.strategyFluid": "Fliessend",
|
|
24166
|
-
"recurrence.strategyStrictDesc": "Fällig am geplanten Datum (z.B. Rechnungen)",
|
|
24167
|
-
"recurrence.strategyFluidDesc": "Fällig nach Abschluss (z.B. Wäsche)",
|
|
24168
|
-
"recurrence.afterCompletion": "Nach
|
|
24169
|
-
"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",
|
|
24170
24539
|
"recurrence.showFutureInCalendar": "Künftige Wiederholungen im Kalender anzeigen",
|
|
24171
24540
|
"recurrence.showFutureInCalendarHint": "Nur Planungsvorschau; die nächste echte Aufgabe wird erst erstellt, wenn diese abgeschlossen wird.",
|
|
24172
24541
|
"inbox.title": "Posteingang",
|
|
@@ -24180,7 +24549,7 @@ var init_de = __esm(() => {
|
|
|
24180
24549
|
"inbox.refineHint": "Präzisiere den Titel und die Details, bevor Sie entscheiden, was als Nächstes getan werden soll.",
|
|
24181
24550
|
"inbox.refineNext": "Nächstes",
|
|
24182
24551
|
"inbox.refineDelete": "Löschen",
|
|
24183
|
-
"inbox.isActionable": "Ist
|
|
24552
|
+
"inbox.isActionable": "Ist diese ausführbar?",
|
|
24184
24553
|
"inbox.actionableHint": "Können Sie eine physische Handlung ausführen?",
|
|
24185
24554
|
"inbox.yes": "Ja",
|
|
24186
24555
|
"inbox.no": "Nein",
|
|
@@ -24201,7 +24570,7 @@ var init_de = __esm(() => {
|
|
|
24201
24570
|
"inbox.addContextPlaceholder": "Neuen Kontext hinzufügen ...",
|
|
24202
24571
|
"inbox.waitingQuestion": "Auf wen oder was warten Sie?",
|
|
24203
24572
|
"inbox.waitingHint": "Fügen Sie eine Notiz hinzu, um sich zu erinnern, auf was Sie warten",
|
|
24204
|
-
"inbox.waitingPlaceholder": "Z.B. Auf Jonathan's Revision warten ...",
|
|
24573
|
+
"inbox.waitingPlaceholder": "Z. B. Auf Jonathan's Revision warten ...",
|
|
24205
24574
|
"inbox.assignProjectQuestion": "Zu einem Projekt hinzufügen? (Optional)",
|
|
24206
24575
|
"inbox.noProject": "Kein Projekt",
|
|
24207
24576
|
"inbox.skip": "Überspringen",
|
|
@@ -24213,7 +24582,7 @@ var init_de = __esm(() => {
|
|
|
24213
24582
|
"next.noTasks": "Keine Aufgaben in Zu Tun. Fügen Sie sie in den Posteingang ein und verarbeiten Sie diese zuerst.",
|
|
24214
24583
|
"next.noContext": "Keine Nächsten Aktionen mit",
|
|
24215
24584
|
"next.warningCount": "Elemente in Nächste Aktionen",
|
|
24216
|
-
"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.",
|
|
24217
24586
|
"contexts.title": "Kontexte",
|
|
24218
24587
|
"contexts.filter": "Aufgaben nach Kontexten filtern",
|
|
24219
24588
|
"filters.label": "Filter",
|
|
@@ -24243,7 +24612,7 @@ var init_de = __esm(() => {
|
|
|
24243
24612
|
"filters.noMatch": " Diesem Filter entsprechen keine Aufgaben.",
|
|
24244
24613
|
"contexts.all": "Alle Kontexte",
|
|
24245
24614
|
"contexts.none": "Keine Kontexte",
|
|
24246
|
-
"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.",
|
|
24247
24616
|
"contexts.noTasks": "Keine aktiven Aufgaben für diesen Kontext",
|
|
24248
24617
|
"board.title": "Tafelansicht",
|
|
24249
24618
|
"board.next": "Nächste Aktionen",
|
|
@@ -24251,11 +24620,11 @@ var init_de = __esm(() => {
|
|
|
24251
24620
|
"board.inProgress": "In Arbeit",
|
|
24252
24621
|
"board.done": "Erledigt",
|
|
24253
24622
|
"board.noTasks": "Keine Aufgaben",
|
|
24254
|
-
"board.hint": "Halten zum Verschieben •
|
|
24623
|
+
"board.hint": "Halten zum Verschieben • Zum Löschen nach links wischen",
|
|
24255
24624
|
"board.dragTask": "Aufgabe verschieben",
|
|
24256
24625
|
"board.delete": "Löschen",
|
|
24257
24626
|
"calendar.title": "Kalender",
|
|
24258
|
-
"calendar.addTask": "Neue Aufgabe
|
|
24627
|
+
"calendar.addTask": "Neue Aufgabe hinzufügen ...",
|
|
24259
24628
|
"calendar.schedulePlaceholder": "Aufgaben suchen zum Einplanen ...",
|
|
24260
24629
|
"calendar.scheduleResults": "Zeitplan",
|
|
24261
24630
|
"calendar.scheduleAction": "Zeitplan",
|
|
@@ -24313,10 +24682,10 @@ var init_de = __esm(() => {
|
|
|
24313
24682
|
"project.notes": "Projektnotizen",
|
|
24314
24683
|
"projects.notesPlaceholder": "Kontexte, Pläne oder Referenzen zu diesem Projekt hinzufügen ...",
|
|
24315
24684
|
"projects.sectionNotes": "Abschnitts-Notizen",
|
|
24316
|
-
"projects.sectionNotesPlaceholder": "Notizen zu diesem Abschnitt
|
|
24317
|
-
"projects.reviewAt": "
|
|
24685
|
+
"projects.sectionNotesPlaceholder": "Notizen zu diesem Abschnitt hinzufügen ...",
|
|
24686
|
+
"projects.reviewAt": "Revisionsdatum",
|
|
24318
24687
|
"projects.areaLabel": "Bereich",
|
|
24319
|
-
"projects.areaPlaceholder": "Z.B. Arbeit",
|
|
24688
|
+
"projects.areaPlaceholder": "Z. B. Arbeit",
|
|
24320
24689
|
"projects.sectionsLabel": "Abschnitte",
|
|
24321
24690
|
"projects.addSection": "Abschnitt hinzufügen",
|
|
24322
24691
|
"projects.sectionPlaceholder": "Titel für den Abschnitt",
|
|
@@ -24369,7 +24738,7 @@ var init_de = __esm(() => {
|
|
|
24369
24738
|
"dailyReview.todayStep": "Heute & Kalender",
|
|
24370
24739
|
"dailyReview.todayDesc": "Überprüfen, was heute ansteht und welche Verpflichtungen im Kalender stehen.",
|
|
24371
24740
|
"dailyReview.focusStep": "Heutiger Fokus",
|
|
24372
|
-
"dailyReview.focusDesc": "
|
|
24741
|
+
"dailyReview.focusDesc": "Optional: Aufgaben markieren, die heute im Fokus sichtbar bleiben sollen.",
|
|
24373
24742
|
"dailyReview.inboxStep": "Posteingang verarbeiten",
|
|
24374
24743
|
"dailyReview.inboxDesc": "Neue Eingaben klären in der Rechte-Liste.",
|
|
24375
24744
|
"dailyReview.waitingStep": "Warten auf",
|
|
@@ -24392,9 +24761,9 @@ var init_de = __esm(() => {
|
|
|
24392
24761
|
"review.calendarStep": "Kalender-Revision",
|
|
24393
24762
|
"review.calendarStepDesc": "Revidieren Sie Ihren Kalender für die nächste 7 Tage.",
|
|
24394
24763
|
"review.past14": "Letzte 14 Tage",
|
|
24395
|
-
"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?",
|
|
24396
24765
|
"review.upcoming14": "Nächste 7 Tage",
|
|
24397
|
-
"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.",
|
|
24398
24767
|
"review.waitingStep": "Warten auf",
|
|
24399
24768
|
"review.waitingStepDesc": "Verfolgen Sie die delegierten Aufgaben.",
|
|
24400
24769
|
"review.waitingHint": "Revidieren Sie diese Elemente. Haben Sie erhalten, auf was Sie warten? Müssen Sie eine Erinnerung absenden?",
|
|
@@ -24404,8 +24773,8 @@ var init_de = __esm(() => {
|
|
|
24404
24773
|
"review.staleStep": "Liegengebliebene Aufgaben",
|
|
24405
24774
|
"review.staleStepDesc": "Keine Aktivität in letzter Zeit. Aktualisieren, abschließen oder loslassen.",
|
|
24406
24775
|
"review.staleDaysInactive": "{{days}} Tage inaktiv",
|
|
24407
|
-
"review.advanceWeek": "In
|
|
24408
|
-
"review.advanceWeekDone": "Nächste Durchsicht in
|
|
24776
|
+
"review.advanceWeek": "In einer Woche prüfen",
|
|
24777
|
+
"review.advanceWeekDone": "Nächste Durchsicht in einer Woche",
|
|
24409
24778
|
"review.aiStep": "KI-Einblick",
|
|
24410
24779
|
"review.aiStepDesc": "Veraltete Elemente hervorheben und Bereinigungsvorschläge anzeigen.",
|
|
24411
24780
|
"review.aiTitle": "KI-Revision",
|
|
@@ -24413,14 +24782,14 @@ var init_de = __esm(() => {
|
|
|
24413
24782
|
"review.aiRunning": "Analysieren ...",
|
|
24414
24783
|
"review.aiEmpty": "Keine veralteten Elemente gefunden.",
|
|
24415
24784
|
"review.aiApply": "Ausgewählte anwenden",
|
|
24416
|
-
"review.aiAction.someday": "Nach
|
|
24785
|
+
"review.aiAction.someday": "Nach Irgendwann verschieben",
|
|
24417
24786
|
"review.aiAction.archive": "Archiv",
|
|
24418
24787
|
"review.aiAction.breakdown": "Benötigt eine Aufschlüsselung",
|
|
24419
24788
|
"review.aiAction.keep": "Behalten",
|
|
24420
24789
|
"review.notDueYet": "Noch nicht fällig",
|
|
24421
24790
|
"review.projectsStep": "Projekte revidieren",
|
|
24422
24791
|
"review.projectsStepDesc": "Sicherstellen, dass jedes aktive Projekt eine nächste Aktion enthält.",
|
|
24423
|
-
"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.",
|
|
24424
24793
|
"review.hasNextAction": "Enthält eine nächste Aktion",
|
|
24425
24794
|
"review.needsAction": "Benötigt eine nächste Aktion",
|
|
24426
24795
|
"review.noActiveTasks": "Keine aktiven Aufgaben",
|
|
@@ -24431,7 +24800,7 @@ var init_de = __esm(() => {
|
|
|
24431
24800
|
"review.allDone": "Alles erledigt!",
|
|
24432
24801
|
"review.allDoneDesc": "Sie sind für bereit für die kommende Woche.",
|
|
24433
24802
|
"review.complete": "Revision abgeschlossen!",
|
|
24434
|
-
"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.",
|
|
24435
24804
|
"review.summaryInboxEmpty": "Eingang ist leer",
|
|
24436
24805
|
"review.summaryInboxCount": "{{count}} Element(e) noch im Eingang",
|
|
24437
24806
|
"review.summaryProjectsOk": "Jedes aktive Projekt hat eine nächste Aktion",
|
|
@@ -24474,10 +24843,10 @@ var init_de = __esm(() => {
|
|
|
24474
24843
|
"process.nextStepDesc": "Sollen Sie es tun oder an jemanden delegieren?",
|
|
24475
24844
|
"process.doIt": "\uD83D\uDCCB Ich werde es selber erledigen",
|
|
24476
24845
|
"process.delegate": "Delegieren",
|
|
24477
|
-
"process.delegateTitle": "
|
|
24846
|
+
"process.delegateTitle": "Delegieren",
|
|
24478
24847
|
"process.delegateDesc": "Optional: Notieren Sie, wer beteiligt ist, und einen Termin für die Weiterverfolgung.",
|
|
24479
24848
|
"process.delegateWhoLabel": "Wer? (Optional)",
|
|
24480
|
-
"process.delegateWhoPlaceholder": "Z.B. Alex",
|
|
24849
|
+
"process.delegateWhoPlaceholder": "Z. B. Alex",
|
|
24481
24850
|
"process.delegateFollowUpLabel": "Weiterverfolgungs-Termin (Optional)",
|
|
24482
24851
|
"process.delegateSendRequest": "Anfrage senden ...",
|
|
24483
24852
|
"process.delegateMoveToWaiting": "Nach Warten verschieben",
|
|
@@ -24488,7 +24857,7 @@ var init_de = __esm(() => {
|
|
|
24488
24857
|
"process.ifNotActionable": "Wenn es nicht ausführbar ist:",
|
|
24489
24858
|
"process.waitingFor": "Auf wen oder was warten Sie?",
|
|
24490
24859
|
"process.waitingForDesc": "Fügen Sie eine Notiz hinzu, um sich zu erinnern, auf was Sie warten",
|
|
24491
|
-
"process.waitingPlaceholder": "Z.B. Auf Jonathan's Revision des Dokumentes warten ...",
|
|
24860
|
+
"process.waitingPlaceholder": "Z. B. Auf Jonathan's Revision des Dokumentes warten ...",
|
|
24492
24861
|
"process.next": "Nächste",
|
|
24493
24862
|
"process.noContext": "Kein Kontext",
|
|
24494
24863
|
"process.project": "Zu einem Projekt hinzufügen?",
|
|
@@ -24538,7 +24907,7 @@ var init_de = __esm(() => {
|
|
|
24538
24907
|
"settings.calendarSystemJalali": "Jalali (Sonnen-Hidschra)",
|
|
24539
24908
|
"settings.keybindingsDesc": "Tastaturbelegung-Stil für den Desktop auswählen.",
|
|
24540
24909
|
"settings.closeBehaviorDesc": "Wählen Sie, was beim Schließen des Fensters passieren soll.",
|
|
24541
|
-
"settings.closeBehaviorAsk": "
|
|
24910
|
+
"settings.closeBehaviorAsk": "Jedes Mal fragen",
|
|
24542
24911
|
"settings.closeBehaviorTray": "Im Taskbereich weiterlaufen lassen",
|
|
24543
24912
|
"settings.closeBehaviorQuit": "Die App schließen",
|
|
24544
24913
|
"settings.closeBehaviorPromptTitle": "Mindwtr schließen?",
|
|
@@ -24677,14 +25046,14 @@ var init_de = __esm(() => {
|
|
|
24677
25046
|
"settings.aiApiKeyPlaceholder": "API-Schlüssel einfügen",
|
|
24678
25047
|
"settings.speechTitle": "Sprache zu Text",
|
|
24679
25048
|
"settings.speechDesc": "Sprachaufnahmen transkribieren und sie in Aufgabenfelder einteilen.",
|
|
24680
|
-
"settings.speechEnable": "Sprache zu Text
|
|
25049
|
+
"settings.speechEnable": "Sprache zu Text aktivieren",
|
|
24681
25050
|
"settings.speechProvider": "Spracherkennungs-Provider",
|
|
24682
25051
|
"settings.speechProviderOffline": "Auf dem Gerät (Whisper)",
|
|
24683
25052
|
"settings.speechModel": "Sprachmodell",
|
|
24684
25053
|
"settings.speechBaseUrl": "Transkriptionsserver-URL",
|
|
24685
25054
|
"settings.speechBaseUrlHint": "Für offizielles OpenAI leer lassen. Für einen selbst gehosteten OpenAI-kompatiblen Transkriptionsserver festlegen. API-Schlüssel optional.",
|
|
24686
25055
|
"settings.speechOfflineModel": "Offline Modell",
|
|
24687
|
-
"settings.speechOfflineModelDesc": "Einmal
|
|
25056
|
+
"settings.speechOfflineModelDesc": "Einmal herunterladen, um dann völlig offline zu transkribieren.",
|
|
24688
25057
|
"settings.speechOfflineReady": "Modell heruntergeladen",
|
|
24689
25058
|
"settings.speechOfflineNotDownloaded": "Modell nicht heruntergeladen",
|
|
24690
25059
|
"settings.speechOfflineDownload": "Herunterladen",
|
|
@@ -24694,13 +25063,13 @@ var init_de = __esm(() => {
|
|
|
24694
25063
|
"settings.speechOfflineDeleteError": "Offline-Modell löschen ist fehlgeschlagen",
|
|
24695
25064
|
"settings.speechOfflineDeleteErrorBody": "Bitte nochmals versuchen.",
|
|
24696
25065
|
"settings.speechLanguage": "Audio-Sprache",
|
|
24697
|
-
"settings.speechLanguageHint": "Einen
|
|
25066
|
+
"settings.speechLanguageHint": "Einen Sprachnamen oder Code angeben, oder frei lassen zur automatischen Bestimmung.",
|
|
24698
25067
|
"settings.speechLanguageAuto": "Automatisch (Sprache bestimmen)",
|
|
24699
25068
|
"settings.speechMode": "Verarbeitungs-Modus",
|
|
24700
|
-
"settings.speechModeHint": "Smart parse extrahiert automatisch Felder und Daten; Nur
|
|
24701
|
-
"settings.speechModeTranscript": "Nur
|
|
25069
|
+
"settings.speechModeHint": "'Smart parse' extrahiert automatisch Felder und Daten; 'Nur Transkribieren' transkribiert lediglich.",
|
|
25070
|
+
"settings.speechModeTranscript": "Nur Transkribieren",
|
|
24702
25071
|
"settings.speechFieldStrategy": "Felder bestimmen",
|
|
24703
|
-
"settings.speechFieldStrategyHint": "Auswählen, wo die
|
|
25072
|
+
"settings.speechFieldStrategyHint": "Auswählen, wo die Transkription standardmäßig gespeichert werden soll.",
|
|
24704
25073
|
"settings.speechFieldTitle": "Titel",
|
|
24705
25074
|
"settings.speechFieldDescription": "Beschreibung",
|
|
24706
25075
|
"settings.aiReasoning": "Begründungsaufwand",
|
|
@@ -24861,8 +25230,8 @@ var init_de = __esm(() => {
|
|
|
24861
25230
|
"sort.label": "Sortieren",
|
|
24862
25231
|
"sort.default": "Standard",
|
|
24863
25232
|
"sort.due": "Fälligkeitsdatum",
|
|
24864
|
-
"sort.start": "
|
|
24865
|
-
"sort.review": "
|
|
25233
|
+
"sort.start": "Beginndatum",
|
|
25234
|
+
"sort.review": "Revisionsdatum",
|
|
24866
25235
|
"sort.title": "Titel",
|
|
24867
25236
|
"sort.timeEstimate": "Zeitabschätzung",
|
|
24868
25237
|
"sort.created": "Älteste",
|
|
@@ -24885,7 +25254,7 @@ var init_de = __esm(() => {
|
|
|
24885
25254
|
"agenda.focusHint": "Tippen Sie auf den Stern irgendeiner untenstehenden Aufgabe, um sie zum heutigen Fokus hinzuzufügen (max. 3).",
|
|
24886
25255
|
"agenda.addToFocus": "Zum heutigen Fokus hinzufügen",
|
|
24887
25256
|
"agenda.removeFromFocus": "Aus dem Fokus entfernen",
|
|
24888
|
-
"agenda.maxFocusItems": "Max.
|
|
25257
|
+
"agenda.maxFocusItems": "Max. {{count}} Fokus-Element(e)",
|
|
24889
25258
|
"agenda.inProgress": "In Arbeit",
|
|
24890
25259
|
"agenda.overdue": "Überfällig",
|
|
24891
25260
|
"agenda.dueToday": "Heute fällig",
|
|
@@ -24915,7 +25284,7 @@ var init_de = __esm(() => {
|
|
|
24915
25284
|
"waiting.moveToNext": "Nach Nächste verschieben",
|
|
24916
25285
|
"waiting.markDone": "Als Erledigt markieren",
|
|
24917
25286
|
"waiting.empty": "Es gibt nichts, worauf Sie warten müssten",
|
|
24918
|
-
"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",
|
|
24919
25288
|
"someday.title": "Irgendwann/Vielleicht",
|
|
24920
25289
|
"someday.subtitle": "Ideen und Ziele, die Sie in Zukunft vielleicht verfolgen möchten",
|
|
24921
25290
|
"someday.ideas": "Ideen",
|
|
@@ -24923,7 +25292,7 @@ var init_de = __esm(() => {
|
|
|
24923
25292
|
"someday.moveToNext": "Zu Nächste verschieben",
|
|
24924
25293
|
"someday.archive": "Archiv",
|
|
24925
25294
|
"someday.empty": "Keine Irgendwann/Vielleicht-Elemente",
|
|
24926
|
-
"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",
|
|
24927
25296
|
"search.title": "Suchen",
|
|
24928
25297
|
"search.placeholder": "Aufgaben and Projekte suchen ...",
|
|
24929
25298
|
"search.scopeHint": "Aufgaben, Projekte, Personen",
|
|
@@ -24936,10 +25305,10 @@ var init_de = __esm(() => {
|
|
|
24936
25305
|
"search.showingFirst": "Zeigt {shown} von {total} Ergebnissen",
|
|
24937
25306
|
"search.saveSearch": "Diese Suchabfrage speichern",
|
|
24938
25307
|
"search.saveSearchPrompt": "Diese Suchabfrage benennen",
|
|
24939
|
-
"search.savedSearches": "
|
|
25308
|
+
"search.savedSearches": "Suchabfrage gespeichert",
|
|
24940
25309
|
"search.noSavedSearches": "Noch keine gespeicherte Suchabfragen.",
|
|
24941
25310
|
"search.deleteConfirm": "Diese gespeicherte Suchabfrage löschen?",
|
|
24942
|
-
"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.",
|
|
24943
25312
|
"search.hiddenCompletedMatches": "{{count}} weitere in Erledigt und Archiviert",
|
|
24944
25313
|
"search.completedDate": "Abgeschlossen {{date}}",
|
|
24945
25314
|
"search.dueDate": "Fällig {{date}}",
|
|
@@ -25008,7 +25377,7 @@ var init_de = __esm(() => {
|
|
|
25008
25377
|
"settings.sync": "Synchronisieren",
|
|
25009
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.",
|
|
25010
25379
|
"settings.attachmentsCleanup": "Bereinigung von Anhängen",
|
|
25011
|
-
"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.",
|
|
25012
25381
|
"settings.attachmentsCleanupLastRun": "Letzte Bereinigung",
|
|
25013
25382
|
"settings.attachmentsCleanupNever": "Nie",
|
|
25014
25383
|
"settings.attachmentsCleanupRun": "Führen Sie die Bereinigung durch",
|
|
@@ -25037,7 +25406,7 @@ var init_de = __esm(() => {
|
|
|
25037
25406
|
"settings.cloudProviderDropbox": "Dropbox",
|
|
25038
25407
|
"settings.dropboxAppKey": "Dropbox-Konto",
|
|
25039
25408
|
"settings.dropboxAppKeyHint": "Der Dropbox-App-Schlüssel wird zum Zeitpunkt der Erstellung/Veröffentlichung eingefügt.",
|
|
25040
|
-
"settings.dropboxRedirectUri": "
|
|
25409
|
+
"settings.dropboxRedirectUri": "Redirect-URI",
|
|
25041
25410
|
"settings.dropboxConnected": "Verbunden",
|
|
25042
25411
|
"settings.dropboxNotConnected": "Nicht verbunden",
|
|
25043
25412
|
"settings.dropboxConnect": "Dropbox verbinden",
|
|
@@ -25090,7 +25459,7 @@ var init_de = __esm(() => {
|
|
|
25090
25459
|
"settings.downloadStarting": "Download wird geöffnet ...",
|
|
25091
25460
|
"settings.downloadStarted": "Der Download wurde in Ihrem Browser gestartet.",
|
|
25092
25461
|
"settings.downloadFailed": "Der Download-Link konnte nicht geöffnet werden.",
|
|
25093
|
-
"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.",
|
|
25094
25463
|
"settings.downloadRecommended": "Empfohlenes Paket",
|
|
25095
25464
|
"settings.downloadAURHint": "Arch erkannt: Aktualisierung über AUR",
|
|
25096
25465
|
"settings.changelog": "Änderungsprotokoll",
|
|
@@ -26844,6 +27213,9 @@ var init_ja = __esm(() => {
|
|
|
26844
27213
|
"nav.main": "メイン",
|
|
26845
27214
|
"nav.inbox": "インボックス",
|
|
26846
27215
|
"nav.board": "ボードビュー",
|
|
27216
|
+
"nav.timeline": "タイムライン",
|
|
27217
|
+
"timeline.empty": "予定されたタスクはまだありません",
|
|
27218
|
+
"timeline.emptyHint": "開始日または期限日のあるタスクがバーとして表示されます。",
|
|
26847
27219
|
"nav.projects": "プロジェクト",
|
|
26848
27220
|
"nav.contexts": "コンテキスト",
|
|
26849
27221
|
"nav.next": "次のアクション",
|
|
@@ -26930,6 +27302,7 @@ var init_ja = __esm(() => {
|
|
|
26930
27302
|
"keybindings.goReference": "資料へ移動",
|
|
26931
27303
|
"keybindings.goCalendar": "カレンダーへ移動",
|
|
26932
27304
|
"keybindings.goBoard": "ボードへ移動",
|
|
27305
|
+
"keybindings.goTimeline": "タイムラインへ移動",
|
|
26933
27306
|
"keybindings.goDone": "完了へ移動",
|
|
26934
27307
|
"keybindings.goArchived": "アーカイブへ移動",
|
|
26935
27308
|
"keybindings.switchArea": "エリア 1〜9 に切り替え",
|
|
@@ -27107,9 +27480,12 @@ var init_ja = __esm(() => {
|
|
|
27107
27480
|
"attachments.obsidianLinkPlaceholder": "obsidian://open?vault=Vault&file=Note",
|
|
27108
27481
|
"attachments.obsidianLinkInputHint": "obsidian:// のノートリンクを貼り付けるか、「タイトル | obsidian://…」の形式で入力してください。",
|
|
27109
27482
|
"attachments.fileNotSupported": "ファイルの添付はデスクトップ版でのみ利用できます。",
|
|
27483
|
+
"attachments.webUnavailable": "この添付ファイルはウェブ版では利用できません。",
|
|
27110
27484
|
"attachments.fileTooLarge": "ファイルが大きすぎてアップロードできません。",
|
|
27111
27485
|
"attachments.fileNotReadable": "このファイルを読み取れなかったため添付できませんでした。別のフォルダに移してからもう一度お試しください。",
|
|
27112
27486
|
"attachments.linkToFile": "ファイルへのリンク…",
|
|
27487
|
+
"attachments.linkedFileElsewhere": "このリンクは別のデバイス上のファイルを指しています: {{path}}。そのデバイスで開くか、リンクではなくファイルを添付してください。",
|
|
27488
|
+
"attachments.openLinkFailed": "このリンクを開けませんでした。",
|
|
27113
27489
|
"attachments.invalidFileType": "対応していないファイル形式です。",
|
|
27114
27490
|
"attachments.invalidLink": "有効な URL を入力してください。",
|
|
27115
27491
|
"attachments.photoUnavailableTitle": "写真の選択が利用できません",
|
|
@@ -27477,7 +27853,7 @@ var init_ja = __esm(() => {
|
|
|
27477
27853
|
"projects.sectionPlaceholder": "セクション名",
|
|
27478
27854
|
"projects.noSection": "セクションなし",
|
|
27479
27855
|
"projects.sectionEmpty": "タスクなし",
|
|
27480
|
-
"projects.deleteSectionConfirm": "
|
|
27856
|
+
"projects.deleteSectionConfirm": "このセクションを削除しますか?中のタスクは削除されず、「セクションなし」に移動します。",
|
|
27481
27857
|
"projects.areaFilter": "エリアで絞り込む",
|
|
27482
27858
|
"projects.allAreas": "すべてのエリア",
|
|
27483
27859
|
"projects.noArea": "エリアなし",
|
|
@@ -27510,6 +27886,8 @@ var init_ja = __esm(() => {
|
|
|
27510
27886
|
"projects.complete": "完了にする",
|
|
27511
27887
|
"projects.archive": "アーカイブ",
|
|
27512
27888
|
"projects.reactivate": "再開する",
|
|
27889
|
+
"projects.archivedTaskInspectionHint": "ダブルタップでこのタスクを確認できます。編集するにはプロジェクトを再開してください。",
|
|
27890
|
+
"projects.archivedReadOnlyHint": "アーカイブ済みのプロジェクトです。このタスクを編集するには再開してください。",
|
|
27513
27891
|
"projects.actionsLabel": "操作",
|
|
27514
27892
|
"projects.archiveHelp": "アーカイブすると、プロジェクトと残っているタスクがまとめて完了になります。あとからいつでも再開できます。",
|
|
27515
27893
|
"projects.completeConfirm": "このプロジェクトを完了にして、含まれるタスクもすべて終わらせますか?",
|
|
@@ -27815,6 +28193,7 @@ var init_ja = __esm(() => {
|
|
|
27815
28193
|
"settings.material3ThemeDesc": "Android で Material 3 の配色を使います",
|
|
27816
28194
|
"settings.selectLang": "使用する言語を選んでください",
|
|
27817
28195
|
"settings.languagePartlyTranslated": "一部のみ翻訳",
|
|
28196
|
+
"settings.videoTutorials": "動画チュートリアル",
|
|
27818
28197
|
"settings.privacy": "プライバシー",
|
|
27819
28198
|
"settings.mobile.appLock": "アプリロック",
|
|
27820
28199
|
"settings.mobile.appLockDesc": "Mindwtr を開くとき、またはアプリに戻るときに端末のロック解除を求めます。保護されるのは画面の表示だけで、端末内のデータベースそのものは保護の対象ではありません。",
|
|
@@ -27902,6 +28281,8 @@ var init_ja = __esm(() => {
|
|
|
27902
28281
|
"settings.syncEncryptionUnlock": "パスフレーズを入力",
|
|
27903
28282
|
"settings.syncEncryptionDecline": "後で",
|
|
27904
28283
|
"settings.syncEncryptionPausedDesc": "パスフレーズを入力するまで、この端末の自動同期は停止したままになります。",
|
|
28284
|
+
"settings.syncEncryptionLockedRecheckHint": "この同期先に暗号化されたファイルがもうない場合は、「今すぐ同期」をタップしてください。この端末が同期先を再確認して続行します。",
|
|
28285
|
+
"settings.syncEncryptionNoEncryptedRemote": "この同期先には暗号化されたファイルがなくなったため、この端末の暗号化はオフになりました。この場所を暗号化するには、もう一度オンにしてください。",
|
|
27905
28286
|
"settings.syncEncryptionRemoteEncrypted": "この同期先は暗号化されています。同期を続けるには、同期パスフレーズを入力してください。",
|
|
27906
28287
|
"settings.syncEncryptionRemotePlaintext": "同期を停止しました: この同期先はもう暗号化されていません。このデバイスで同期の暗号化をオフにするか、同期先で暗号化をもう一度オンにしてください。",
|
|
27907
28288
|
"settings.syncEncryptionRemotePlaintextDesc": "別のデバイスがこの同期先の暗号化をオフにしました。この端末側では何も変更も解除もされていません。平文のまま同期を続けるにはこのデバイスで同期の暗号化をオフにし、そうでなければ同期先で暗号化をもう一度オンにしてください。",
|
|
@@ -28147,6 +28528,10 @@ var init_ja = __esm(() => {
|
|
|
28147
28528
|
"settings.featureTimeEstimatesDesc": "時間を確保して計画を立てるための、簡単な所要時間の見積もりを追加します。",
|
|
28148
28529
|
"settings.featurePomodoro": "ポモドーロタイマー",
|
|
28149
28530
|
"settings.featurePomodoroDesc": "フォーカス画面にポモドーロのパネルを表示します。",
|
|
28531
|
+
"settings.featureTimeline": "タイムラインビュー",
|
|
28532
|
+
"settings.featureTimelineDesc": "日付のあるタスクの読み取り専用タイムラインをサイドバーに表示します。",
|
|
28533
|
+
"settings.sidebarViews": "サイドバーの表示項目",
|
|
28534
|
+
"settings.sidebarViewsDesc": "サイドバーに表示するビューを選択します。非表示のビューも検索から開けます。",
|
|
28150
28535
|
"settings.pomodoroCustomPreset": "カスタムのプリセット",
|
|
28151
28536
|
"settings.pomodoroCustomPresetDesc": "集中・休憩の組み合わせを1つだけ追加できます。既定のプリセットと同じ値にした場合は、既定のものだけが表示されます。",
|
|
28152
28537
|
"settings.pomodoroFocusMinutes": "集中する時間(分)",
|
|
@@ -28233,6 +28618,7 @@ var init_ja = __esm(() => {
|
|
|
28233
28618
|
"tags.title": "タグ",
|
|
28234
28619
|
"areas.edit": "エリアを編集",
|
|
28235
28620
|
"common.edit": "編集",
|
|
28621
|
+
"common.view": "表示",
|
|
28236
28622
|
"common.add": "追加",
|
|
28237
28623
|
"common.open": "開く",
|
|
28238
28624
|
"common.ok": "OK",
|
|
@@ -28300,6 +28686,7 @@ var init_ja = __esm(() => {
|
|
|
28300
28686
|
"bulk.keepStatus": "ステータスは変えない",
|
|
28301
28687
|
"bulk.keepProject": "プロジェクトは変えない",
|
|
28302
28688
|
"bulk.keepArea": "エリアは変えない",
|
|
28689
|
+
"bulk.keepSection": "セクションは変えない",
|
|
28303
28690
|
"bulk.waitingPersonRequired": "待っている相手を選んでください。",
|
|
28304
28691
|
"bulk.deleting": "選択したタスクを削除しています…",
|
|
28305
28692
|
"sort.label": "並び順",
|
|
@@ -28845,6 +29232,12 @@ App Store に更新があります。アプリのページを開きますか?`
|
|
|
28845
29232
|
"settings.syncMobile.accountStatus": "アカウントの状態",
|
|
28846
29233
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "Dropbox の OAuth 設定に、このリダイレクト URI をそのまま登録してください。",
|
|
28847
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": "オフ",
|
|
28848
29241
|
"settings.syncMobile.clearPendingAttachmentDeletes": "保留中の添付ファイル削除を取り消しますか?",
|
|
28849
29242
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "この端末では CloudKit が制限されています。スクリーンタイム、MDM、iCloud の制限を確認してから、もう一度お試しください。",
|
|
28850
29243
|
"settings.syncMobile.connectedToDropbox": "Dropbox に接続しました。",
|
|
@@ -28932,6 +29325,9 @@ App Store に更新があります。アプリのページを開きますか?`
|
|
|
28932
29325
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV のエンドポイントに接続できました。",
|
|
28933
29326
|
"settings.persistentCaptureLabel": "通知バーからクイックキャプチャ",
|
|
28934
29327
|
"settings.persistentCaptureDesc": "常駐する通知を表示して、ロック画面を含めどこからでも書き留められるようにします。",
|
|
29328
|
+
"settings.exactAlarmsLabel": "リマインダーが遅れる可能性があります",
|
|
29329
|
+
"settings.exactAlarmsDesc": "Android が Mindwtr に正確なアラームを許可していないため、リマインダーが最大 1 分遅れることがあります。",
|
|
29330
|
+
"settings.exactAlarmsAllow": "許可",
|
|
28935
29331
|
"settings.appSearchLabel": "システム検索に表示する",
|
|
28936
29332
|
"settings.appSearchDesc": "Android のシステム検索から、進行中のタスク・プロジェクト・エリアをタイトルで探せるようにします。データが端末の外に出ることはありません。",
|
|
28937
29333
|
"captureNotification.title": "クイックキャプチャ",
|
|
@@ -29266,6 +29662,8 @@ App Store に更新があります。アプリのページを開きますか?`
|
|
|
29266
29662
|
"settings.gettingStartedContentContinueDesc": "ここでの作業が終わったあとでも、ガイド付きの「はじめかた」プロジェクトとサンプルのインボックス項目を追加できます。",
|
|
29267
29663
|
"settings.syncSetupGuideTitle": "データと同期の設定ガイド",
|
|
29268
29664
|
"settings.syncSetupGuideDesc": "Dropbox・iCloud・WebDAV・フォルダ同期・復旧についての手引き。",
|
|
29665
|
+
"settings.syncEncryptionGuideTitle": "同期の暗号化ガイド",
|
|
29666
|
+
"settings.syncEncryptionGuideDesc": "何を保護するか、対応するサーバー、パスフレーズの仕組み。",
|
|
29269
29667
|
"settings.importSetupGuideTitle": "読み込みの設定ガイド",
|
|
29270
29668
|
"settings.importSetupGuideDesc": "Todoist・TickTick・DGT GTD・OmniFocus・Mindwtr CSV・Apple リマインダー・バックアップからの読み込み方法。",
|
|
29271
29669
|
"settings.backupDiagnostics.newerVersion": "このバックアップは、より新しいバージョンの Mindwtr({{version}})で作成されています。",
|
|
@@ -29288,7 +29686,7 @@ App Store に更新があります。アプリのページを開きますか?`
|
|
|
29288
29686
|
"settings.importDiagnostics.unmappedDate": "{{count}}件の日付は対応づけられなかったため、取り込みませんでした。",
|
|
29289
29687
|
"settings.importDiagnostics.unmappedStatus": "{{count}}件のステータスは対応づけられなかったため、安全な既定値を使いました。",
|
|
29290
29688
|
"settings.importDiagnostics.unsupportedRecurrence": "対応していない繰り返しルール{{count}}件は、メモとして残しました。",
|
|
29291
|
-
"settings.syncRemoteBusy": "
|
|
29689
|
+
"settings.syncRemoteBusy": "別の Mindwtr デバイスがこの同期先を一時的に確保しています。同期は自動的に再試行されます。",
|
|
29292
29690
|
"settings.syncRemoteCleanupDeferred": "同期処理は完了しました。Mindwtr は一時的な同期ロックを削除できませんでしたが、ロックは自動的に期限切れになります。再試行は不要です。",
|
|
29293
29691
|
"settings.syncAttachmentWriteDeferred": "一部の添付ファイルの変更を完了できませんでした。不足しているローカルファイルを復元するか、該当する添付ファイルを削除してから、もう一度同期してください。",
|
|
29294
29692
|
"settings.syncFileAttachmentTooLarge": "Mindwtr はローカルの添付ファイルを保持しました。File Sync で同期できる添付ファイルは 100 MB 未満です。小さいファイルに置き換えるか添付ファイルを削除してから、もう一度同期してください。",
|
|
@@ -37046,6 +37444,8 @@ var init_ko = __esm(() => {
|
|
|
37046
37444
|
"attachments.fileTooLarge": "파일이 너무 커서 업로드할 수 없습니다.",
|
|
37047
37445
|
"attachments.fileNotReadable": "이 파일을 읽을 수 없어 첨부되지 않았습니다. 파일을 다른 폴더로 옮긴 뒤 다시 시도하세요.",
|
|
37048
37446
|
"attachments.linkToFile": "파일에 연결…",
|
|
37447
|
+
"attachments.linkedFileElsewhere": "이 링크는 다른 기기에 있는 파일을 가리킵니다: {{path}}. 해당 기기에서 열거나, 링크 대신 파일 자체를 첨부하세요.",
|
|
37448
|
+
"attachments.openLinkFailed": "이 링크를 열 수 없습니다.",
|
|
37049
37449
|
"attachments.invalidFileType": "지원되지 않는 파일 형식입니다.",
|
|
37050
37450
|
"attachments.invalidLink": "유효한 URL을 입력하세요.",
|
|
37051
37451
|
"attachments.photoUnavailableTitle": "사진 선택 도구를 사용할 수 없습니다.",
|
|
@@ -38669,6 +39069,9 @@ App Store에 업데이트가 있습니다. 지금 앱 목록을 여시겠습니
|
|
|
38669
39069
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV 엔드포인트에 접근할 수 있습니다.",
|
|
38670
39070
|
"settings.persistentCaptureLabel": "알림 표시줄에서 빠른 수집",
|
|
38671
39071
|
"settings.persistentCaptureDesc": "잠금 화면을 포함해 어디서나 수집할 수 있는 고정 알림을 유지합니다.",
|
|
39072
|
+
"settings.exactAlarmsLabel": "알림이 늦게 도착할 수 있습니다",
|
|
39073
|
+
"settings.exactAlarmsDesc": "Android가 Mindwtr에 정확한 알람을 허용하지 않아 알림이 최대 1분까지 늦게 울릴 수 있습니다.",
|
|
39074
|
+
"settings.exactAlarmsAllow": "허용",
|
|
38672
39075
|
"settings.appSearchLabel": "시스템 검색에 노출",
|
|
38673
39076
|
"settings.appSearchDesc": "Android 시스템 검색이 제목으로 활성 작업, 프로젝트, 영역을 찾을 수 있게 합니다. 어떤 데이터도 이 기기를 벗어나지 않습니다.",
|
|
38674
39077
|
"captureNotification.title": "빠른 수집",
|
|
@@ -42864,6 +43267,9 @@ var init_fa = __esm(() => {
|
|
|
42864
43267
|
"nav.main": "اصلی",
|
|
42865
43268
|
"nav.inbox": "صندوق ورودی",
|
|
42866
43269
|
"nav.board": "نمای تابلو",
|
|
43270
|
+
"nav.timeline": "خط زمانی",
|
|
43271
|
+
"timeline.empty": "هنوز چیزی زمانبندی نشده است",
|
|
43272
|
+
"timeline.emptyHint": "کارهایی که تاریخ شروع یا تاریخ سررسید دارند اینجا به صورت نوار نمایش داده میشوند.",
|
|
42867
43273
|
"nav.projects": "پروژهها",
|
|
42868
43274
|
"nav.contexts": "زمینهها",
|
|
42869
43275
|
"nav.next": "اقدامات بعدی",
|
|
@@ -42950,6 +43356,7 @@ var init_fa = __esm(() => {
|
|
|
42950
43356
|
"keybindings.goReference": "رفتن به مرجع",
|
|
42951
43357
|
"keybindings.goCalendar": "رفتن به تقویم",
|
|
42952
43358
|
"keybindings.goBoard": "رفتن به تابلو",
|
|
43359
|
+
"keybindings.goTimeline": "رفتن به خط زمانی",
|
|
42953
43360
|
"keybindings.goDone": "رفتن به انجامشده",
|
|
42954
43361
|
"keybindings.goArchived": "رفتن به بایگانیشده",
|
|
42955
43362
|
"keybindings.switchArea": "تعویض حوزه ۱ تا ۹",
|
|
@@ -43128,9 +43535,12 @@ var init_fa = __esm(() => {
|
|
|
43128
43535
|
"attachments.obsidianLinkPlaceholder": "obsidian://open?vault=Vault&file=Note",
|
|
43129
43536
|
"attachments.obsidianLinkInputHint": "یک پیوند obsidian:// را بچسبانید یا از «عنوان | obsidian://...» استفاده کنید.",
|
|
43130
43537
|
"attachments.fileNotSupported": "پیوست فایل فقط در برنامه دسکتاپ پشتیبانی میشود.",
|
|
43538
|
+
"attachments.webUnavailable": "این پیوست در نسخه وب در دسترس نیست.",
|
|
43131
43539
|
"attachments.fileTooLarge": "حجم فایل برای بارگذاری زیاد است.",
|
|
43132
43540
|
"attachments.fileNotReadable": "این فایل خوانده نشد، بنابراین پیوست نگردید. آن را به پوشه دیگری منتقل کرده و دوباره امتحان کنید.",
|
|
43133
43541
|
"attachments.linkToFile": "پیوند به فایل…",
|
|
43542
|
+
"attachments.linkedFileElsewhere": "این پیوند به فایلی روی دستگاه دیگری اشاره میکند: {{path}}. آن را همانجا باز کنید یا بهجای پیوند، خود فایل را پیوست کنید.",
|
|
43543
|
+
"attachments.openLinkFailed": "باز کردن این پیوند ممکن نبود.",
|
|
43134
43544
|
"attachments.invalidFileType": "نوع فایل پشتیبانی نمیشود.",
|
|
43135
43545
|
"attachments.invalidLink": "لطفاً یک آدرس معتبر وارد کنید.",
|
|
43136
43546
|
"attachments.photoUnavailableTitle": "انتخابگر عکس در دسترس نیست",
|
|
@@ -43497,7 +43907,7 @@ var init_fa = __esm(() => {
|
|
|
43497
43907
|
"projects.sectionPlaceholder": "عنوان بخش",
|
|
43498
43908
|
"projects.noSection": "بدون بخش",
|
|
43499
43909
|
"projects.sectionEmpty": "بدون وظیفه",
|
|
43500
|
-
"projects.deleteSectionConfirm": "
|
|
43910
|
+
"projects.deleteSectionConfirm": "این بخش حذف شود؟ کارهای داخل آن حذف نمیشوند و به «بدون بخش» منتقل میشوند.",
|
|
43501
43911
|
"projects.areaFilter": "فیلتر حوزه",
|
|
43502
43912
|
"projects.allAreas": "همه حوزهها",
|
|
43503
43913
|
"projects.noArea": "بدون حوزه",
|
|
@@ -43530,6 +43940,8 @@ var init_fa = __esm(() => {
|
|
|
43530
43940
|
"projects.complete": "تکمیل",
|
|
43531
43941
|
"projects.archive": "بایگانی",
|
|
43532
43942
|
"projects.reactivate": "فعالسازی مجدد",
|
|
43943
|
+
"projects.archivedTaskInspectionHint": "برای بررسی این کار دو بار ضربه بزنید. برای ویرایش، پروژه را دوباره فعال کنید.",
|
|
43944
|
+
"projects.archivedReadOnlyHint": "پروژه بایگانی شده است. برای ویرایش این کار، آن را دوباره فعال کنید.",
|
|
43533
43945
|
"projects.actionsLabel": "اقدامات",
|
|
43534
43946
|
"projects.archiveHelp": "بایگانی یک پروژه، آن و کارهای باقیماندهاش را تکمیل میکند — هر زمان میتوانید دوباره فعالش کنید.",
|
|
43535
43947
|
"projects.completeConfirm": "این پروژه تکمیلشده علامتگذاری و همه کارهایش پایان یابند؟",
|
|
@@ -43835,6 +44247,7 @@ var init_fa = __esm(() => {
|
|
|
43835
44247
|
"settings.material3ThemeDesc": "استفاده از رنگهای متریال ۳ در اندروید",
|
|
43836
44248
|
"settings.selectLang": "زبان دلخواه خود را انتخاب کنید",
|
|
43837
44249
|
"settings.languagePartlyTranslated": "ترجمهٔ ناقص",
|
|
44250
|
+
"settings.videoTutorials": "آموزشهای ویدیویی",
|
|
43838
44251
|
"settings.privacy": "حریم خصوصی",
|
|
43839
44252
|
"settings.mobile.appLock": "قفل برنامه",
|
|
43840
44253
|
"settings.mobile.appLockDesc": "هنگام باز کردن Mindwtr یا بازگشت به برنامه، قفل دستگاه را الزامی کنید. این فقط نمای برنامه را محافظت میکند، نه پایگاهداده روی دستگاه.",
|
|
@@ -43922,6 +44335,8 @@ var init_fa = __esm(() => {
|
|
|
43922
44335
|
"settings.syncEncryptionUnlock": "وارد کردن عبارت عبور",
|
|
43923
44336
|
"settings.syncEncryptionDecline": "فعلاً نه",
|
|
43924
44337
|
"settings.syncEncryptionPausedDesc": "تا زمانی که عبارت عبور را وارد نکنید، همگامسازی خودکار روی این دستگاه متوقف میماند.",
|
|
44338
|
+
"settings.syncEncryptionLockedRecheckHint": "اگر این مکان همگامسازی دیگر فایل رمزگذاریشده ندارد، «همگامسازی اکنون» را بزنید؛ این دستگاه دوباره آن را بررسی میکند و ادامه میدهد.",
|
|
44339
|
+
"settings.syncEncryptionNoEncryptedRemote": "دیگر هیچ فایل رمزگذاریشدهای در این مکان همگامسازی وجود ندارد، بنابراین رمزگذاری روی این دستگاه اکنون خاموش است. برای رمزگذاری این مکان دوباره آن را روشن کنید.",
|
|
43925
44340
|
"settings.syncEncryptionRemoteEncrypted": "این محل همگامسازی رمزگذاری شده است. برای ادامه همگامسازی، عبارت عبور آن را وارد کنید.",
|
|
43926
44341
|
"settings.syncEncryptionRemotePlaintext": "همگامسازی متوقف شد: این محل همگامسازی دیگر رمزگذاریشده نیست. رمزگذاری همگامسازی را در این دستگاه خاموش کنید یا دوباره در محل همگامسازی روشن کنید.",
|
|
43927
44342
|
"settings.syncEncryptionRemotePlaintextDesc": "دستگاه دیگری رمزگذاری را در این محل همگامسازی خاموش کرده است. هیچ چیزی در اینجا تغییر نکرده و از رمزگذاری خارج نشده است. برای ادامهٔ همگامسازی به شکل ساده، رمزگذاری همگامسازی را در این دستگاه خاموش کنید، یا رمزگذاری را دوباره در محل همگامسازی روشن کنید.",
|
|
@@ -44167,6 +44582,10 @@ var init_fa = __esm(() => {
|
|
|
44167
44582
|
"settings.featureTimeEstimatesDesc": "افزودن برآورد سریع مدت زمان برای بلوکبندی زمانی.",
|
|
44168
44583
|
"settings.featurePomodoro": "تایمر پومودورو",
|
|
44169
44584
|
"settings.featurePomodoroDesc": "فعالسازی پنل اختیاری پومودورو در نمای تمرکز.",
|
|
44585
|
+
"settings.featureTimeline": "نمای خط زمانی",
|
|
44586
|
+
"settings.featureTimelineDesc": "نمایش خط زمانی فقطخواندنی کارهای تاریخدار در نوار کناری.",
|
|
44587
|
+
"settings.sidebarViews": "نماهای نوار کناری",
|
|
44588
|
+
"settings.sidebarViewsDesc": "انتخاب کنید کدام نماها در نوار کناری نمایش داده شوند. نماهای پنهان از طریق جستجو در دسترس میمانند.",
|
|
44170
44589
|
"settings.pomodoroCustomPreset": "پیشتنظیم سفارشی",
|
|
44171
44590
|
"settings.pomodoroCustomPresetDesc": "یک پیشتنظیم اضافی تمرکز/استراحت اضافه کنید. تطبیق با یک پیشتنظیم داخلی فقط تراشههای داخلی را نگه میدارد.",
|
|
44172
44591
|
"settings.pomodoroFocusMinutes": "دقایق تمرکز",
|
|
@@ -44253,6 +44672,7 @@ var init_fa = __esm(() => {
|
|
|
44253
44672
|
"tags.title": "برچسبها",
|
|
44254
44673
|
"areas.edit": "ویرایش حوزه",
|
|
44255
44674
|
"common.edit": "ویرایش",
|
|
44675
|
+
"common.view": "مشاهده",
|
|
44256
44676
|
"common.add": "افزودن",
|
|
44257
44677
|
"common.open": "باز کردن",
|
|
44258
44678
|
"common.ok": "تأیید",
|
|
@@ -44320,6 +44740,7 @@ var init_fa = __esm(() => {
|
|
|
44320
44740
|
"bulk.keepStatus": "نگهداشتن وضعیت",
|
|
44321
44741
|
"bulk.keepProject": "نگهداشتن پروژه",
|
|
44322
44742
|
"bulk.keepArea": "نگهداشتن حوزه",
|
|
44743
|
+
"bulk.keepSection": "نگهداشتن بخش",
|
|
44323
44744
|
"bulk.waitingPersonRequired": "انتخاب کنید این موارد منتظر چه کسی هستند.",
|
|
44324
44745
|
"bulk.deleting": "در حال حذف کارهای انتخابشده...",
|
|
44325
44746
|
"sort.label": "مرتبسازی",
|
|
@@ -44865,6 +45286,12 @@ var init_fa = __esm(() => {
|
|
|
44865
45286
|
"settings.syncMobile.accountStatus": "وضعیت حساب",
|
|
44866
45287
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "دقیقاً همین آدرس بازگشت را در تنظیمات OAuth Dropbox اضافه کنید.",
|
|
44867
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": "خاموش",
|
|
44868
45295
|
"settings.syncMobile.clearPendingAttachmentDeletes": "حذفهای در انتظار پیوست پاک شوند؟",
|
|
44869
45296
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "CloudKit روی این دستگاه محدود شده است. Screen Time، MDM یا محدودیتهای iCloud را بررسی کرده و دوباره امتحان کنید.",
|
|
44870
45297
|
"settings.syncMobile.connectedToDropbox": "به Dropbox متصل شد.",
|
|
@@ -44952,6 +45379,9 @@ var init_fa = __esm(() => {
|
|
|
44952
45379
|
"settings.syncMobile.webdavEndpointIsReachable": "نقطه پایانی WebDAV در دسترس است.",
|
|
44953
45380
|
"settings.persistentCaptureLabel": "ثبت سریع در نوار اعلان",
|
|
44954
45381
|
"settings.persistentCaptureDesc": "یک اعلان پایدار برای ثبت از هر جا، از جمله صفحه قفل، نگه دار.",
|
|
45382
|
+
"settings.exactAlarmsLabel": "یادآورها ممکن است دیر برسند",
|
|
45383
|
+
"settings.exactAlarmsDesc": "اندروید به Mindwtr اجازهی تنظیم زنگ دقیق نمیدهد، بنابراین یادآورها ممکن است تا یک دقیقه دیرتر اجرا شوند.",
|
|
45384
|
+
"settings.exactAlarmsAllow": "اجازه بده",
|
|
44955
45385
|
"settings.appSearchLabel": "نمایش در جستجوی سیستم",
|
|
44956
45386
|
"settings.appSearchDesc": "به جستجوی سیستم اندروید اجازه بده کارها، پروژهها و حوزههای فعال شما را بر اساس عنوان پیدا کند. هیچ دادهای از این دستگاه خارج نمیشود.",
|
|
44957
45387
|
"captureNotification.title": "ثبت سریع",
|
|
@@ -45286,6 +45716,8 @@ var init_fa = __esm(() => {
|
|
|
45286
45716
|
"settings.gettingStartedContentContinueDesc": "پس از پایان کار در اینجا نیز میتوانید پروژه راهنمای «شروع کار» و موارد نمونه صندوق ورودی را اضافه کنید.",
|
|
45287
45717
|
"settings.syncSetupGuideTitle": "راهنمای راهاندازی داده و همگامسازی",
|
|
45288
45718
|
"settings.syncSetupGuideDesc": "نکات راهاندازی برای Dropbox، iCloud، WebDAV، همگامسازی فایل و بازیابی.",
|
|
45719
|
+
"settings.syncEncryptionGuideTitle": "راهنمای رمزگذاری همگامسازی",
|
|
45720
|
+
"settings.syncEncryptionGuideDesc": "چه چیزی را محافظت میکند، کدام سرورها از آن پشتیبانی میکنند و عبارت عبور چگونه کار میکند.",
|
|
45289
45721
|
"settings.importSetupGuideTitle": "راهنمای راهاندازی واردکردن",
|
|
45290
45722
|
"settings.importSetupGuideDesc": "روشهای واردکردن پشتیبانیشده برای Todoist، TickTick، DGT GTD، OmniFocus، Mindwtr CSV، یادآورهای Apple و نسخههای پشتیبان.",
|
|
45291
45723
|
"settings.backupDiagnostics.newerVersion": "این نسخه پشتیبان با نسخه جدیدتری از Mindwtr ({{version}}) ساخته شده است.",
|
|
@@ -45308,7 +45740,7 @@ var init_fa = __esm(() => {
|
|
|
45308
45740
|
"settings.importDiagnostics.unmappedDate": "{{count}} مقدار تاریخ قابل تبدیل نبود و حذف شد.",
|
|
45309
45741
|
"settings.importDiagnostics.unmappedStatus": "{{count}} مقدار وضعیت قابل تبدیل نبود و مقدار پیشفرض امن استفاده شد.",
|
|
45310
45742
|
"settings.importDiagnostics.unsupportedRecurrence": "{{count}} قانون تکرار پشتیبانینشده بهصورت یادداشت نگه داشته شد.",
|
|
45311
|
-
"settings.syncRemoteBusy": "
|
|
45743
|
+
"settings.syncRemoteBusy": "دستگاه Mindwtr دیگری این مکان همگامسازی را برای لحظهای در اختیار دارد. همگامسازی بهطور خودکار دوباره تلاش میکند.",
|
|
45312
45744
|
"settings.syncRemoteCleanupDeferred": "عملیات همگامسازی کامل شد. Mindwtr نتوانست قفل موقت همگامسازی را حذف کند، اما این قفل خودکار منقضی میشود. نیازی به تلاش دوباره نیست.",
|
|
45313
45745
|
"settings.syncAttachmentWriteDeferred": "برخی تغییرات پیوستها کامل نشد. فایلهای محلی گمشده را بازیابی کنید یا پیوستهای مربوط را حذف کنید، سپس دوباره همگامسازی کنید.",
|
|
45314
45746
|
"settings.syncFileAttachmentTooLarge": "Mindwtr پیوست محلی را نگه داشت. File Sync فقط میتواند پیوستهای کوچکتر از ۱۰۰ مگابایت را همگامسازی کند. آن را با فایل کوچکتری جایگزین کنید یا پیوست را حذف کنید، سپس دوباره همگامسازی کنید.",
|
|
@@ -45343,6 +45775,9 @@ var init_sv = __esm(() => {
|
|
|
45343
45775
|
"nav.main": "Huvud",
|
|
45344
45776
|
"nav.inbox": "Inkorg",
|
|
45345
45777
|
"nav.board": "Tavelvy",
|
|
45778
|
+
"nav.timeline": "Tidslinje",
|
|
45779
|
+
"timeline.empty": "Inget schemalagt än",
|
|
45780
|
+
"timeline.emptyHint": "Uppgifter med start- eller förfallodatum visas här som staplar.",
|
|
45346
45781
|
"nav.projects": "Projekt",
|
|
45347
45782
|
"nav.contexts": "Kontexter",
|
|
45348
45783
|
"nav.next": "Nästa steg",
|
|
@@ -45429,6 +45864,7 @@ var init_sv = __esm(() => {
|
|
|
45429
45864
|
"keybindings.goReference": "Gå till Referens",
|
|
45430
45865
|
"keybindings.goCalendar": "Gå till Kalender",
|
|
45431
45866
|
"keybindings.goBoard": "Gå till Tavla",
|
|
45867
|
+
"keybindings.goTimeline": "Gå till Tidslinje",
|
|
45432
45868
|
"keybindings.goDone": "Gå till Klart",
|
|
45433
45869
|
"keybindings.goArchived": "Gå till Arkiverat",
|
|
45434
45870
|
"keybindings.switchArea": "Byt till område 1–9",
|
|
@@ -45607,9 +46043,12 @@ var init_sv = __esm(() => {
|
|
|
45607
46043
|
"attachments.obsidianLinkPlaceholder": "obsidian://open?vault=Vault&file=Note",
|
|
45608
46044
|
"attachments.obsidianLinkInputHint": 'Klistra in en obsidian://-anteckningslänk, eller använd "Titel | obsidian://...".',
|
|
45609
46045
|
"attachments.fileNotSupported": "Filbilagor stöds endast i skrivbordsappen.",
|
|
46046
|
+
"attachments.webUnavailable": "Den här bilagan är inte tillgänglig i webbappen.",
|
|
45610
46047
|
"attachments.fileTooLarge": "Filen är för stor för att laddas upp.",
|
|
45611
46048
|
"attachments.fileNotReadable": "Kunde inte läsa filen, så den bifogades inte. Flytta den till en annan mapp och försök igen.",
|
|
45612
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.",
|
|
45613
46052
|
"attachments.invalidFileType": "Filtypen stöds inte.",
|
|
45614
46053
|
"attachments.invalidLink": "Ange en giltig URL.",
|
|
45615
46054
|
"attachments.photoUnavailableTitle": "Bildväljaren är inte tillgänglig",
|
|
@@ -45976,7 +46415,7 @@ var init_sv = __esm(() => {
|
|
|
45976
46415
|
"projects.sectionPlaceholder": "Sektionens titel",
|
|
45977
46416
|
"projects.noSection": "Ingen sektion",
|
|
45978
46417
|
"projects.sectionEmpty": "Inga uppgifter",
|
|
45979
|
-
"projects.deleteSectionConfirm": "
|
|
46418
|
+
"projects.deleteSectionConfirm": "Ta bort denna sektion? Uppgifterna i den tas inte bort utan flyttas till Ingen sektion.",
|
|
45980
46419
|
"projects.areaFilter": "Områdesfilter",
|
|
45981
46420
|
"projects.allAreas": "Alla områden",
|
|
45982
46421
|
"projects.noArea": "Inget område",
|
|
@@ -46009,6 +46448,8 @@ var init_sv = __esm(() => {
|
|
|
46009
46448
|
"projects.complete": "Slutför",
|
|
46010
46449
|
"projects.archive": "Arkivera",
|
|
46011
46450
|
"projects.reactivate": "Återaktivera",
|
|
46451
|
+
"projects.archivedTaskInspectionHint": "Dubbeltryck för att granska uppgiften. Återaktivera projektet för att redigera den.",
|
|
46452
|
+
"projects.archivedReadOnlyHint": "Arkiverat projekt. Återaktivera det för att redigera uppgiften.",
|
|
46012
46453
|
"projects.actionsLabel": "Åtgärder",
|
|
46013
46454
|
"projects.archiveHelp": "Att arkivera ett projekt slutför det och dess kvarvarande uppgifter — återaktivera det när som helst.",
|
|
46014
46455
|
"projects.completeConfirm": "Markera det här projektet som slutfört och avsluta alla dess uppgifter?",
|
|
@@ -46314,6 +46755,7 @@ var init_sv = __esm(() => {
|
|
|
46314
46755
|
"settings.material3ThemeDesc": "Använd Material 3-färgtoken på Android",
|
|
46315
46756
|
"settings.selectLang": "Välj ditt önskade språk",
|
|
46316
46757
|
"settings.languagePartlyTranslated": "Delvis översatt",
|
|
46758
|
+
"settings.videoTutorials": "Videohandledningar",
|
|
46317
46759
|
"settings.privacy": "Integritet",
|
|
46318
46760
|
"settings.mobile.appLock": "Applås",
|
|
46319
46761
|
"settings.mobile.appLockDesc": "Kräv enhetens lås när du öppnar Mindwtr eller återgår till appen. Det här skyddar appvyn, inte databasen på enheten.",
|
|
@@ -46401,6 +46843,8 @@ var init_sv = __esm(() => {
|
|
|
46401
46843
|
"settings.syncEncryptionUnlock": "Ange lösenfras",
|
|
46402
46844
|
"settings.syncEncryptionDecline": "Inte nu",
|
|
46403
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.",
|
|
46404
46848
|
"settings.syncEncryptionRemoteEncrypted": "Den här synkplatsen är krypterad. Ange synklösenfrasen för att fortsätta synka.",
|
|
46405
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.",
|
|
46406
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.",
|
|
@@ -46646,6 +47090,10 @@ var init_sv = __esm(() => {
|
|
|
46646
47090
|
"settings.featureTimeEstimatesDesc": "Lägg till snabba tidsuppskattningar för tidsblockering.",
|
|
46647
47091
|
"settings.featurePomodoro": "Pomodoro-timer",
|
|
46648
47092
|
"settings.featurePomodoroDesc": "Aktivera den valfria Pomodoro-panelen i Fokus-vyn.",
|
|
47093
|
+
"settings.featureTimeline": "Tidslinjevy",
|
|
47094
|
+
"settings.featureTimelineDesc": "Visa en skrivskyddad tidslinje över daterade uppgifter i sidofältet.",
|
|
47095
|
+
"settings.sidebarViews": "Vyer i sidofältet",
|
|
47096
|
+
"settings.sidebarViewsDesc": "Välj vilka vyer som visas i sidofältet. Dolda vyer nås fortfarande via sök.",
|
|
46649
47097
|
"settings.pomodoroCustomPreset": "Anpassad förinställning",
|
|
46650
47098
|
"settings.pomodoroCustomPresetDesc": "Lägg till en extra fokus-/pausförinställning. Matchar den en inbyggd förinställning behålls bara de inbyggda alternativen.",
|
|
46651
47099
|
"settings.pomodoroFocusMinutes": "Fokusminuter",
|
|
@@ -46732,6 +47180,7 @@ var init_sv = __esm(() => {
|
|
|
46732
47180
|
"tags.title": "Taggar",
|
|
46733
47181
|
"areas.edit": "Redigera område",
|
|
46734
47182
|
"common.edit": "Redigera",
|
|
47183
|
+
"common.view": "Visa",
|
|
46735
47184
|
"common.add": "Lägg till",
|
|
46736
47185
|
"common.open": "Öppna",
|
|
46737
47186
|
"common.ok": "OK",
|
|
@@ -46799,6 +47248,7 @@ var init_sv = __esm(() => {
|
|
|
46799
47248
|
"bulk.keepStatus": "Behåll status",
|
|
46800
47249
|
"bulk.keepProject": "Behåll projekt",
|
|
46801
47250
|
"bulk.keepArea": "Behåll område",
|
|
47251
|
+
"bulk.keepSection": "Behåll sektion",
|
|
46802
47252
|
"bulk.waitingPersonRequired": "Välj vem de här posterna väntar på.",
|
|
46803
47253
|
"bulk.deleting": "Tar bort markerade uppgifter...",
|
|
46804
47254
|
"sort.label": "Sortera",
|
|
@@ -47344,6 +47794,12 @@ En uppdatering finns i App Store. Öppna appsidan nu?`,
|
|
|
47344
47794
|
"settings.syncMobile.accountStatus": "Kontostatus",
|
|
47345
47795
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "Lägg till exakt den här omdirigerings-URI:n i Dropboxs OAuth-inställningar.",
|
|
47346
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",
|
|
47347
47803
|
"settings.syncMobile.clearPendingAttachmentDeletes": "Rensa väntande bilageborttagningar?",
|
|
47348
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.",
|
|
47349
47805
|
"settings.syncMobile.connectedToDropbox": "Ansluten till Dropbox.",
|
|
@@ -47431,6 +47887,9 @@ En uppdatering finns i App Store. Öppna appsidan nu?`,
|
|
|
47431
47887
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV-slutpunkten är nåbar.",
|
|
47432
47888
|
"settings.persistentCaptureLabel": "Snabbinspelning i aviseringsfältet",
|
|
47433
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",
|
|
47434
47893
|
"settings.appSearchLabel": "Exponera för systemsökning",
|
|
47435
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.",
|
|
47436
47895
|
"captureNotification.title": "Snabbinspelning",
|
|
@@ -47765,6 +48224,8 @@ En uppdatering finns i App Store. Öppna appsidan nu?`,
|
|
|
47765
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.",
|
|
47766
48225
|
"settings.syncSetupGuideTitle": "Guide för data- och synkroniseringsinställning",
|
|
47767
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.",
|
|
47768
48229
|
"settings.importSetupGuideTitle": "Guide för importinställning",
|
|
47769
48230
|
"settings.importSetupGuideDesc": "Importvägar som stöds för Todoist, TickTick, DGT GTD, OmniFocus, Mindwtr CSV, Apple Påminnelser och säkerhetskopior.",
|
|
47770
48231
|
"settings.backupDiagnostics.newerVersion": "Den här säkerhetskopian skapades med en nyare version av Mindwtr ({{version}}).",
|
|
@@ -47787,7 +48248,7 @@ En uppdatering finns i App Store. Öppna appsidan nu?`,
|
|
|
47787
48248
|
"settings.importDiagnostics.unmappedDate": "{{count}} datumvärden kunde inte mappas och utelämnades.",
|
|
47788
48249
|
"settings.importDiagnostics.unmappedStatus": "{{count}} statusvärden kunde inte mappas; ett säkert standardvärde användes.",
|
|
47789
48250
|
"settings.importDiagnostics.unsupportedRecurrence": "{{count}} upprepningsregler som inte stöds sparades som anteckningar.",
|
|
47790
|
-
"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.",
|
|
47791
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.",
|
|
47792
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.",
|
|
47793
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.",
|
|
@@ -47820,7 +48281,7 @@ var init_i18n_locales = __esm(() => {
|
|
|
47820
48281
|
mode: "overrides",
|
|
47821
48282
|
native: "Tiếng Việt",
|
|
47822
48283
|
nonLatin: false,
|
|
47823
|
-
translatedKeyFloor:
|
|
48284
|
+
translatedKeyFloor: 2280
|
|
47824
48285
|
},
|
|
47825
48286
|
zh: {
|
|
47826
48287
|
loadSync: () => (init_zh_Hans(), __toCommonJS(exports_zh_Hans)),
|
|
@@ -47950,7 +48411,7 @@ var init_i18n_locales = __esm(() => {
|
|
|
47950
48411
|
mode: "overrides",
|
|
47951
48412
|
native: "한국어",
|
|
47952
48413
|
nonLatin: true,
|
|
47953
|
-
translatedKeyFloor:
|
|
48414
|
+
translatedKeyFloor: 2240
|
|
47954
48415
|
},
|
|
47955
48416
|
it: {
|
|
47956
48417
|
loadSync: () => (init_it(), __toCommonJS(exports_it)),
|
|
@@ -48211,12 +48672,15 @@ var init_settings_options = __esm(() => {
|
|
|
48211
48672
|
GTD_SYNCED_FEATURE_FIELD_KEYS = [
|
|
48212
48673
|
"priorities",
|
|
48213
48674
|
"timeEstimates",
|
|
48214
|
-
"pomodoro"
|
|
48675
|
+
"pomodoro",
|
|
48676
|
+
"timeline"
|
|
48215
48677
|
];
|
|
48216
48678
|
});
|
|
48217
48679
|
|
|
48218
48680
|
// ../../packages/core/src/async-utils.ts
|
|
48219
|
-
var
|
|
48681
|
+
var sleepBypass = null, setSleepBypass = (predicate) => {
|
|
48682
|
+
sleepBypass = predicate;
|
|
48683
|
+
}, sleep = (ms) => sleepBypass?.() ? Promise.resolve() : new Promise((resolve) => setTimeout(resolve, ms)), decodeUriSafe = (value) => {
|
|
48220
48684
|
try {
|
|
48221
48685
|
return decodeURIComponent(value);
|
|
48222
48686
|
} catch {
|
|
@@ -48282,7 +48746,8 @@ function resolveFeatureFlags(settings) {
|
|
|
48282
48746
|
return {
|
|
48283
48747
|
priorities: settings?.features?.priorities !== false,
|
|
48284
48748
|
timeEstimates: settings?.features?.timeEstimates !== false,
|
|
48285
|
-
pomodoro: settings?.features?.pomodoro === true
|
|
48749
|
+
pomodoro: settings?.features?.pomodoro === true,
|
|
48750
|
+
timeline: settings?.features?.timeline === true
|
|
48286
48751
|
};
|
|
48287
48752
|
}
|
|
48288
48753
|
|
|
@@ -48311,6 +48776,15 @@ function buildBulkOrganizeTaskUpdate(task, input) {
|
|
|
48311
48776
|
updates.projectId = undefined;
|
|
48312
48777
|
}
|
|
48313
48778
|
}
|
|
48779
|
+
if (hasOwn(input, "sectionId")) {
|
|
48780
|
+
const sectionId = normalizedOptionalString(input.sectionId);
|
|
48781
|
+
const effectiveProjectId = hasOwn(updates, "projectId") ? updates.projectId : normalizedOptionalString(task.projectId);
|
|
48782
|
+
if (!sectionId) {
|
|
48783
|
+
updates.sectionId = undefined;
|
|
48784
|
+
} else if (effectiveProjectId && effectiveProjectId === normalizedOptionalString(input.sectionProjectId)) {
|
|
48785
|
+
updates.sectionId = sectionId;
|
|
48786
|
+
}
|
|
48787
|
+
}
|
|
48314
48788
|
const contexts = mergeTokens(task.contexts, input.contexts);
|
|
48315
48789
|
if (contexts)
|
|
48316
48790
|
updates.contexts = contexts;
|
|
@@ -67342,11 +67816,14 @@ var DEFAULT_TIMEOUT_MS = 30000, SYNC_LOCAL_INSECURE_URL_OPTIONS, isAbortError =
|
|
|
67342
67816
|
onProgress(offset, total);
|
|
67343
67817
|
}
|
|
67344
67818
|
});
|
|
67345
|
-
}, 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) => {
|
|
67346
67820
|
const abortController = typeof AbortController === "function" ? new AbortController : null;
|
|
67347
67821
|
let didTimeout = false;
|
|
67822
|
+
let firedAfterSuspension = false;
|
|
67823
|
+
const startedAt = Date.now();
|
|
67348
67824
|
const timeoutId = abortController ? setTimeout(() => {
|
|
67349
67825
|
didTimeout = true;
|
|
67826
|
+
firedAfterSuspension = Date.now() - startedAt > timeoutMs * SUSPENDED_REQUEST_FACTOR;
|
|
67350
67827
|
abortController.abort(createAbortError(timeoutMessage));
|
|
67351
67828
|
}, timeoutMs) : null;
|
|
67352
67829
|
const signal = abortController?.signal ?? init.signal ?? undefined;
|
|
@@ -67381,7 +67858,7 @@ var DEFAULT_TIMEOUT_MS = 30000, SYNC_LOCAL_INSECURE_URL_OPTIONS, isAbortError =
|
|
|
67381
67858
|
} catch (error2) {
|
|
67382
67859
|
if (isAbortError(error2)) {
|
|
67383
67860
|
if (didTimeout) {
|
|
67384
|
-
throw new Error(timeoutMessage);
|
|
67861
|
+
throw new Error(firedAfterSuspension ? `${timeoutMessage}; ${SUSPENDED_REQUEST_MESSAGE}` : timeoutMessage);
|
|
67385
67862
|
}
|
|
67386
67863
|
if (externalSignal?.aborted) {
|
|
67387
67864
|
throw getAbortSignalReason(externalSignal, "Request cancelled");
|
|
@@ -70549,6 +71026,28 @@ function buildRRuleString(rule, byDay, interval3, options = {}) {
|
|
|
70549
71026
|
}
|
|
70550
71027
|
return parts.join(";");
|
|
70551
71028
|
}
|
|
71029
|
+
function editRRuleString(existingRRule, rule, overrides = {}) {
|
|
71030
|
+
const parsed = parseRRuleString(existingRRule);
|
|
71031
|
+
const byDay = hasRRuleEditOverride(overrides, "byDay") ? overrides.byDay : parsed.byDay;
|
|
71032
|
+
const interval3 = hasRRuleEditOverride(overrides, "interval") ? overrides.interval : parsed.interval;
|
|
71033
|
+
const byMonthDay = hasRRuleEditOverride(overrides, "byMonthDay") ? overrides.byMonthDay : parsed.byMonthDay;
|
|
71034
|
+
const count = hasRRuleEditOverride(overrides, "count") ? overrides.count : parsed.count;
|
|
71035
|
+
const weekStart = hasRRuleEditOverride(overrides, "weekStart") ? overrides.weekStart : parsed.weekStart;
|
|
71036
|
+
const until = hasRRuleEditOverride(overrides, "until") ? overrides.until : parsed.until;
|
|
71037
|
+
const edited = buildRRuleString(rule, byDay, interval3, {
|
|
71038
|
+
byMonthDay,
|
|
71039
|
+
count,
|
|
71040
|
+
weekStart,
|
|
71041
|
+
until
|
|
71042
|
+
});
|
|
71043
|
+
const opaqueTokens = existingRRule.split(";").map((part) => part.trim()).filter((part) => {
|
|
71044
|
+
const separator = part.indexOf("=");
|
|
71045
|
+
if (separator <= 0 || separator === part.length - 1)
|
|
71046
|
+
return false;
|
|
71047
|
+
return !EDITABLE_RRULE_TOKEN_KEYS.has(part.slice(0, separator).trim().toUpperCase());
|
|
71048
|
+
});
|
|
71049
|
+
return opaqueTokens.length > 0 ? `${edited};${opaqueTokens.join(";")}` : edited;
|
|
71050
|
+
}
|
|
70552
71051
|
function getRecurrenceRRuleValue(value) {
|
|
70553
71052
|
if (!value || typeof value === "string" || !value.rule)
|
|
70554
71053
|
return "";
|
|
@@ -70557,16 +71056,25 @@ function getRecurrenceRRuleValue(value) {
|
|
|
70557
71056
|
const count = getRecurrenceCountValue(value);
|
|
70558
71057
|
const until = getRecurrenceUntilValue(value);
|
|
70559
71058
|
if (value.byDay?.length) {
|
|
70560
|
-
return buildRRuleString(value.rule, value.byDay, undefined, {
|
|
71059
|
+
return buildRRuleString(value.rule, value.byDay, undefined, {
|
|
71060
|
+
count,
|
|
71061
|
+
weekStart: value.weekStart,
|
|
71062
|
+
until
|
|
71063
|
+
});
|
|
70561
71064
|
}
|
|
70562
71065
|
if (value.byMonthDay?.length) {
|
|
70563
71066
|
return buildRRuleString(value.rule, undefined, undefined, {
|
|
70564
71067
|
byMonthDay: value.byMonthDay,
|
|
70565
71068
|
count,
|
|
71069
|
+
weekStart: value.weekStart,
|
|
70566
71070
|
until
|
|
70567
71071
|
});
|
|
70568
71072
|
}
|
|
70569
|
-
return buildRRuleString(value.rule, undefined, undefined, {
|
|
71073
|
+
return buildRRuleString(value.rule, undefined, undefined, {
|
|
71074
|
+
count,
|
|
71075
|
+
weekStart: value.weekStart,
|
|
71076
|
+
until
|
|
71077
|
+
});
|
|
70570
71078
|
}
|
|
70571
71079
|
function hasRecurrenceRule(value) {
|
|
70572
71080
|
return getRecurrenceRule(value) !== null;
|
|
@@ -71444,7 +71952,7 @@ var RECURRENCE_RULES, RECURRENCE_INTERVAL_MAX = 999, RRULE_SERIES_ID_KEY = "X-MI
|
|
|
71444
71952
|
return;
|
|
71445
71953
|
const weekly = normalized.filter((day) => WEEKDAY_ORDER.includes(day));
|
|
71446
71954
|
return weekly.length > 0 ? Array.from(new Set(weekly)) : undefined;
|
|
71447
|
-
}, getDateDay = (value) => {
|
|
71955
|
+
}, EDITABLE_RRULE_TOKEN_KEYS, hasRRuleEditOverride = (overrides, key) => Object.prototype.hasOwnProperty.call(overrides, key), getDateDay = (value) => {
|
|
71448
71956
|
const parsed = safeParseDate(value);
|
|
71449
71957
|
return parsed ? parsed.getDate() : undefined;
|
|
71450
71958
|
}, getRecurrenceScheduleAnchorField = (dates) => ["dueDate", "startTime", "reviewAt"].find((field) => Boolean(dates[field])) ?? null, weekdayIndex = (weekday) => WEEKDAY_ORDER.indexOf(weekday), getLastDayOfMonth = (year, month) => {
|
|
@@ -71534,6 +72042,15 @@ var init_recurrence = __esm(() => {
|
|
|
71534
72042
|
MONTHLY: "monthly",
|
|
71535
72043
|
YEARLY: "yearly"
|
|
71536
72044
|
};
|
|
72045
|
+
EDITABLE_RRULE_TOKEN_KEYS = new Set([
|
|
72046
|
+
"FREQ",
|
|
72047
|
+
"INTERVAL",
|
|
72048
|
+
"BYDAY",
|
|
72049
|
+
"BYMONTHDAY",
|
|
72050
|
+
"COUNT",
|
|
72051
|
+
"WKST",
|
|
72052
|
+
"UNTIL"
|
|
72053
|
+
]);
|
|
71537
72054
|
});
|
|
71538
72055
|
|
|
71539
72056
|
// ../../packages/core/src/task-date-coherence.ts
|
|
@@ -71584,6 +72101,9 @@ var init_en = __esm(() => {
|
|
|
71584
72101
|
"nav.main": "Main",
|
|
71585
72102
|
"nav.inbox": "Inbox",
|
|
71586
72103
|
"nav.board": "Board View",
|
|
72104
|
+
"nav.timeline": "Timeline",
|
|
72105
|
+
"timeline.empty": "Nothing scheduled yet",
|
|
72106
|
+
"timeline.emptyHint": "Tasks with a start or due date appear here as bars.",
|
|
71587
72107
|
"nav.projects": "Projects",
|
|
71588
72108
|
"nav.contexts": "Contexts",
|
|
71589
72109
|
"nav.next": "Next Actions",
|
|
@@ -71670,6 +72190,7 @@ var init_en = __esm(() => {
|
|
|
71670
72190
|
"keybindings.goReference": "Go to Reference",
|
|
71671
72191
|
"keybindings.goCalendar": "Go to Calendar",
|
|
71672
72192
|
"keybindings.goBoard": "Go to Board",
|
|
72193
|
+
"keybindings.goTimeline": "Go to Timeline",
|
|
71673
72194
|
"keybindings.goDone": "Go to Done",
|
|
71674
72195
|
"keybindings.goArchived": "Go to Archived",
|
|
71675
72196
|
"keybindings.switchArea": "Switch to Area 1-9",
|
|
@@ -71847,9 +72368,12 @@ var init_en = __esm(() => {
|
|
|
71847
72368
|
"attachments.obsidianLinkPlaceholder": "obsidian://open?vault=Vault&file=Note",
|
|
71848
72369
|
"attachments.obsidianLinkInputHint": 'Paste an obsidian:// note link, or use "Title | obsidian://...".',
|
|
71849
72370
|
"attachments.fileNotSupported": "File attachments are only supported in the desktop app.",
|
|
72371
|
+
"attachments.webUnavailable": "This attachment is not available in the web app.",
|
|
71850
72372
|
"attachments.fileTooLarge": "File is too large to upload.",
|
|
71851
72373
|
"attachments.fileNotReadable": "Couldn't read this file, so it was not attached. Move it to a different folder and try again.",
|
|
71852
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.",
|
|
71853
72377
|
"attachments.invalidFileType": "Unsupported file type.",
|
|
71854
72378
|
"attachments.invalidLink": "Please enter a valid URL.",
|
|
71855
72379
|
"attachments.photoUnavailableTitle": "Photo picker unavailable",
|
|
@@ -72217,7 +72741,7 @@ var init_en = __esm(() => {
|
|
|
72217
72741
|
"projects.sectionPlaceholder": "Section title",
|
|
72218
72742
|
"projects.noSection": "No Section",
|
|
72219
72743
|
"projects.sectionEmpty": "No tasks",
|
|
72220
|
-
"projects.deleteSectionConfirm": "
|
|
72744
|
+
"projects.deleteSectionConfirm": "Delete this section? Its tasks are not deleted; they move to No Section.",
|
|
72221
72745
|
"projects.areaFilter": "Area filter",
|
|
72222
72746
|
"projects.allAreas": "All areas",
|
|
72223
72747
|
"projects.noArea": "No area",
|
|
@@ -72250,6 +72774,8 @@ var init_en = __esm(() => {
|
|
|
72250
72774
|
"projects.complete": "Complete",
|
|
72251
72775
|
"projects.archive": "Archive",
|
|
72252
72776
|
"projects.reactivate": "Reactivate",
|
|
72777
|
+
"projects.archivedTaskInspectionHint": "Double-tap to inspect this task. Reactivate the project to edit it.",
|
|
72778
|
+
"projects.archivedReadOnlyHint": "Archived project. Reactivate it to edit this task.",
|
|
72253
72779
|
"projects.actionsLabel": "Actions",
|
|
72254
72780
|
"projects.archiveHelp": "Archiving a project completes it and its remaining tasks — reactivate it anytime.",
|
|
72255
72781
|
"projects.completeConfirm": "Mark this project completed and finish all its tasks?",
|
|
@@ -72555,6 +73081,7 @@ var init_en = __esm(() => {
|
|
|
72555
73081
|
"settings.material3ThemeDesc": "Use Material 3 color tokens on Android",
|
|
72556
73082
|
"settings.selectLang": "Select your preferred language",
|
|
72557
73083
|
"settings.languagePartlyTranslated": "Partly translated",
|
|
73084
|
+
"settings.videoTutorials": "Video tutorials",
|
|
72558
73085
|
"settings.privacy": "Privacy",
|
|
72559
73086
|
"settings.mobile.appLock": "App lock",
|
|
72560
73087
|
"settings.mobile.appLockDesc": "Require your device lock when opening Mindwtr or returning to the app. This protects the app view, not the on-device database.",
|
|
@@ -72642,6 +73169,8 @@ var init_en = __esm(() => {
|
|
|
72642
73169
|
"settings.syncEncryptionUnlock": "Enter passphrase",
|
|
72643
73170
|
"settings.syncEncryptionDecline": "Not now",
|
|
72644
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.",
|
|
72645
73174
|
"settings.syncEncryptionRemoteEncrypted": "This sync location is encrypted. Enter its sync passphrase to continue syncing.",
|
|
72646
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.",
|
|
72647
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.",
|
|
@@ -72887,6 +73416,10 @@ var init_en = __esm(() => {
|
|
|
72887
73416
|
"settings.featureTimeEstimatesDesc": "Add quick duration estimates for time blocking.",
|
|
72888
73417
|
"settings.featurePomodoro": "Pomodoro timer",
|
|
72889
73418
|
"settings.featurePomodoroDesc": "Enable the optional Pomodoro panel in Focus view.",
|
|
73419
|
+
"settings.featureTimeline": "Timeline view",
|
|
73420
|
+
"settings.featureTimelineDesc": "Show a read-only timeline of dated tasks in the sidebar.",
|
|
73421
|
+
"settings.sidebarViews": "Sidebar views",
|
|
73422
|
+
"settings.sidebarViewsDesc": "Choose which views appear in the sidebar. Hidden views stay available from search.",
|
|
72890
73423
|
"settings.pomodoroCustomPreset": "Custom preset",
|
|
72891
73424
|
"settings.pomodoroCustomPresetDesc": "Add one extra focus/break preset. Matching a built-in preset keeps the built-in chips only.",
|
|
72892
73425
|
"settings.pomodoroFocusMinutes": "Focus minutes",
|
|
@@ -72973,6 +73506,7 @@ var init_en = __esm(() => {
|
|
|
72973
73506
|
"tags.title": "Tags",
|
|
72974
73507
|
"areas.edit": "Edit area",
|
|
72975
73508
|
"common.edit": "Edit",
|
|
73509
|
+
"common.view": "View",
|
|
72976
73510
|
"common.add": "Add",
|
|
72977
73511
|
"common.open": "Open",
|
|
72978
73512
|
"common.ok": "OK",
|
|
@@ -73040,6 +73574,7 @@ var init_en = __esm(() => {
|
|
|
73040
73574
|
"bulk.keepStatus": "Keep status",
|
|
73041
73575
|
"bulk.keepProject": "Keep project",
|
|
73042
73576
|
"bulk.keepArea": "Keep area",
|
|
73577
|
+
"bulk.keepSection": "Keep section",
|
|
73043
73578
|
"bulk.waitingPersonRequired": "Choose who these items are waiting for.",
|
|
73044
73579
|
"bulk.deleting": "Deleting selected tasks...",
|
|
73045
73580
|
"sort.label": "Sort",
|
|
@@ -73585,6 +74120,12 @@ Update is available on the App Store. Open app listing now?`,
|
|
|
73585
74120
|
"settings.syncMobile.accountStatus": "Account status",
|
|
73586
74121
|
"settings.syncMobile.addThisExactRedirectUriInDropboxOauthSettings": "Add this exact redirect URI in Dropbox OAuth settings.",
|
|
73587
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",
|
|
73588
74129
|
"settings.syncMobile.clearPendingAttachmentDeletes": "Clear pending attachment deletes?",
|
|
73589
74130
|
"settings.syncMobile.cloudkitIsRestrictedOnThisDeviceCheckScreenTimeMdm": "CloudKit is restricted on this device. Check Screen Time, MDM, or iCloud restrictions, then try again.",
|
|
73590
74131
|
"settings.syncMobile.connectedToDropbox": "Connected to Dropbox.",
|
|
@@ -73672,6 +74213,9 @@ Update is available on the App Store. Open app listing now?`,
|
|
|
73672
74213
|
"settings.syncMobile.webdavEndpointIsReachable": "WebDAV endpoint is reachable.",
|
|
73673
74214
|
"settings.persistentCaptureLabel": "Quick capture in notification bar",
|
|
73674
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",
|
|
73675
74219
|
"settings.appSearchLabel": "Expose to system search",
|
|
73676
74220
|
"settings.appSearchDesc": "Let Android system search find your active tasks, projects, and areas by title. Nothing leaves this device.",
|
|
73677
74221
|
"captureNotification.title": "Quick capture",
|
|
@@ -74006,6 +74550,8 @@ Update is available on the App Store. Open app listing now?`,
|
|
|
74006
74550
|
"settings.gettingStartedContentContinueDesc": "When you are done here, you can still add the guided Getting Started project and sample inbox items.",
|
|
74007
74551
|
"settings.syncSetupGuideTitle": "Data & Sync setup guide",
|
|
74008
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.",
|
|
74009
74555
|
"settings.importSetupGuideTitle": "Import setup guide",
|
|
74010
74556
|
"settings.importSetupGuideDesc": "Supported Todoist, TickTick, DGT GTD, OmniFocus, Mindwtr CSV, Apple Reminders, and backup import paths.",
|
|
74011
74557
|
"settings.backupDiagnostics.newerVersion": "This backup was created by a newer Mindwtr version ({{version}}).",
|
|
@@ -74028,7 +74574,7 @@ Update is available on the App Store. Open app listing now?`,
|
|
|
74028
74574
|
"settings.importDiagnostics.unmappedDate": "{{count}} date value(s) could not be mapped and were omitted.",
|
|
74029
74575
|
"settings.importDiagnostics.unmappedStatus": "{{count}} status value(s) could not be mapped and used a safe default.",
|
|
74030
74576
|
"settings.importDiagnostics.unsupportedRecurrence": "{{count}} unsupported repeat rule(s) were kept as notes.",
|
|
74031
|
-
"settings.syncRemoteBusy": "Another
|
|
74577
|
+
"settings.syncRemoteBusy": "Another Mindwtr device is holding this sync location for a moment. Sync will retry on its own.",
|
|
74032
74578
|
"settings.syncRemoteCleanupDeferred": "The sync operation completed. Mindwtr could not remove the temporary sync lock, but it expires automatically. No retry is needed.",
|
|
74033
74579
|
"settings.syncAttachmentWriteDeferred": "Some attachment changes could not finish. Restore any missing local files or remove the affected attachments, then sync again.",
|
|
74034
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.",
|
|
@@ -84536,7 +85082,8 @@ function buildQuickAddParseOptions(settings, source = {}) {
|
|
|
84536
85082
|
knownPeople: getPersonOptionNames(source.people, tasks),
|
|
84537
85083
|
defaultScheduleTime: normalizeClockTimeInput(settings?.gtd?.defaultScheduleTime) || undefined,
|
|
84538
85084
|
preserveText: settings?.quickAddAutoClean !== true,
|
|
84539
|
-
naturalLanguageDates: isNaturalLanguageDatesEnabled(settings)
|
|
85085
|
+
naturalLanguageDates: isNaturalLanguageDatesEnabled(settings),
|
|
85086
|
+
parsePriority: resolveFeatureFlags(settings).priorities
|
|
84540
85087
|
};
|
|
84541
85088
|
}
|
|
84542
85089
|
function getQuickAddProjectInitialProps(props, fallbackAreaId) {
|
|
@@ -85040,7 +85587,7 @@ function parseQuickAdd(input, projects, now2 = new Date, areas, options = {}) {
|
|
|
85040
85587
|
}
|
|
85041
85588
|
}
|
|
85042
85589
|
let priority;
|
|
85043
|
-
const priorityMatch = working.match(/(?:^|\s)\/priority:([^\s/]+)/i);
|
|
85590
|
+
const priorityMatch = options.parsePriority === false ? null : working.match(/(?:^|\s)\/priority:([^\s/]+)/i);
|
|
85044
85591
|
if (priorityMatch) {
|
|
85045
85592
|
const token = restoreEscapes(priorityMatch[1] ?? "").trim().toLowerCase();
|
|
85046
85593
|
priority = PRIORITY_TOKENS[token];
|
|
@@ -85213,7 +85760,12 @@ function parseQuickAdd(input, projects, now2 = new Date, areas, options = {}) {
|
|
|
85213
85760
|
detectedDate
|
|
85214
85761
|
};
|
|
85215
85762
|
}
|
|
85216
|
-
|
|
85763
|
+
function formatQuickAddHelp(help, flags) {
|
|
85764
|
+
if (flags.priorities)
|
|
85765
|
+
return help;
|
|
85766
|
+
return help.replace(QUICK_ADD_PRIORITY_HELP_TOKEN, "");
|
|
85767
|
+
}
|
|
85768
|
+
var STATUS_TOKENS, ENERGY_TOKENS, PRIORITY_TOKENS, ESCAPE_SENTINEL = "__MW_ESC__", QUICK_ADD_ESCAPE_CHARS, QUICK_ADD_FOCUS_COMMAND_PATTERN, QUICK_ADD_COMMAND_START, QUICK_ADD_COMMAND_BOUNDARY, QUICK_ADD_INLINE_CONTROL_BOUNDARY, SIMPLE_TASK_TOKEN_RE, RICH_TASK_TOKEN_RE, NATURAL_TIME_HINT_RE, PURE_TIME_ONLY_RE, BARE_MONTH_RE, TRAILING_DATE_SUFFIX_RE, TRAILING_DATE_SEPARATOR_RE, dotDateParser, quickAddChrono, quickAddChronoDayFirst, getQuickAddChrono = () => isActiveDateFormatDayFirst() ? quickAddChronoDayFirst : quickAddChrono, LOCALE_CHRONO_FACTORY, localeChronoCache, TRAILING_DATE_INTRO_WORDS, localizedMonthNamesCache, CONTAINS_LETTER_RE, QUICK_ADD_PRIORITY_HELP_TOKEN;
|
|
85217
85769
|
var init_quick_add = __esm(() => {
|
|
85218
85770
|
init_esm();
|
|
85219
85771
|
init_date_fns();
|
|
@@ -85298,6 +85850,7 @@ var init_quick_add = __esm(() => {
|
|
|
85298
85850
|
};
|
|
85299
85851
|
localizedMonthNamesCache = new Map;
|
|
85300
85852
|
CONTAINS_LETTER_RE = /\p{L}/u;
|
|
85853
|
+
QUICK_ADD_PRIORITY_HELP_TOKEN = /\/priority:<[^>]*>(?:\s*[,،、]\s*|\s+)?/u;
|
|
85301
85854
|
});
|
|
85302
85855
|
|
|
85303
85856
|
// ../../packages/core/src/project-utils.ts
|
|
@@ -85312,6 +85865,19 @@ function normalizeProjectTaskSortBy(value) {
|
|
|
85312
85865
|
}
|
|
85313
85866
|
return;
|
|
85314
85867
|
}
|
|
85868
|
+
function getProjectSectionsForView(project, visibleSections, allSections = visibleSections) {
|
|
85869
|
+
if (!project)
|
|
85870
|
+
return [];
|
|
85871
|
+
const archivedHistory = project.status === "archived";
|
|
85872
|
+
const source = archivedHistory ? allSections : visibleSections;
|
|
85873
|
+
return source.filter((section) => {
|
|
85874
|
+
if (section.projectId !== project.id)
|
|
85875
|
+
return false;
|
|
85876
|
+
if (!section.deletedAt)
|
|
85877
|
+
return true;
|
|
85878
|
+
return archivedHistory && section.projectArchivedAt === section.deletedAt && section.deletedAtBeforeProjectArchive === null;
|
|
85879
|
+
}).sort(compareProjectSections);
|
|
85880
|
+
}
|
|
85315
85881
|
function getSequentialProjectTaskCues(project, tasks, options = {}) {
|
|
85316
85882
|
const cues = new Map;
|
|
85317
85883
|
if (!project?.isSequential)
|
|
@@ -85443,7 +86009,13 @@ function getProjectChoiceState(browseProjects, query, searchProjects = browsePro
|
|
|
85443
86009
|
canCreate: !exactMatch
|
|
85444
86010
|
};
|
|
85445
86011
|
}
|
|
85446
|
-
var TASK_SORT_BY_VALUES, TASK_SORT_BY_VALUE_SET, PROJECT_TASK_SORT_BY_VALUES,
|
|
86012
|
+
var TASK_SORT_BY_VALUES, TASK_SORT_BY_VALUE_SET, PROJECT_TASK_SORT_BY_VALUES, compareProjectSections = (a, b) => {
|
|
86013
|
+
const aOrder = Number.isFinite(a.order) ? a.order : 0;
|
|
86014
|
+
const bOrder = Number.isFinite(b.order) ? b.order : 0;
|
|
86015
|
+
if (aOrder !== bOrder)
|
|
86016
|
+
return aOrder - bOrder;
|
|
86017
|
+
return a.title.localeCompare(b.title);
|
|
86018
|
+
}, getTaskProjectOrder = (task) => {
|
|
85447
86019
|
if (Number.isFinite(task.order))
|
|
85448
86020
|
return task.order;
|
|
85449
86021
|
if (Number.isFinite(task.orderNum))
|
|
@@ -86368,6 +86940,36 @@ function buildTrashTimeline(tasks, projects) {
|
|
|
86368
86940
|
];
|
|
86369
86941
|
return items.sort((left, right) => compareDeletedAtDesc(getTrashTimelineEntity(left), getTrashTimelineEntity(right)));
|
|
86370
86942
|
}
|
|
86943
|
+
function resolveTaskSortByForFeatures(sortBy, settings) {
|
|
86944
|
+
const flags = resolveFeatureFlags(settings);
|
|
86945
|
+
if (sortBy === "timeEstimate" && !flags.timeEstimates)
|
|
86946
|
+
return "default";
|
|
86947
|
+
if (sortBy === "priority" && !flags.priorities)
|
|
86948
|
+
return "default";
|
|
86949
|
+
return sortBy;
|
|
86950
|
+
}
|
|
86951
|
+
function resolveTaskGroupByForFeatures(groupBy, settings) {
|
|
86952
|
+
if (groupBy === "priority" && !resolveFeatureFlags(settings).priorities)
|
|
86953
|
+
return "none";
|
|
86954
|
+
return groupBy;
|
|
86955
|
+
}
|
|
86956
|
+
function resolveTaskPerspectiveForFeatures({
|
|
86957
|
+
sortBy,
|
|
86958
|
+
groupBy,
|
|
86959
|
+
settings,
|
|
86960
|
+
hasActiveFilters,
|
|
86961
|
+
hasCurrentCriteria,
|
|
86962
|
+
activeSavedFilterId
|
|
86963
|
+
}) {
|
|
86964
|
+
const effectiveSortBy = resolveTaskSortByForFeatures(sortBy, settings);
|
|
86965
|
+
const effectiveGroupBy = resolveTaskGroupByForFeatures(groupBy, settings);
|
|
86966
|
+
return {
|
|
86967
|
+
effectiveSortBy,
|
|
86968
|
+
effectiveGroupBy,
|
|
86969
|
+
isDefaultPerspective: !hasActiveFilters && activeSavedFilterId === null && effectiveSortBy === "default",
|
|
86970
|
+
canSavePerspective: activeSavedFilterId === null && (hasCurrentCriteria || effectiveSortBy !== "default" || effectiveGroupBy !== "none")
|
|
86971
|
+
};
|
|
86972
|
+
}
|
|
86371
86973
|
function sortTasksBy(tasks, sortBy = "default") {
|
|
86372
86974
|
if (!sortBy || sortBy === "default") {
|
|
86373
86975
|
return sortTasks(tasks);
|
|
@@ -86517,7 +87119,7 @@ function sortTasksBySavedPreference(tasks, sortBy, options = {}) {
|
|
|
86517
87119
|
case "created-desc":
|
|
86518
87120
|
return withFallbacks(byCreatedDesc);
|
|
86519
87121
|
case "priority":
|
|
86520
|
-
return withFallbacks(byPriority, byDue, byStart, byCreatedAsc);
|
|
87122
|
+
return options.prioritizeByPriority ? withFallbacks(byPriority, byDue, byStart, byCreatedAsc) : withFallbacks(byDue, byStart, byCreatedAsc);
|
|
86521
87123
|
case "energy":
|
|
86522
87124
|
return withFallbacks(byEnergy, byDue, byStart, byCreatedAsc);
|
|
86523
87125
|
case "timeEstimate":
|
|
@@ -87518,6 +88120,7 @@ var init_sync_service_utils = __esm(() => {
|
|
|
87518
88120
|
READONLY_ERROR_PATTERN = /isn't writable|not writable|read-only|read only|permission denied|EACCES/i;
|
|
87519
88121
|
OFFLINE_ERROR_PATTERNS = [
|
|
87520
88122
|
/offline state detected/i,
|
|
88123
|
+
/interrupted while the app was suspended/i,
|
|
87521
88124
|
/network request failed/i,
|
|
87522
88125
|
/internet connection appears to be offline/i,
|
|
87523
88126
|
/airplane mode/i,
|
|
@@ -87658,7 +88261,18 @@ var init_tombstone_compaction = __esm(() => {
|
|
|
87658
88261
|
function filterNotDeleted(items) {
|
|
87659
88262
|
return items.filter((item) => !item.deletedAt);
|
|
87660
88263
|
}
|
|
87661
|
-
var MISSING_ATTACHMENT_TIMESTAMP_SENTINEL = "1970-01-01T00:00:00.000Z",
|
|
88264
|
+
var MISSING_ATTACHMENT_TIMESTAMP_SENTINEL = "1970-01-01T00:00:00.000Z", MISSING_SETTINGS_SYNC_TIMESTAMP_SENTINEL = "1970-01-01T00:00:00.000Z", advanceLatestSyncTimestamp = (...values) => {
|
|
88265
|
+
let latestTime = Date.parse(MISSING_SETTINGS_SYNC_TIMESTAMP_SENTINEL);
|
|
88266
|
+
for (const value of values) {
|
|
88267
|
+
const parsed = Date.parse(value ?? "");
|
|
88268
|
+
if (Number.isFinite(parsed) && parsed > latestTime)
|
|
88269
|
+
latestTime = parsed;
|
|
88270
|
+
}
|
|
88271
|
+
if (!Number.isFinite(latestTime))
|
|
88272
|
+
return;
|
|
88273
|
+
const advanced = new Date(latestTime + 1);
|
|
88274
|
+
return Number.isFinite(advanced.getTime()) ? advanced.toISOString() : undefined;
|
|
88275
|
+
}, normalizeWebdavUrl = (rawUrl) => {
|
|
87662
88276
|
const splitIndex = rawUrl.search(/[?#]/);
|
|
87663
88277
|
const pathEnd = splitIndex >= 0 ? splitIndex : rawUrl.length;
|
|
87664
88278
|
const path = rawUrl.slice(0, pathEnd).replace(/\/+$/, "");
|
|
@@ -87749,9 +88363,20 @@ var MISSING_ATTACHMENT_TIMESTAMP_SENTINEL = "1970-01-01T00:00:00.000Z", normaliz
|
|
|
87749
88363
|
assertNoPendingUploadList(findPendingAttachmentUploads(data).filter((item) => item.reason === "content-replacement"));
|
|
87750
88364
|
}, hasPendingSyncSideEffects = (data) => Boolean(data.settings.pendingRemoteWriteAt) || findPendingAttachmentUploads(data).length > 0 || Boolean(data.settings.attachments?.pendingRemoteDeletes?.length), sanitizeSettingsForRemote = (settings) => {
|
|
87751
88365
|
const prefs = settings.syncPreferences ?? {};
|
|
88366
|
+
const remotePrefs = { ...prefs };
|
|
88367
|
+
let remotePrefsUpdatedAt = settings.syncPreferencesUpdatedAt ? { ...settings.syncPreferencesUpdatedAt } : undefined;
|
|
88368
|
+
if (isSettingsSyncGroupEnabled(prefs, "gtd")) {
|
|
88369
|
+
remotePrefs.gtd = true;
|
|
88370
|
+
if (prefs.gtd === undefined) {
|
|
88371
|
+
const materializedAt = advanceLatestSyncTimestamp(remotePrefsUpdatedAt?.preferences, remotePrefsUpdatedAt?.gtd);
|
|
88372
|
+
if (materializedAt) {
|
|
88373
|
+
remotePrefsUpdatedAt = { ...remotePrefsUpdatedAt, preferences: materializedAt };
|
|
88374
|
+
}
|
|
88375
|
+
}
|
|
88376
|
+
}
|
|
87752
88377
|
const next = {
|
|
87753
|
-
syncPreferences:
|
|
87754
|
-
syncPreferencesUpdatedAt:
|
|
88378
|
+
syncPreferences: remotePrefs,
|
|
88379
|
+
syncPreferencesUpdatedAt: remotePrefsUpdatedAt
|
|
87755
88380
|
};
|
|
87756
88381
|
if (prefs.appearance === true) {
|
|
87757
88382
|
next.theme = settings.theme;
|
|
@@ -87870,6 +88495,56 @@ var MISSING_ATTACHMENT_TIMESTAMP_SENTINEL = "1970-01-01T00:00:00.000Z", normaliz
|
|
|
87870
88495
|
delete comparable[key];
|
|
87871
88496
|
}
|
|
87872
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 });
|
|
87873
88548
|
}, appendEntityRevisions = (parts, entities) => {
|
|
87874
88549
|
parts.push(String(entities?.length ?? 0));
|
|
87875
88550
|
for (const entity of entities ?? []) {
|
|
@@ -88321,6 +88996,17 @@ var hasOwnField2 = (value, field) => Object.prototype.hasOwnProperty.call(value,
|
|
|
88321
88996
|
sequentialWithinSectionProjectIds,
|
|
88322
88997
|
focusedProjectCount
|
|
88323
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;
|
|
88324
89010
|
}, computeTaskDerivedState = (tasks, tasksById) => {
|
|
88325
89011
|
const resolvedTasksById = tasksById ?? new Map;
|
|
88326
89012
|
const activeTasksByStatus = new Map;
|
|
@@ -88371,7 +89057,7 @@ var hasOwnField2 = (value, field) => Object.prototype.hasOwnProperty.call(value,
|
|
|
88371
89057
|
if (dateCoherenceIssues.length > 0) {
|
|
88372
89058
|
dateCoherenceIssuesByTaskId.set(task.id, dateCoherenceIssues);
|
|
88373
89059
|
}
|
|
88374
|
-
if (task
|
|
89060
|
+
if (isTaskCountedAsFocused(task)) {
|
|
88375
89061
|
focusedCount += 1;
|
|
88376
89062
|
focusedTasks.push(task);
|
|
88377
89063
|
}
|
|
@@ -88723,6 +89409,34 @@ async function runAttachmentTransferLifecycle(options) {
|
|
|
88723
89409
|
}
|
|
88724
89410
|
}
|
|
88725
89411
|
};
|
|
89412
|
+
const provePendingUploadIdentity = async (attachment, localPath) => {
|
|
89413
|
+
if (!options.createUploadSnapshot)
|
|
89414
|
+
return false;
|
|
89415
|
+
if (options.getLocalFileStat) {
|
|
89416
|
+
const candidateStat = await options.getLocalFileStat(localPath, attachment).catch(() => null);
|
|
89417
|
+
if (candidateStat)
|
|
89418
|
+
assertUploadStatAllowed(candidateStat);
|
|
89419
|
+
}
|
|
89420
|
+
const snapshot = await options.createUploadSnapshot(localPath, attachment);
|
|
89421
|
+
if (!snapshot)
|
|
89422
|
+
return false;
|
|
89423
|
+
try {
|
|
89424
|
+
const snapshotHash = snapshot.fileHash.trim().toLowerCase();
|
|
89425
|
+
if (!isSha256Hex(snapshotHash)) {
|
|
89426
|
+
options.onLocalEditRace?.(attachment);
|
|
89427
|
+
return false;
|
|
89428
|
+
}
|
|
89429
|
+
assertUploadStatAllowed(snapshot.stat);
|
|
89430
|
+
applyAttachmentContentStat(attachment, snapshot.stat, snapshotHash);
|
|
89431
|
+
return true;
|
|
89432
|
+
} finally {
|
|
89433
|
+
try {
|
|
89434
|
+
await snapshot.dispose();
|
|
89435
|
+
} catch (error2) {
|
|
89436
|
+
options.onUploadError(attachment, error2);
|
|
89437
|
+
}
|
|
89438
|
+
}
|
|
89439
|
+
};
|
|
88726
89440
|
for (const original of options.attachmentsById.values()) {
|
|
88727
89441
|
await options.beforeEachAttachment?.();
|
|
88728
89442
|
if (original.kind !== "file")
|
|
@@ -88752,6 +89466,17 @@ async function runAttachmentTransferLifecycle(options) {
|
|
|
88752
89466
|
itemMutated = true;
|
|
88753
89467
|
}
|
|
88754
89468
|
const mayReadForSync = existsLocally && (options.canUploadFrom?.(localPath, attachment) ?? true);
|
|
89469
|
+
if (hasPendingContentUpload && options.deferUploads && mayReadForSync && !isSha256Hex(attachment.fileHash)) {
|
|
89470
|
+
try {
|
|
89471
|
+
if (await provePendingUploadIdentity(attachment, localPath)) {
|
|
89472
|
+
itemMutated = true;
|
|
89473
|
+
}
|
|
89474
|
+
} catch (error2) {
|
|
89475
|
+
if (options.isFatalError?.(error2))
|
|
89476
|
+
throw error2;
|
|
89477
|
+
options.onUploadError(attachment, error2);
|
|
89478
|
+
}
|
|
89479
|
+
}
|
|
88755
89480
|
if (hasPendingContentUpload && !options.deferUploads) {
|
|
88756
89481
|
const expectedPendingHash = attachment.fileHash?.trim().toLowerCase();
|
|
88757
89482
|
if (!isSha256Hex(expectedPendingHash)) {
|
|
@@ -89544,6 +90269,7 @@ var normalizeAppData = (data) => ({
|
|
|
89544
90269
|
isFocused: normalizeSyncedBoolean(project.isFocused),
|
|
89545
90270
|
attachments: normalizeAttachmentsForSyncMerge(project.attachments),
|
|
89546
90271
|
dueDate: normalizeOptionalString2(project.dueDate),
|
|
90272
|
+
startDate: normalizeOptionalString2(project.startDate),
|
|
89547
90273
|
reviewAt: normalizeOptionalString2(project.reviewAt),
|
|
89548
90274
|
areaId: normalizeOptionalString2(project.areaId),
|
|
89549
90275
|
areaTitle: normalizeOptionalString2(project.areaTitle)
|
|
@@ -91750,6 +92476,23 @@ function createEmptyEntityStats(localTotal, incomingTotal) {
|
|
|
91750
92476
|
conflictSamples: []
|
|
91751
92477
|
};
|
|
91752
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
|
+
}
|
|
91753
92496
|
function mergeEntitiesWithStats(local, incoming, mergeConflict, normalizeForComparison, entityType = "entity", nowIso) {
|
|
91754
92497
|
const localMap = new Map(local.map((item) => [item.id, item]));
|
|
91755
92498
|
const incomingMap = new Map(incoming.map((item) => [item.id, item]));
|
|
@@ -92233,11 +92976,12 @@ function mergeAppDataWithStats(local, incoming, options = {}) {
|
|
|
92233
92976
|
const localRev = localAttachment.contentRev ?? 0;
|
|
92234
92977
|
const incomingRev = incomingAttachment.contentRev ?? 0;
|
|
92235
92978
|
const contentSource = localRev === incomingRev ? winner : localRev > incomingRev ? localAttachment : incomingAttachment;
|
|
92236
|
-
const fileHash = contentSource.fileHash || localAttachment.fileHash || incomingAttachment.fileHash;
|
|
92237
92979
|
const contentRev = contentSource.contentRev;
|
|
92980
|
+
const localPendingCandidateWon = localAttachment.pendingContentUpload === true && contentSource === localAttachment;
|
|
92981
|
+
const fileHash = localPendingCandidateWon ? localAttachment.fileHash : contentSource.fileHash || localAttachment.fileHash || incomingAttachment.fileHash;
|
|
92238
92982
|
const normalizedLocalFileHash = localAttachment.fileHash?.trim().toLowerCase();
|
|
92239
92983
|
const normalizedResolvedFileHash = fileHash?.trim().toLowerCase();
|
|
92240
|
-
const localIdentitySurvived = (contentRev ?? 0) === localRev && Boolean(normalizedLocalFileHash) && normalizedResolvedFileHash === normalizedLocalFileHash;
|
|
92984
|
+
const localIdentitySurvived = (contentRev ?? 0) === localRev && (Boolean(normalizedLocalFileHash) && normalizedResolvedFileHash === normalizedLocalFileHash || localPendingCandidateWon && !normalizedLocalFileHash && !normalizedResolvedFileHash);
|
|
92241
92985
|
const localPendingIdentitySurvived = localAttachment.pendingContentUpload === true && localIdentitySurvived;
|
|
92242
92986
|
const statSource = localIdentitySurvived ? localAttachment : contentSource;
|
|
92243
92987
|
return {
|
|
@@ -92299,7 +93043,7 @@ function mergeAppDataWithStats(local, incoming, options = {}) {
|
|
|
92299
93043
|
...attachment,
|
|
92300
93044
|
uri: safeUri ?? "",
|
|
92301
93045
|
cloudKey: resolveCloudKey(attachment, localFile, incomingFile),
|
|
92302
|
-
fileHash: attachment.deletedAt ? attachment.fileHash : attachment.fileHash || localFile?.fileHash || incomingFile?.fileHash,
|
|
93046
|
+
fileHash: attachment.deletedAt ? attachment.fileHash : attachment.pendingContentUpload === true ? attachment.fileHash : attachment.fileHash || localFile?.fileHash || incomingFile?.fileHash,
|
|
92303
93047
|
localStatus: attachment.deletedAt ? attachment.localStatus : uriAvailable ? attachment.localStatus ?? "available" : normalizeMissingFileStatus(attachment.localStatus, attachment.deletedAt)
|
|
92304
93048
|
};
|
|
92305
93049
|
});
|
|
@@ -92403,7 +93147,8 @@ async function performSyncCycleUnlocked(io) {
|
|
|
92403
93147
|
const remoteData = purgeExpiredTombstones(remoteDocument.data, nowIso, io.tombstoneRetentionDays).data;
|
|
92404
93148
|
io.onStep?.("merge");
|
|
92405
93149
|
await yieldToUi();
|
|
92406
|
-
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, {
|
|
92407
93152
|
nowIso,
|
|
92408
93153
|
preferIncomingAttachmentCloudKeys: io.preferIncomingAttachmentCloudKeys
|
|
92409
93154
|
});
|
|
@@ -92491,6 +93236,34 @@ async function performSyncCycleUnlocked(io) {
|
|
|
92491
93236
|
throw new Error(`Sync validation failed: ${sample}`);
|
|
92492
93237
|
}
|
|
92493
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
|
+
}
|
|
92494
93267
|
const finalDataWithPendingRemoteWrite = withPendingRemoteWriteFlag(finalData, pendingRemoteWriteMeta?.pendingAt ?? nowIso, pendingRemoteWriteMeta?.attempts);
|
|
92495
93268
|
io.onStep?.("write-local");
|
|
92496
93269
|
await yieldToUi();
|
|
@@ -94324,6 +95097,8 @@ var normalizeStarterTaskTitle = (title) => title.trim().toLowerCase(), STARTER_T
|
|
|
94324
95097
|
order: 0,
|
|
94325
95098
|
tagIds: [],
|
|
94326
95099
|
supportNotes: resolveStarterString(lang, STARTER_PROJECT_NOTES_KEY),
|
|
95100
|
+
isSequential: false,
|
|
95101
|
+
isFocused: false,
|
|
94327
95102
|
rev: 1,
|
|
94328
95103
|
...revisionMeta,
|
|
94329
95104
|
createdAt: nowIso,
|
|
@@ -94347,7 +95122,9 @@ var normalizeStarterTaskTitle = (title) => title.trim().toLowerCase(), STARTER_T
|
|
|
94347
95122
|
projectId,
|
|
94348
95123
|
order: index,
|
|
94349
95124
|
orderNum: index,
|
|
94350
|
-
isFocusedToday: template.isFocusedToday,
|
|
95125
|
+
isFocusedToday: template.isFocusedToday ?? false,
|
|
95126
|
+
suppressMindwtrReminders: false,
|
|
95127
|
+
pushCount: 0,
|
|
94351
95128
|
rev: 1,
|
|
94352
95129
|
...revisionMeta,
|
|
94353
95130
|
createdAt: nowIso,
|
|
@@ -94360,6 +95137,9 @@ var normalizeStarterTaskTitle = (title) => title.trim().toLowerCase(), STARTER_T
|
|
|
94360
95137
|
taskMode: "task",
|
|
94361
95138
|
tags: [],
|
|
94362
95139
|
contexts: [],
|
|
95140
|
+
isFocusedToday: false,
|
|
95141
|
+
suppressMindwtrReminders: false,
|
|
95142
|
+
pushCount: 0,
|
|
94363
95143
|
rev: 1,
|
|
94364
95144
|
...revisionMeta,
|
|
94365
95145
|
createdAt: nowIso,
|
|
@@ -94998,7 +95778,8 @@ var STORAGE_TIMEOUT_MS = 15000, SLOW_FETCH_LOG_THRESHOLD_MS = 1000, getFetchData
|
|
|
94998
95778
|
},
|
|
94999
95779
|
setHighlightTask: (id2) => {
|
|
95000
95780
|
set5({ highlightTaskId: id2, highlightTaskAt: id2 ? Date.now() : null });
|
|
95001
|
-
}
|
|
95781
|
+
},
|
|
95782
|
+
getFocusedCount: () => selectFocusedCount(get().tasks)
|
|
95002
95783
|
});
|
|
95003
95784
|
var init_store_settings = __esm(() => {
|
|
95004
95785
|
init_logger();
|
|
@@ -95251,17 +96032,22 @@ var createAreaActions = ({
|
|
|
95251
96032
|
const nextName = updates.name !== undefined ? updates.name.trim() : area.name;
|
|
95252
96033
|
let projectsChanged = false;
|
|
95253
96034
|
let newAllProjects = state._allProjects;
|
|
95254
|
-
|
|
95255
|
-
|
|
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()) {
|
|
95256
96039
|
newAllProjects = state._allProjects.map((project) => {
|
|
95257
96040
|
if (project.areaId !== id2)
|
|
95258
96041
|
return project;
|
|
95259
|
-
|
|
96042
|
+
const wantsColor = repaintColor && project.color !== nextAreaColor;
|
|
96043
|
+
const wantsTitle = project.areaTitle !== nextAreaTitle;
|
|
96044
|
+
if (!wantsColor && !wantsTitle)
|
|
95260
96045
|
return project;
|
|
95261
96046
|
projectsChanged = true;
|
|
95262
96047
|
return {
|
|
95263
96048
|
...project,
|
|
95264
|
-
color: nextAreaColor,
|
|
96049
|
+
...wantsColor ? { color: nextAreaColor } : {},
|
|
96050
|
+
...wantsTitle ? { areaTitle: nextAreaTitle } : {},
|
|
95265
96051
|
updatedAt: now3,
|
|
95266
96052
|
rev: nextRevision(project.rev),
|
|
95267
96053
|
revBy: deviceState.deviceId
|
|
@@ -95338,7 +96124,7 @@ var createAreaActions = ({
|
|
|
95338
96124
|
};
|
|
95339
96125
|
});
|
|
95340
96126
|
const newAllTasks = state._allTasks.map((task) => {
|
|
95341
|
-
if (task.areaId !== id2
|
|
96127
|
+
if (task.areaId !== id2)
|
|
95342
96128
|
return task;
|
|
95343
96129
|
return {
|
|
95344
96130
|
...task,
|
|
@@ -95665,6 +96451,7 @@ var duplicateProjectAttachmentCopy = (attachment, now3) => ({
|
|
|
95665
96451
|
color,
|
|
95666
96452
|
initialProps,
|
|
95667
96453
|
existingProjects,
|
|
96454
|
+
existingAreas,
|
|
95668
96455
|
settings,
|
|
95669
96456
|
deviceId,
|
|
95670
96457
|
now: now3,
|
|
@@ -95672,11 +96459,11 @@ var duplicateProjectAttachmentCopy = (attachment, now3) => ({
|
|
|
95672
96459
|
}) => {
|
|
95673
96460
|
const trimmedTitle = typeof title === "string" ? title.trim() : "";
|
|
95674
96461
|
const targetAreaId = initialProps?.areaId;
|
|
95675
|
-
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);
|
|
95676
96463
|
const baseOrder = Number.isFinite(initialProps?.order) ? initialProps?.order : maxOrder + 1;
|
|
95677
96464
|
const hasExplicitFlowMode = Boolean(initialProps && Object.prototype.hasOwnProperty.call(initialProps, "isSequential"));
|
|
95678
96465
|
const useSequentialDefault = !hasExplicitFlowMode && settings.gtd?.defaultProjectFlowMode === "sequential";
|
|
95679
|
-
|
|
96466
|
+
const project = {
|
|
95680
96467
|
id: id2 ?? generateUUID(),
|
|
95681
96468
|
title: trimmedTitle,
|
|
95682
96469
|
color: color ?? DEFAULT_PROJECT_COLOR,
|
|
@@ -95686,10 +96473,14 @@ var duplicateProjectAttachmentCopy = (attachment, now3) => ({
|
|
|
95686
96473
|
revBy: deviceId,
|
|
95687
96474
|
createdAt: now3,
|
|
95688
96475
|
updatedAt: now3,
|
|
96476
|
+
isSequential: false,
|
|
96477
|
+
isFocused: false,
|
|
95689
96478
|
...useSequentialDefault ? { isSequential: true } : {},
|
|
95690
96479
|
...initialProps,
|
|
95691
96480
|
tagIds: initialProps?.tagIds ?? []
|
|
95692
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 };
|
|
95693
96484
|
}, createProjectCoreActions = ({
|
|
95694
96485
|
set: set5,
|
|
95695
96486
|
get,
|
|
@@ -95718,6 +96509,7 @@ var duplicateProjectAttachmentCopy = (attachment, now3) => ({
|
|
|
95718
96509
|
color,
|
|
95719
96510
|
initialProps,
|
|
95720
96511
|
existingProjects: state._allProjects,
|
|
96512
|
+
existingAreas: state._allAreas,
|
|
95721
96513
|
settings: state.settings,
|
|
95722
96514
|
deviceId: deviceState.deviceId,
|
|
95723
96515
|
now: now3
|
|
@@ -96399,7 +97191,7 @@ var SLOW_TASK_UPDATE_LOG_THRESHOLD_MS = 500, collectAttachmentCloudKeysForTasks
|
|
|
96399
97191
|
const now3 = new Date().toISOString();
|
|
96400
97192
|
const projectOrderReserver = createProjectOrderReserver(currentState._allTasks);
|
|
96401
97193
|
const focusTaskLimit = normalizeFocusTaskLimit(currentState.settings.gtd?.focusTaskLimit);
|
|
96402
|
-
let focusedCount = currentState.
|
|
97194
|
+
let focusedCount = currentState.getFocusedCount();
|
|
96403
97195
|
const nextAllTasks = [...currentState._allTasks];
|
|
96404
97196
|
const newTasks = [];
|
|
96405
97197
|
for (const item of normalizedItems) {
|
|
@@ -96445,6 +97237,8 @@ var SLOW_TASK_UPDATE_LOG_THRESHOLD_MS = 500, collectAttachmentCloudKeysForTasks
|
|
|
96445
97237
|
updatedAt: now3,
|
|
96446
97238
|
deletedAt: undefined,
|
|
96447
97239
|
purgedAt: undefined,
|
|
97240
|
+
isFocusedToday: initialTaskProps.isFocusedToday ?? false,
|
|
97241
|
+
suppressMindwtrReminders: initialTaskProps.suppressMindwtrReminders ?? false,
|
|
96448
97242
|
...referenceClears,
|
|
96449
97243
|
areaId: resolvedAreaId,
|
|
96450
97244
|
projectId: resolvedProjectId,
|
|
@@ -96513,7 +97307,7 @@ var SLOW_TASK_UPDATE_LOG_THRESHOLD_MS = 500, collectAttachmentCloudKeysForTasks
|
|
|
96513
97307
|
const isPromotingTaskFocus = preparedUpdates.updates.isFocusedToday === true && existingTask.isFocusedToday !== true;
|
|
96514
97308
|
if (isPromotingTaskFocus) {
|
|
96515
97309
|
const focusTaskLimit = normalizeFocusTaskLimit(currentState.settings.gtd?.focusTaskLimit);
|
|
96516
|
-
const focusedCount = currentState.
|
|
97310
|
+
const focusedCount = currentState.getFocusedCount();
|
|
96517
97311
|
if (focusedCount >= focusTaskLimit) {
|
|
96518
97312
|
const message3 = `Focus limit of ${focusTaskLimit} reached`;
|
|
96519
97313
|
set5({ error: message3 });
|
|
@@ -96777,35 +97571,109 @@ var SLOW_TASK_UPDATE_LOG_THRESHOLD_MS = 500, collectAttachmentCloudKeysForTasks
|
|
|
96777
97571
|
return missingTask ? actionFail2("Task not found") : actionOk2({ id: duplicatedTaskId });
|
|
96778
97572
|
},
|
|
96779
97573
|
convertTaskToSection: async (id2) => {
|
|
96780
|
-
const
|
|
96781
|
-
if (!sourceTask || sourceTask.deletedAt)
|
|
96782
|
-
return actionFail2("Task not found");
|
|
96783
|
-
const projectId = sourceTask.projectId;
|
|
96784
|
-
if (!projectId)
|
|
96785
|
-
return actionFail2("Task is not in a project");
|
|
96786
|
-
const description = typeof sourceTask.description === "string" ? sourceTask.description.trim() : "";
|
|
96787
|
-
const section = await get().addSection(projectId, sourceTask.title, description ? { description } : undefined);
|
|
96788
|
-
if (!section)
|
|
96789
|
-
return actionFail2("Section could not be created");
|
|
97574
|
+
const changeAt = Date.now();
|
|
96790
97575
|
const now3 = new Date().toISOString();
|
|
96791
|
-
|
|
96792
|
-
|
|
96793
|
-
|
|
97576
|
+
let errorMessage;
|
|
97577
|
+
let convertedSectionId;
|
|
97578
|
+
set5((state) => {
|
|
97579
|
+
const sourceTask = state._tasksById.get(id2);
|
|
97580
|
+
if (!sourceTask || sourceTask.deletedAt) {
|
|
97581
|
+
errorMessage = "Task not found";
|
|
97582
|
+
return state;
|
|
97583
|
+
}
|
|
97584
|
+
const projectId = normalizeOptionalContainerId(sourceTask.projectId);
|
|
97585
|
+
if (!projectId) {
|
|
97586
|
+
errorMessage = "Task is not in a project";
|
|
97587
|
+
return state;
|
|
97588
|
+
}
|
|
97589
|
+
const projectExists = state._allProjects.some((project) => project.id === projectId && !project.deletedAt);
|
|
97590
|
+
const sectionTitle = typeof sourceTask.title === "string" ? sourceTask.title.trim() : "";
|
|
97591
|
+
if (!projectExists || !sectionTitle) {
|
|
97592
|
+
errorMessage = "Section could not be created";
|
|
97593
|
+
return state;
|
|
97594
|
+
}
|
|
97595
|
+
const deviceState = ensureDeviceId(state.settings);
|
|
97596
|
+
const sectionOrder = state._allSections.filter((section2) => section2.projectId === projectId && !section2.deletedAt).reduce((max3, section2) => Math.max(max3, Number.isFinite(section2.order) ? section2.order : -1), -1) + 1;
|
|
97597
|
+
const description = typeof sourceTask.description === "string" ? sourceTask.description.trim() : "";
|
|
97598
|
+
const section = {
|
|
97599
|
+
id: generateUUID(),
|
|
96794
97600
|
projectId,
|
|
96795
|
-
|
|
96796
|
-
|
|
96797
|
-
|
|
97601
|
+
title: sectionTitle,
|
|
97602
|
+
...description ? { description } : {},
|
|
97603
|
+
order: sectionOrder,
|
|
97604
|
+
isCollapsed: false,
|
|
97605
|
+
rev: 1,
|
|
97606
|
+
revBy: deviceState.deviceId,
|
|
97607
|
+
createdAt: now3,
|
|
97608
|
+
updatedAt: now3
|
|
97609
|
+
};
|
|
97610
|
+
const nextAllSections = [...state._allSections, section];
|
|
97611
|
+
const projectOrderReserver = createProjectOrderReserver(state._allTasks);
|
|
97612
|
+
const checklistTasks = [];
|
|
97613
|
+
for (const item of sourceTask.checklist || []) {
|
|
97614
|
+
const title = typeof item.title === "string" ? item.title.trim() : "";
|
|
97615
|
+
if (!title)
|
|
97616
|
+
continue;
|
|
97617
|
+
const containerResolution = resolveTaskContainerAssignment({
|
|
97618
|
+
projectId,
|
|
97619
|
+
sectionId: section.id,
|
|
97620
|
+
areaId: undefined,
|
|
97621
|
+
allProjects: state._allProjects,
|
|
97622
|
+
allSections: nextAllSections,
|
|
97623
|
+
allAreas: state._allAreas
|
|
97624
|
+
});
|
|
97625
|
+
if (!containerResolution.ok) {
|
|
97626
|
+
errorMessage = containerResolution.error;
|
|
97627
|
+
return state;
|
|
97628
|
+
}
|
|
97629
|
+
const order = projectOrderReserver(containerResolution.projectId);
|
|
97630
|
+
checklistTasks.push({
|
|
97631
|
+
id: generateUUID(),
|
|
97632
|
+
title,
|
|
97633
|
+
status: item.isCompleted ? "done" : "next",
|
|
97634
|
+
taskMode: "task",
|
|
97635
|
+
tags: [],
|
|
97636
|
+
contexts: [],
|
|
97637
|
+
pushCount: 0,
|
|
97638
|
+
projectId: containerResolution.projectId,
|
|
97639
|
+
sectionId: containerResolution.sectionId,
|
|
97640
|
+
areaId: containerResolution.areaId,
|
|
97641
|
+
...item.isCompleted ? { completedAt: now3 } : {},
|
|
97642
|
+
order,
|
|
97643
|
+
orderNum: order,
|
|
97644
|
+
rev: 1,
|
|
97645
|
+
revBy: deviceState.deviceId,
|
|
97646
|
+
createdAt: now3,
|
|
97647
|
+
updatedAt: now3
|
|
97648
|
+
});
|
|
96798
97649
|
}
|
|
96799
|
-
|
|
96800
|
-
|
|
96801
|
-
|
|
96802
|
-
|
|
96803
|
-
|
|
96804
|
-
|
|
96805
|
-
|
|
96806
|
-
|
|
96807
|
-
|
|
96808
|
-
|
|
97650
|
+
const deletedSource = {
|
|
97651
|
+
...sourceTask,
|
|
97652
|
+
deletedAt: now3,
|
|
97653
|
+
updatedAt: now3,
|
|
97654
|
+
rev: nextRevision(sourceTask.rev),
|
|
97655
|
+
revBy: deviceState.deviceId
|
|
97656
|
+
};
|
|
97657
|
+
const nextAllTasks = [
|
|
97658
|
+
...replaceEntityInArray(state._allTasks, deletedSource.id, deletedSource),
|
|
97659
|
+
...checklistTasks
|
|
97660
|
+
];
|
|
97661
|
+
convertedSectionId = section.id;
|
|
97662
|
+
persist(set5, debouncedSave, state, {
|
|
97663
|
+
tasks: nextAllTasks,
|
|
97664
|
+
sections: nextAllSections,
|
|
97665
|
+
...deviceState.updated ? { settings: deviceState.settings } : {}
|
|
97666
|
+
});
|
|
97667
|
+
return {
|
|
97668
|
+
_allTasks: nextAllTasks,
|
|
97669
|
+
_allSections: nextAllSections,
|
|
97670
|
+
lastDataChangeAt: getNextDataChangeAt(state.lastDataChangeAt, changeAt),
|
|
97671
|
+
...deviceState.updated ? { settings: deviceState.settings } : {}
|
|
97672
|
+
};
|
|
97673
|
+
});
|
|
97674
|
+
if (errorMessage)
|
|
97675
|
+
return actionFail2(errorMessage);
|
|
97676
|
+
return convertedSectionId ? actionOk2({ id: convertedSectionId }) : actionFail2("Task not found");
|
|
96809
97677
|
},
|
|
96810
97678
|
promoteTaskToProject: async (id2, options) => {
|
|
96811
97679
|
const changeAt = Date.now();
|
|
@@ -96850,6 +97718,7 @@ var SLOW_TASK_UPDATE_LOG_THRESHOLD_MS = 500, collectAttachmentCloudKeysForTasks
|
|
|
96850
97718
|
tagIds: projectTagIds
|
|
96851
97719
|
},
|
|
96852
97720
|
existingProjects: state._allProjects,
|
|
97721
|
+
existingAreas: state._allAreas,
|
|
96853
97722
|
settings: state.settings,
|
|
96854
97723
|
deviceId: deviceState.deviceId,
|
|
96855
97724
|
now: now3
|
|
@@ -98495,7 +99364,7 @@ var DEFAULT_ATTACHMENT_CLEANUP_INTERVAL_MS, CLOUD_PROVIDER_SELF_HOSTED = "selfho
|
|
|
98495
99364
|
return currentChangeAt;
|
|
98496
99365
|
onStale?.({ localSnapshotChangeAt, currentChangeAt });
|
|
98497
99366
|
requestFollowUp();
|
|
98498
|
-
throw new LocalSyncAbort;
|
|
99367
|
+
throw new LocalSyncAbort("local-data-changed");
|
|
98499
99368
|
}, getInMemoryAppDataSnapshot = () => {
|
|
98500
99369
|
const state = useTaskStore.getState();
|
|
98501
99370
|
return cloneAppData({
|
|
@@ -98576,9 +99445,11 @@ var init_sync_client_helpers = __esm(() => {
|
|
|
98576
99445
|
init_sync_runtime_utils();
|
|
98577
99446
|
DEFAULT_ATTACHMENT_CLEANUP_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
98578
99447
|
LocalSyncAbort = class LocalSyncAbort extends Error {
|
|
98579
|
-
|
|
99448
|
+
reason;
|
|
99449
|
+
constructor(reason = "local-data-changed") {
|
|
98580
99450
|
super("Local changes detected during sync");
|
|
98581
99451
|
this.name = "LocalSyncAbort";
|
|
99452
|
+
this.reason = reason;
|
|
98582
99453
|
}
|
|
98583
99454
|
};
|
|
98584
99455
|
});
|
|
@@ -100659,21 +101530,26 @@ function getSyncEncryptionStatusFromLocalState(localState) {
|
|
|
100659
101530
|
incompleteTransition: persisted.incompleteTransition
|
|
100660
101531
|
};
|
|
100661
101532
|
}
|
|
100662
|
-
function markRemoteEncryptionDiscovered(localState, discovered) {
|
|
101533
|
+
function markRemoteEncryptionDiscovered(localState, discovered, scope) {
|
|
100663
101534
|
const current = localState.read();
|
|
100664
101535
|
if (current && SYNC_ENCRYPTION_KEYED_STATES.includes(current.state) && current.discoveredSalt === bytesToHex(discovered.salt))
|
|
100665
101536
|
return;
|
|
100666
101537
|
localState.write({
|
|
100667
101538
|
state: "remote-encrypted-no-key",
|
|
100668
101539
|
discoveredSalt: bytesToHex(discovered.salt),
|
|
100669
|
-
discoveredParams: discovered.params
|
|
101540
|
+
discoveredParams: discovered.params,
|
|
101541
|
+
...scope ? { discoveredScope: scope } : {}
|
|
100670
101542
|
});
|
|
100671
101543
|
}
|
|
100672
|
-
function markRemotePlaintextDiscovered(localState) {
|
|
101544
|
+
function markRemotePlaintextDiscovered(localState, scope) {
|
|
100673
101545
|
const current = localState.read();
|
|
100674
101546
|
if (!current || current.state !== "enabled")
|
|
100675
101547
|
return;
|
|
100676
|
-
localState.write({
|
|
101548
|
+
localState.write({
|
|
101549
|
+
...current,
|
|
101550
|
+
state: "remote-plaintext",
|
|
101551
|
+
...scope ? { discoveredScope: scope } : {}
|
|
101552
|
+
});
|
|
100677
101553
|
}
|
|
100678
101554
|
function reaffirmRemoteEncryptionNoKey(localState) {
|
|
100679
101555
|
const current = localState.read();
|
|
@@ -101082,6 +101958,10 @@ async function runProvideSyncEncryptionPassphraseOverRemote(passphrase, baseDocu
|
|
|
101082
101958
|
const captured = await remote.read(encName);
|
|
101083
101959
|
const bytes = captured.bytes;
|
|
101084
101960
|
if (!bytes) {
|
|
101961
|
+
if (localState.read()?.state === "remote-encrypted-no-key") {
|
|
101962
|
+
await runDisableSyncEncryptionLocalOnly(keyCache, localState);
|
|
101963
|
+
return "no-encrypted-remote";
|
|
101964
|
+
}
|
|
101085
101965
|
throw new Error(`sync encryption: no encrypted remote artifact found at ${encName}`);
|
|
101086
101966
|
}
|
|
101087
101967
|
requireExistingRemoteVersion(encName, captured);
|
|
@@ -101117,7 +101997,42 @@ async function runProvideSyncEncryptionPassphraseOverRemote(passphrase, baseDocu
|
|
|
101117
101997
|
}
|
|
101118
101998
|
throw new SyncEncryptionRemoteConflictError(`${encName} changed during passphrase validation`);
|
|
101119
101999
|
}
|
|
101120
|
-
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) => {
|
|
101121
102036
|
const current = localState.read();
|
|
101122
102037
|
if (current?.incompleteTransition && current.incompleteTransition !== kind) {
|
|
101123
102038
|
throw new SyncEncryptionTransitionIncompleteError(current.incompleteTransition);
|
|
@@ -101193,6 +102108,7 @@ var SYNC_ENCRYPTION_KEYED_STATES, SYNC_ENCRYPTION_TRANSITION_INCOMPLETE = "SYNC_
|
|
|
101193
102108
|
}, PLAINTEXT_PAD_BYTE = 32, __syncEncryptionTestUtils;
|
|
101194
102109
|
var init_sync_encryption = __esm(() => {
|
|
101195
102110
|
init_sync_crypto();
|
|
102111
|
+
init_sync_helpers();
|
|
101196
102112
|
SYNC_ENCRYPTION_KEYED_STATES = ["enabled", "remote-plaintext"];
|
|
101197
102113
|
SyncEncryptionTransitionIncompleteError = class SyncEncryptionTransitionIncompleteError extends Error {
|
|
101198
102114
|
constructor(kind) {
|
|
@@ -101557,8 +102473,17 @@ async function webdavGetFileVersionedWithServerTime(url, options = {}) {
|
|
|
101557
102473
|
error2.status = res.status;
|
|
101558
102474
|
throw error2;
|
|
101559
102475
|
}
|
|
102476
|
+
let body;
|
|
102477
|
+
try {
|
|
102478
|
+
body = await readResponseBody(res, options.onProgress, options.maxBytes ?? MAX_DOWNLOAD_BYTES, signal);
|
|
102479
|
+
} catch (error2) {
|
|
102480
|
+
if (options.treatOversizeAsAbsent && error2 instanceof ResponseTooLargeError) {
|
|
102481
|
+
return { bytes: null, version: null, serverNowMs };
|
|
102482
|
+
}
|
|
102483
|
+
throw error2;
|
|
102484
|
+
}
|
|
101560
102485
|
return {
|
|
101561
|
-
bytes: new Uint8Array(
|
|
102486
|
+
bytes: new Uint8Array(body),
|
|
101562
102487
|
version: normalizeStrongWebdavEtag(res.headers.get("etag")),
|
|
101563
102488
|
serverNowMs
|
|
101564
102489
|
};
|
|
@@ -101593,7 +102518,14 @@ async function probeWebdavSyncCompatibility(documentUrl, options = {}, policy =
|
|
|
101593
102518
|
}
|
|
101594
102519
|
return "legacy-plaintext";
|
|
101595
102520
|
}
|
|
101596
|
-
|
|
102521
|
+
try {
|
|
102522
|
+
await assertWebdavConditionalWriteSupport(documentUrl, documentOptions);
|
|
102523
|
+
} catch (error2) {
|
|
102524
|
+
if (!policy.requireStrongEtag && error2 instanceof SyncEncryptionRemoteVersionUnavailableError) {
|
|
102525
|
+
return "legacy-plaintext";
|
|
102526
|
+
}
|
|
102527
|
+
throw error2;
|
|
102528
|
+
}
|
|
101597
102529
|
return "strong-etag";
|
|
101598
102530
|
}
|
|
101599
102531
|
async function assertWebdavStrongEtagSupport(documentUrl, options = {}) {
|
|
@@ -101789,15 +102721,18 @@ var WEBDAV_REMOTE_WRITE_CONFLICT = "WEBDAV_REMOTE_WRITE_CONFLICT", WebDavRemoteW
|
|
|
101789
102721
|
}
|
|
101790
102722
|
}, __webdavTestUtils, getWebdavParentCollectionUrl = (url) => {
|
|
101791
102723
|
try {
|
|
101792
|
-
const
|
|
101793
|
-
const
|
|
101794
|
-
const
|
|
101795
|
-
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)
|
|
101796
102728
|
return null;
|
|
101797
|
-
|
|
101798
|
-
|
|
101799
|
-
|
|
101800
|
-
|
|
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);
|
|
101801
102736
|
} catch {
|
|
101802
102737
|
return null;
|
|
101803
102738
|
}
|
|
@@ -102102,7 +103037,7 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102102
103037
|
if (!Number.isFinite(ttlMs) || ttlMs < MIN_TTL_MS || ttlMs > MAX_TTL_MS) {
|
|
102103
103038
|
throw new Error(`Remote sync mutation fence ttlMs must be between ${MIN_TTL_MS} and ${MAX_TTL_MS}`);
|
|
102104
103039
|
}
|
|
102105
|
-
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)));
|
|
102106
103041
|
if (!Number.isFinite(heartbeatMs) || heartbeatMs < 0 || heartbeatMs >= ttlMs) {
|
|
102107
103042
|
throw new Error("Remote sync mutation fence heartbeatMs must be zero or shorter than ttlMs");
|
|
102108
103043
|
}
|
|
@@ -102115,16 +103050,27 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102115
103050
|
throw new Error("Remote sync mutation fence leaseId is too short");
|
|
102116
103051
|
let acquiredVersion = null;
|
|
102117
103052
|
let acquiredRemainingMs = ttlMs;
|
|
103053
|
+
let reclaimedFrom = null;
|
|
102118
103054
|
for (let attempt = 0;attempt < maxAttempts; attempt += 1) {
|
|
102119
103055
|
const snapshot = await port.read();
|
|
102120
103056
|
const serverNowMs = requireServerNow(snapshot);
|
|
103057
|
+
reclaimedFrom = null;
|
|
102121
103058
|
if (snapshot.bytes) {
|
|
102122
103059
|
if (!snapshot.version) {
|
|
102123
103060
|
throw new SyncRemoteMutationFenceUnavailableError("Existing remote sync mutation fence has no safe version");
|
|
102124
103061
|
}
|
|
102125
103062
|
const current = parseRecord(snapshot.bytes);
|
|
102126
103063
|
if (current.expiresAt > serverNowMs && !isImpossibleFutureExpiry(current.expiresAt, serverNowMs)) {
|
|
102127
|
-
|
|
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;
|
|
102128
103074
|
}
|
|
102129
103075
|
} else if (snapshot.version !== null) {
|
|
102130
103076
|
throw new SyncRemoteMutationFenceUnavailableError("Missing remote sync mutation fence unexpectedly has a version");
|
|
@@ -102134,7 +103080,9 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102134
103080
|
leaseId,
|
|
102135
103081
|
ownerId,
|
|
102136
103082
|
purpose: options.purpose,
|
|
102137
|
-
expiresAt: serverNowMs + ttlMs
|
|
103083
|
+
expiresAt: serverNowMs + ttlMs,
|
|
103084
|
+
heartbeatMs,
|
|
103085
|
+
renewedAt: serverNowMs
|
|
102138
103086
|
};
|
|
102139
103087
|
try {
|
|
102140
103088
|
await port.write(encodeRecord(record3), snapshot.version);
|
|
@@ -102206,7 +103154,9 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102206
103154
|
leaseId,
|
|
102207
103155
|
ownerId,
|
|
102208
103156
|
purpose: options.purpose,
|
|
102209
|
-
expiresAt: serverNowMs + ttlMs
|
|
103157
|
+
expiresAt: serverNowMs + ttlMs,
|
|
103158
|
+
heartbeatMs,
|
|
103159
|
+
renewedAt: serverNowMs
|
|
102210
103160
|
};
|
|
102211
103161
|
try {
|
|
102212
103162
|
await port.write(encodeRecord(replacement), snapshot.version);
|
|
@@ -102248,6 +103198,7 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102248
103198
|
};
|
|
102249
103199
|
scheduleHeartbeat();
|
|
102250
103200
|
return {
|
|
103201
|
+
reclaimedFrom,
|
|
102251
103202
|
assertHeld: (minRemainingMs = 0) => serialize(async () => {
|
|
102252
103203
|
if (!Number.isFinite(minRemainingMs) || minRemainingMs < 0 || minRemainingMs >= ttlMs) {
|
|
102253
103204
|
throw new Error("Remote sync mutation fence remaining-time requirement is invalid");
|
|
@@ -102289,12 +103240,19 @@ async function acquireSyncRemoteMutationFence(port, options) {
|
|
|
102289
103240
|
})
|
|
102290
103241
|
};
|
|
102291
103242
|
}
|
|
102292
|
-
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) => {
|
|
102293
103244
|
if (snapshot.serverNowMs === null || !Number.isFinite(snapshot.serverNowMs)) {
|
|
102294
103245
|
throw new SyncRemoteMutationFenceUnavailableError("Remote sync mutation fencing requires a valid provider Date response header");
|
|
102295
103246
|
}
|
|
102296
103247
|
return snapshot.serverNowMs;
|
|
102297
|
-
}, 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) => {
|
|
102298
103256
|
if (bytes.length === 0 || bytes.length > MAX_RECORD_BYTES) {
|
|
102299
103257
|
throw new SyncRemoteMutationFenceUnavailableError("Remote sync mutation fence record is malformed");
|
|
102300
103258
|
}
|
|
@@ -102311,7 +103269,14 @@ var SYNC_REMOTE_MUTATION_FENCE_NAME = ".mindwtr-sync-fence-v1.json", SYNC_REMOTE
|
|
|
102311
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)) {
|
|
102312
103270
|
throw new SyncRemoteMutationFenceUnavailableError("Remote sync mutation fence record is malformed");
|
|
102313
103271
|
}
|
|
102314
|
-
|
|
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;
|
|
102315
103280
|
}, encodeRecord = (record3) => encodeUtf8(JSON.stringify(record3)), randomLeaseId = () => {
|
|
102316
103281
|
const randomUuid = globalThis.crypto?.randomUUID?.();
|
|
102317
103282
|
if (randomUuid)
|
|
@@ -102321,10 +103286,12 @@ var SYNC_REMOTE_MUTATION_FENCE_NAME = ".mindwtr-sync-fence-v1.json", SYNC_REMOTE
|
|
|
102321
103286
|
var init_sync_remote_fence = __esm(() => {
|
|
102322
103287
|
SyncRemoteMutationFenceBusyError = class SyncRemoteMutationFenceBusyError extends Error {
|
|
102323
103288
|
retryAfterMs;
|
|
102324
|
-
|
|
102325
|
-
|
|
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");
|
|
102326
103292
|
this.name = "SyncRemoteMutationFenceBusyError";
|
|
102327
103293
|
this.retryAfterMs = Math.max(0, Math.floor(retryAfterMs));
|
|
103294
|
+
this.holder = holder;
|
|
102328
103295
|
}
|
|
102329
103296
|
};
|
|
102330
103297
|
SyncRemoteMutationFenceLostError = class SyncRemoteMutationFenceLostError extends Error {
|
|
@@ -102355,6 +103322,7 @@ class SharedSyncRunMachine {
|
|
|
102355
103322
|
performSyncCycleImpl;
|
|
102356
103323
|
io = null;
|
|
102357
103324
|
remoteMutationFence = null;
|
|
103325
|
+
carriedIdleSnapshot = takeIdleCycleSnapshot();
|
|
102358
103326
|
state = {
|
|
102359
103327
|
backend: "off",
|
|
102360
103328
|
cloudProvider: "selfhosted",
|
|
@@ -102362,10 +103330,14 @@ class SharedSyncRunMachine {
|
|
|
102362
103330
|
fastSyncScope: null,
|
|
102363
103331
|
localSnapshotChangeAt: 0,
|
|
102364
103332
|
localDataCache: null,
|
|
103333
|
+
localSnapshotMatchesDisk: false,
|
|
103334
|
+
localDocumentFingerprint: null,
|
|
103335
|
+
fastSyncStateCache: null,
|
|
102365
103336
|
preSyncedLocalData: null,
|
|
102366
103337
|
wroteLocal: false,
|
|
102367
103338
|
remoteDataForCompare: null,
|
|
102368
103339
|
readCheckRemoteData: undefined,
|
|
103340
|
+
localOnlyUploadFingerprint: null,
|
|
102369
103341
|
lastRemoteWriteFingerprint: null,
|
|
102370
103342
|
lastRemoteWriteMergedServerData: false,
|
|
102371
103343
|
webdavRemoteCorrupted: false,
|
|
@@ -102431,10 +103403,14 @@ class SharedSyncRunMachine {
|
|
|
102431
103403
|
await this.runAttachmentPreSyncPhase();
|
|
102432
103404
|
}
|
|
102433
103405
|
let skipResult = null;
|
|
103406
|
+
let localOnlyUpload = false;
|
|
102434
103407
|
if (!this.options.activationProbe) {
|
|
102435
103408
|
skipResult = await this.trySkipUnchangedFastSync();
|
|
103409
|
+
if (!skipResult) {
|
|
103410
|
+
localOnlyUpload = await this.tryArmLocalOnlyUploadFastPath();
|
|
103411
|
+
}
|
|
102436
103412
|
}
|
|
102437
|
-
if (!this.options.activationProbe && !skipResult && this.policy.enableReadCheckSkip) {
|
|
103413
|
+
if (!this.options.activationProbe && !skipResult && !localOnlyUpload && this.policy.enableReadCheckSkip) {
|
|
102438
103414
|
skipResult = await this.trySkipUnchangedReadSync();
|
|
102439
103415
|
}
|
|
102440
103416
|
if (skipResult) {
|
|
@@ -102478,10 +103454,18 @@ class SharedSyncRunMachine {
|
|
|
102478
103454
|
const lease = await this.runRemoteMutationFenceOperation("Remote sync mutation fence acquisition failed", acquire);
|
|
102479
103455
|
if (!lease)
|
|
102480
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
|
+
}
|
|
102481
103461
|
this.remoteMutationFence = lease;
|
|
102482
103462
|
this.state.readCheckRemoteData = undefined;
|
|
102483
103463
|
this.state.remoteDataForCompare = null;
|
|
102484
103464
|
}
|
|
103465
|
+
async acquireAndAssertRemoteMutationFence(minRemainingMs) {
|
|
103466
|
+
await this.ensureRemoteMutationFence();
|
|
103467
|
+
await this.assertRemoteMutationFenceHeld(minRemainingMs);
|
|
103468
|
+
}
|
|
102485
103469
|
async assertRemoteMutationFenceHeld(minRemainingMs = SYNC_REMOTE_MUTATION_REQUEST_HORIZON_MS) {
|
|
102486
103470
|
if (!this.remoteMutationFence)
|
|
102487
103471
|
return;
|
|
@@ -102529,7 +103513,7 @@ class SharedSyncRunMachine {
|
|
|
102529
103513
|
attachmentHelpers(phase) {
|
|
102530
103514
|
return {
|
|
102531
103515
|
ensureLocalSnapshotFresh: () => this.ensureLocalSnapshotFresh(),
|
|
102532
|
-
assertRemoteMutationFenceHeld: (minRemainingMs) => this.
|
|
103516
|
+
assertRemoteMutationFenceHeld: (minRemainingMs) => this.acquireAndAssertRemoteMutationFence(minRemainingMs),
|
|
102533
103517
|
activationProbe: this.options.activationProbe === true,
|
|
102534
103518
|
phase
|
|
102535
103519
|
};
|
|
@@ -102565,15 +103549,38 @@ class SharedSyncRunMachine {
|
|
|
102565
103549
|
this.state.localSnapshotChangeAt = currentChangeAt;
|
|
102566
103550
|
return this.state.localDataCache.data;
|
|
102567
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
|
+
}
|
|
102568
103565
|
const inMemorySnapshot = this.store.getInMemorySnapshot();
|
|
102569
103566
|
let baseData;
|
|
103567
|
+
let matchesDisk = false;
|
|
102570
103568
|
if (this.state.preSyncedLocalData) {
|
|
102571
|
-
|
|
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
|
+
});
|
|
102572
103578
|
} else {
|
|
102573
103579
|
const persisted = await this.storage.readPersistedLocal();
|
|
102574
103580
|
const reconcileStart = Date.now();
|
|
102575
103581
|
const aligned = computeSyncChangeFingerprint(persisted) === computeSyncChangeFingerprint(inMemorySnapshot);
|
|
102576
103582
|
baseData = aligned ? persisted : mergeAppData(persisted, inMemorySnapshot);
|
|
103583
|
+
matchesDisk = aligned;
|
|
102577
103584
|
this.notifier.logInfo("Sync local reconcile", {
|
|
102578
103585
|
reconcile: aligned ? "aligned-skip" : "merged",
|
|
102579
103586
|
durationMs: String(Date.now() - reconcileStart),
|
|
@@ -102586,12 +103593,14 @@ class SharedSyncRunMachine {
|
|
|
102586
103593
|
changeAt: currentChangeAt,
|
|
102587
103594
|
data
|
|
102588
103595
|
};
|
|
103596
|
+
this.state.localSnapshotMatchesDisk = matchesDisk && data === baseData;
|
|
102589
103597
|
return data;
|
|
102590
103598
|
}
|
|
102591
103599
|
async persistLocalDataWithTracking(data) {
|
|
102592
103600
|
await this.assertRemoteMutationFenceHeld();
|
|
102593
103601
|
const persisted = await this.storage.persistLocal(data) ?? data;
|
|
102594
103602
|
this.ensureLocalSnapshotFresh(persisted);
|
|
103603
|
+
this.state.localSnapshotMatchesDisk = false;
|
|
102595
103604
|
if (this.storage.applyDataToStore) {
|
|
102596
103605
|
this.storage.applyDataToStore(persisted);
|
|
102597
103606
|
const currentChangeAt = this.store.getLastDataChangeAt();
|
|
@@ -102622,6 +103631,10 @@ class SharedSyncRunMachine {
|
|
|
102622
103631
|
this.state.remoteDataForCompare = data;
|
|
102623
103632
|
return data;
|
|
102624
103633
|
}
|
|
103634
|
+
if (this.state.localOnlyUploadFingerprint) {
|
|
103635
|
+
this.state.remoteDataForCompare = null;
|
|
103636
|
+
return null;
|
|
103637
|
+
}
|
|
102625
103638
|
await this.ensureNetwork();
|
|
102626
103639
|
try {
|
|
102627
103640
|
const raw = await this.requireIo().readRemote();
|
|
@@ -102652,7 +103665,23 @@ class SharedSyncRunMachine {
|
|
|
102652
103665
|
return null;
|
|
102653
103666
|
return io.readRemoteFingerprint();
|
|
102654
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
|
+
}
|
|
102655
103683
|
async writeRemoteForCycle(data) {
|
|
103684
|
+
this.assertLocalOnlyUploadIsCanonical(data);
|
|
102656
103685
|
await this.ensureRemoteMutationFence();
|
|
102657
103686
|
await this.assertRemoteMutationFenceHeld();
|
|
102658
103687
|
await this.ensureNetwork();
|
|
@@ -102686,7 +103715,7 @@ class SharedSyncRunMachine {
|
|
|
102686
103715
|
} catch (error2) {
|
|
102687
103716
|
if (error2 instanceof SyncRemoteWriteConflict) {
|
|
102688
103717
|
this.requestFollowUp();
|
|
102689
|
-
throw new LocalSyncAbort;
|
|
103718
|
+
throw new LocalSyncAbort("remote-write-conflict");
|
|
102690
103719
|
}
|
|
102691
103720
|
throw error2;
|
|
102692
103721
|
}
|
|
@@ -102736,8 +103765,8 @@ class SharedSyncRunMachine {
|
|
|
102736
103765
|
this.ensureLocalSnapshotFresh();
|
|
102737
103766
|
if (hasPendingSyncSideEffects(localData))
|
|
102738
103767
|
return null;
|
|
102739
|
-
const localFingerprint =
|
|
102740
|
-
const cached2 = await this.
|
|
103768
|
+
const localFingerprint = this.localDocumentFingerprint(localData);
|
|
103769
|
+
const cached2 = await this.readFastSyncState(scope);
|
|
102741
103770
|
if (!cached2 || cached2.localFingerprint !== localFingerprint)
|
|
102742
103771
|
return null;
|
|
102743
103772
|
let remoteFingerprint = null;
|
|
@@ -102750,16 +103779,64 @@ class SharedSyncRunMachine {
|
|
|
102750
103779
|
if (!remoteFingerprint || remoteFingerprint !== cached2.remoteFingerprint)
|
|
102751
103780
|
return null;
|
|
102752
103781
|
this.ensureLocalSnapshotFresh();
|
|
102753
|
-
await this.
|
|
103782
|
+
await this.writeFastSyncState({
|
|
102754
103783
|
scope,
|
|
102755
103784
|
localFingerprint,
|
|
102756
103785
|
remoteFingerprint,
|
|
102757
103786
|
checkedAt: this.nowIso()
|
|
102758
103787
|
});
|
|
102759
103788
|
await this.persistUnchangedSyncStatus();
|
|
103789
|
+
this.publishIdleCycleSnapshot(localData, localFingerprint);
|
|
102760
103790
|
this.notifier.logInfo("Sync fast check found no changes", { backend: this.backend });
|
|
103791
|
+
this.logUnchangedCycleSkips("fast");
|
|
102761
103792
|
return { success: true, skipped: "unchanged" };
|
|
102762
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
|
+
}
|
|
102763
103840
|
async trySkipUnchangedReadSync() {
|
|
102764
103841
|
this.setStep("read-check");
|
|
102765
103842
|
await this.yieldToUi();
|
|
@@ -102776,14 +103853,16 @@ class SharedSyncRunMachine {
|
|
|
102776
103853
|
this.state.readCheckRemoteData = remoteData;
|
|
102777
103854
|
if (hasUncompactedPurgedTombstones(remoteData))
|
|
102778
103855
|
return null;
|
|
102779
|
-
const
|
|
102780
|
-
const
|
|
102781
|
-
if (
|
|
103856
|
+
const localFingerprint = this.localDocumentFingerprint(localData);
|
|
103857
|
+
const remoteFingerprint = computeRemoteSyncDocumentFingerprint(toRemoteSyncDocument(remoteData));
|
|
103858
|
+
if (localFingerprint !== remoteFingerprint)
|
|
102782
103859
|
return null;
|
|
102783
103860
|
await this.recordFastSyncState(localData, { allowRemoteFingerprintRead: false });
|
|
102784
103861
|
await this.persistUnchangedSyncStatus();
|
|
103862
|
+
this.publishIdleCycleSnapshot(localData, localFingerprint);
|
|
102785
103863
|
this.state.readCheckRemoteData = undefined;
|
|
102786
103864
|
this.notifier.logInfo("Sync read check found no changes", { backend: this.backend });
|
|
103865
|
+
this.logUnchangedCycleSkips("read");
|
|
102787
103866
|
return { success: true, skipped: "unchanged" };
|
|
102788
103867
|
}
|
|
102789
103868
|
async recordFastSyncState(data, options = {}) {
|
|
@@ -102810,13 +103889,71 @@ class SharedSyncRunMachine {
|
|
|
102810
103889
|
}
|
|
102811
103890
|
if (!remoteFingerprint)
|
|
102812
103891
|
return;
|
|
102813
|
-
await this.
|
|
103892
|
+
await this.writeFastSyncState({
|
|
102814
103893
|
scope,
|
|
102815
|
-
localFingerprint:
|
|
103894
|
+
localFingerprint: this.localDocumentFingerprint(data),
|
|
102816
103895
|
remoteFingerprint,
|
|
102817
103896
|
checkedAt: this.nowIso()
|
|
102818
103897
|
});
|
|
102819
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
|
+
}
|
|
102820
103957
|
async runAttachmentPreSyncPhase() {
|
|
102821
103958
|
if (!this.policy.attachmentPhasesEnabled || this.options.activationProbe)
|
|
102822
103959
|
return;
|
|
@@ -102833,7 +103970,6 @@ class SharedSyncRunMachine {
|
|
|
102833
103970
|
if (isRemoteSyncBackend(this.backend)) {
|
|
102834
103971
|
await this.ensureNetwork();
|
|
102835
103972
|
}
|
|
102836
|
-
await this.ensureRemoteMutationFence();
|
|
102837
103973
|
const result = await io.syncAttachments(localData, this.attachmentHelpers("prepare"));
|
|
102838
103974
|
await this.assertRemoteMutationFenceHeld();
|
|
102839
103975
|
const mutated = result === true || Boolean(result) && typeof result === "object";
|
|
@@ -102865,7 +104001,7 @@ class SharedSyncRunMachine {
|
|
|
102865
104001
|
}
|
|
102866
104002
|
async prepareRemoteWriteData(data) {
|
|
102867
104003
|
if (this.options.activationProbe) {
|
|
102868
|
-
const activationSnapshot = prepareActivationAttachmentSnapshot(data, this.state.remoteDataForCompare);
|
|
104004
|
+
const activationSnapshot = prepareActivationAttachmentSnapshot(data, this.state.remoteDataForCompare, this.state.localDataCache?.data ?? null);
|
|
102869
104005
|
if (activationSnapshot.count === 0)
|
|
102870
104006
|
return data;
|
|
102871
104007
|
const io2 = this.requireIo();
|
|
@@ -102878,15 +104014,25 @@ class SharedSyncRunMachine {
|
|
|
102878
104014
|
await this.ensureNetwork();
|
|
102879
104015
|
}
|
|
102880
104016
|
await this.ensureRemoteMutationFence();
|
|
102881
|
-
|
|
104017
|
+
let result2 = await io2.syncAttachments(activationSnapshot.data, this.attachmentHelpers("post-merge"));
|
|
102882
104018
|
await this.assertRemoteMutationFenceHeld();
|
|
102883
|
-
|
|
102884
|
-
|
|
104019
|
+
let provenData = result2 && typeof result2 === "object" ? result2 : activationSnapshot.data;
|
|
104020
|
+
this.ensureLocalSnapshotFresh();
|
|
104021
|
+
const fallbackRetry = prepareActivationFallbackRetry(provenData, activationSnapshot.localFallbacks);
|
|
104022
|
+
if (fallbackRetry.count > 0) {
|
|
104023
|
+
result2 = await io2.syncAttachments(fallbackRetry.data, this.attachmentHelpers("post-merge"));
|
|
104024
|
+
await this.assertRemoteMutationFenceHeld();
|
|
104025
|
+
provenData = result2 && typeof result2 === "object" ? result2 : fallbackRetry.data;
|
|
104026
|
+
}
|
|
104027
|
+
assertActivationAttachmentsProven(provenData, activationSnapshot.expectedIds, activationSnapshot.metadataOnlyIds, activationSnapshot.noLocalBytesIds);
|
|
102885
104028
|
this.ensureLocalSnapshotFresh();
|
|
102886
104029
|
this.notifier.onDiagnostic?.({
|
|
102887
104030
|
event: "attachments-prepare-complete",
|
|
102888
104031
|
data: provenData,
|
|
102889
|
-
extra: {
|
|
104032
|
+
extra: {
|
|
104033
|
+
mutated: String(result2 === true || Boolean(result2 && typeof result2 === "object")),
|
|
104034
|
+
fallbackRetries: String(fallbackRetry.count)
|
|
104035
|
+
}
|
|
102890
104036
|
});
|
|
102891
104037
|
return provenData;
|
|
102892
104038
|
}
|
|
@@ -103010,6 +104156,19 @@ class SharedSyncRunMachine {
|
|
|
103010
104156
|
});
|
|
103011
104157
|
},
|
|
103012
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
|
+
},
|
|
103013
104172
|
prepareRemoteWrite: (data) => this.prepareRemoteWriteData(data),
|
|
103014
104173
|
writeRemote: async (data) => {
|
|
103015
104174
|
this.notifier.tracePayload?.("write-remote", data, { backend: this.backend });
|
|
@@ -103017,6 +104176,7 @@ class SharedSyncRunMachine {
|
|
|
103017
104176
|
await this.writeRemoteForCycle(data);
|
|
103018
104177
|
},
|
|
103019
104178
|
preferIncomingAttachmentCloudKeys: this.options.ignorePendingRemoteWriteBackoff === true,
|
|
104179
|
+
skipEmptyRemoteMerge: () => this.state.localOnlyUploadFingerprint !== null,
|
|
103020
104180
|
onStep: (next) => this.setStep(next),
|
|
103021
104181
|
yieldToUi: this.notifier.yieldToUi ? () => this.notifier.yieldToUi() : undefined,
|
|
103022
104182
|
historyContext: {
|
|
@@ -103103,9 +104263,11 @@ class SharedSyncRunMachine {
|
|
|
103103
104263
|
await this.yieldToUi();
|
|
103104
104264
|
this.ensureLocalSnapshotFresh(mergedData);
|
|
103105
104265
|
await this.assertRemoteMutationFenceHeld();
|
|
104266
|
+
const localWriteSkipped = syncResult.localWriteSkipped && !this.state.wroteLocal ? true : undefined;
|
|
103106
104267
|
await this.hooks.finalizeSuccess(mergedData, {
|
|
103107
104268
|
status: syncResult.status,
|
|
103108
104269
|
wroteLocal: this.state.wroteLocal,
|
|
104270
|
+
localWriteSkipped,
|
|
103109
104271
|
getLocalSnapshotChangeAt: () => this.state.localSnapshotChangeAt,
|
|
103110
104272
|
acceptCoveredSnapshot: (expectedData) => this.acceptCoveredLocalSnapshot(expectedData)
|
|
103111
104273
|
});
|
|
@@ -103117,6 +104279,7 @@ class SharedSyncRunMachine {
|
|
|
103117
104279
|
attachmentWriteDeferred: attachmentWriteDeferred || undefined,
|
|
103118
104280
|
fileAttachmentUploadBlocked: this.state.fileAttachmentUploadBlocked ?? undefined,
|
|
103119
104281
|
error: mergedData.settings.lastSyncError,
|
|
104282
|
+
localWriteSkipped,
|
|
103120
104283
|
stats
|
|
103121
104284
|
};
|
|
103122
104285
|
}
|
|
@@ -103124,6 +104287,7 @@ class SharedSyncRunMachine {
|
|
|
103124
104287
|
success: true,
|
|
103125
104288
|
attachmentWriteDeferred: attachmentWriteDeferred || undefined,
|
|
103126
104289
|
fileAttachmentUploadBlocked: this.state.fileAttachmentUploadBlocked ?? undefined,
|
|
104290
|
+
localWriteSkipped,
|
|
103127
104291
|
stats
|
|
103128
104292
|
};
|
|
103129
104293
|
}
|
|
@@ -103149,6 +104313,7 @@ class SharedSyncRunMachine {
|
|
|
103149
104313
|
};
|
|
103150
104314
|
}
|
|
103151
104315
|
if (error2 instanceof SyncRemoteMutationFenceBusyError) {
|
|
104316
|
+
this.notifier.logWarning("Remote sync location is reserved; retrying after the lease lapses", error2);
|
|
103152
104317
|
if (!this.options.activationProbe)
|
|
103153
104318
|
this.requestFollowUpAfter(error2.retryAfterMs);
|
|
103154
104319
|
return {
|
|
@@ -103170,6 +104335,12 @@ class SharedSyncRunMachine {
|
|
|
103170
104335
|
if (!this.options.activationProbe) {
|
|
103171
104336
|
await this.persistPreSyncedDataAfterAbort();
|
|
103172
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
|
+
});
|
|
103173
104344
|
this.notifier.onDiagnostic?.({
|
|
103174
104345
|
event: "requeued",
|
|
103175
104346
|
extra: {
|
|
@@ -103252,7 +104423,28 @@ var normalizeRemoteWriteResult = (source, result) => {
|
|
|
103252
104423
|
fingerprint,
|
|
103253
104424
|
serverMergedRemoteData: result.serverMergedRemoteData === true
|
|
103254
104425
|
};
|
|
103255
|
-
}, 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) => {
|
|
103256
104448
|
if (!data.settings.pendingRemoteWriteAt && data.settings.pendingRemoteWriteRetryAt === undefined && data.settings.pendingRemoteWriteAttempts === undefined) {
|
|
103257
104449
|
return data;
|
|
103258
104450
|
}
|
|
@@ -103296,17 +104488,60 @@ var normalizeRemoteWriteResult = (source, result) => {
|
|
|
103296
104488
|
if (!merged.fileHash || !candidate.fileHash)
|
|
103297
104489
|
return false;
|
|
103298
104490
|
return merged.fileHash.toLowerCase() !== candidate.fileHash.toLowerCase();
|
|
103299
|
-
},
|
|
104491
|
+
}, normalizeAttachmentHash = (value) => value?.trim().toLowerCase() ?? "", buildExactLocalActivationFallback = (merged, local, candidate) => {
|
|
104492
|
+
if (!local || !candidate?.cloudKey)
|
|
104493
|
+
return null;
|
|
104494
|
+
const localUri = local.uri?.trim();
|
|
104495
|
+
const localHash = normalizeAttachmentHash(local.fileHash);
|
|
104496
|
+
const mergedHash = normalizeAttachmentHash(merged.fileHash);
|
|
104497
|
+
const candidateHash = normalizeAttachmentHash(candidate.fileHash);
|
|
104498
|
+
if (!localUri || local.localStatus === "missing" || !localHash || localHash !== mergedHash || localHash !== candidateHash || (local.contentRev ?? 0) !== (merged.contentRev ?? 0) || (local.contentRev ?? 0) !== (candidate.contentRev ?? 0)) {
|
|
104499
|
+
return null;
|
|
104500
|
+
}
|
|
104501
|
+
return {
|
|
104502
|
+
...merged,
|
|
104503
|
+
uri: local.uri,
|
|
104504
|
+
cloudKey: undefined,
|
|
104505
|
+
fileHash: merged.fileHash,
|
|
104506
|
+
contentMtimeMs: local.contentMtimeMs,
|
|
104507
|
+
contentSize: local.contentSize,
|
|
104508
|
+
localStatus: "available",
|
|
104509
|
+
pendingContentUpload: true,
|
|
104510
|
+
deletedAt: undefined
|
|
104511
|
+
};
|
|
104512
|
+
}, prepareActivationAttachmentSnapshot = (data, candidateRemoteData, localData) => {
|
|
103300
104513
|
const candidateAttachments = new Map;
|
|
103301
104514
|
if (candidateRemoteData) {
|
|
103302
104515
|
visitLiveFileAttachments(candidateRemoteData, (attachment) => {
|
|
103303
104516
|
candidateAttachments.set(attachment.id, attachment);
|
|
103304
104517
|
});
|
|
103305
104518
|
}
|
|
104519
|
+
const localAttachments = new Map;
|
|
104520
|
+
if (localData) {
|
|
104521
|
+
visitLiveFileAttachments(localData, (attachment) => {
|
|
104522
|
+
localAttachments.set(attachment.id, attachment);
|
|
104523
|
+
});
|
|
104524
|
+
}
|
|
103306
104525
|
const candidate = cloneAppData(data);
|
|
104526
|
+
const expectedIds = new Set;
|
|
104527
|
+
const localFallbacks = new Map;
|
|
104528
|
+
const metadataOnlyIds = new Set;
|
|
104529
|
+
const noLocalBytesIds = new Set;
|
|
103307
104530
|
const count = visitLiveFileAttachments(candidate, (attachment) => {
|
|
104531
|
+
expectedIds.add(attachment.id);
|
|
103308
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);
|
|
103309
104539
|
const mustReplaceCandidateBlob = Boolean(candidateAttachment?.cloudKey && mergedContentMustReplaceCandidateBlob(attachment, candidateAttachment));
|
|
104540
|
+
if (!mustReplaceCandidateBlob) {
|
|
104541
|
+
const fallback = buildExactLocalActivationFallback(attachment, localAttachments.get(attachment.id), candidateAttachment);
|
|
104542
|
+
if (fallback)
|
|
104543
|
+
localFallbacks.set(attachment.id, fallback);
|
|
104544
|
+
}
|
|
103310
104545
|
attachment.cloudKey = candidateAttachment?.cloudKey;
|
|
103311
104546
|
attachment.pendingContentUpload = mustReplaceCandidateBlob ? true : undefined;
|
|
103312
104547
|
if (candidateAttachment?.cloudKey && !mustReplaceCandidateBlob) {
|
|
@@ -103314,17 +104549,55 @@ var normalizeRemoteWriteResult = (source, result) => {
|
|
|
103314
104549
|
}
|
|
103315
104550
|
attachment.localStatus = "missing";
|
|
103316
104551
|
});
|
|
103317
|
-
return { data: candidate, count };
|
|
103318
|
-
},
|
|
103319
|
-
|
|
103320
|
-
|
|
103321
|
-
|
|
103322
|
-
|
|
103323
|
-
|
|
103324
|
-
|
|
103325
|
-
|
|
103326
|
-
|
|
103327
|
-
|
|
104552
|
+
return { data: candidate, count, expectedIds, localFallbacks, metadataOnlyIds, noLocalBytesIds };
|
|
104553
|
+
}, prepareActivationFallbackRetry = (data, localFallbacks) => {
|
|
104554
|
+
if (localFallbacks.size === 0)
|
|
104555
|
+
return { data, count: 0 };
|
|
104556
|
+
const retryData = cloneAppData(data);
|
|
104557
|
+
let count = 0;
|
|
104558
|
+
for (const owner of [...retryData.tasks, ...retryData.projects]) {
|
|
104559
|
+
if (owner.deletedAt)
|
|
104560
|
+
continue;
|
|
104561
|
+
for (const attachment of owner.attachments ?? []) {
|
|
104562
|
+
if (attachment.kind !== "file" || !attachment.deletedAt)
|
|
104563
|
+
continue;
|
|
104564
|
+
const fallback = localFallbacks.get(attachment.id);
|
|
104565
|
+
if (!fallback)
|
|
104566
|
+
continue;
|
|
104567
|
+
Object.assign(attachment, fallback);
|
|
104568
|
+
count += 1;
|
|
104569
|
+
}
|
|
104570
|
+
}
|
|
104571
|
+
return count > 0 ? { data: retryData, count } : { data, count: 0 };
|
|
104572
|
+
}, assertActivationAttachmentsProven = (data, expectedIds, metadataOnlyIds, noLocalBytesIds) => {
|
|
104573
|
+
const resolved = new Set;
|
|
104574
|
+
for (const owner of [...data.tasks, ...data.projects]) {
|
|
104575
|
+
for (const attachment of owner.attachments ?? []) {
|
|
104576
|
+
if (attachment.kind !== "file")
|
|
104577
|
+
continue;
|
|
104578
|
+
if (owner.deletedAt || attachment.deletedAt) {
|
|
104579
|
+
if (expectedIds.has(attachment.id)) {
|
|
104580
|
+
if (!noLocalBytesIds.has(attachment.id)) {
|
|
104581
|
+
throw new Error(`Candidate attachment proof failed for ${attachment.id}`);
|
|
104582
|
+
}
|
|
104583
|
+
resolved.add(attachment.id);
|
|
104584
|
+
}
|
|
104585
|
+
continue;
|
|
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
|
+
}
|
|
104592
|
+
if (!attachment.cloudKey || attachment.localStatus !== "available" || attachment.pendingContentUpload === true) {
|
|
104593
|
+
throw new Error(`Candidate attachment proof failed for ${attachment.id}`);
|
|
104594
|
+
}
|
|
104595
|
+
if (expectedIds.has(attachment.id))
|
|
104596
|
+
resolved.add(attachment.id);
|
|
104597
|
+
}
|
|
104598
|
+
}
|
|
104599
|
+
if (resolved.size !== expectedIds.size) {
|
|
104600
|
+
throw new Error(`Candidate attachment proof incomplete: expected ${expectedIds.size}, proved ${resolved.size}`);
|
|
103328
104601
|
}
|
|
103329
104602
|
}, runSharedSyncCycle = async (ports) => {
|
|
103330
104603
|
return new SharedSyncRunMachine(ports).run();
|
|
@@ -103988,8 +105261,19 @@ var DROPBOX_SYNC_PATH = "/data.json", DOWNLOAD_ENDPOINT = "https://content.dropb
|
|
|
103988
105261
|
throw new Error(`Dropbox download failed: HTTP ${response.status}`);
|
|
103989
105262
|
}
|
|
103990
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
|
+
};
|
|
103991
105274
|
};
|
|
103992
105275
|
var init_dropbox = __esm(() => {
|
|
105276
|
+
init_attachment_paths();
|
|
103993
105277
|
init_dropbox_sync_utils();
|
|
103994
105278
|
init_http_utils();
|
|
103995
105279
|
init_sync_encryption();
|
|
@@ -104013,6 +105297,7 @@ var init_dropbox = __esm(() => {
|
|
|
104013
105297
|
this.name = "DropboxFileNotFoundError";
|
|
104014
105298
|
}
|
|
104015
105299
|
};
|
|
105300
|
+
DROPBOX_ATTACHMENTS_PATH = `/${ATTACHMENTS_DIR_NAME}`;
|
|
104016
105301
|
});
|
|
104017
105302
|
|
|
104018
105303
|
// ../../packages/core/src/sync-backend-io.ts
|
|
@@ -104056,6 +105341,28 @@ function createSyncBackendIO(ctx, transport) {
|
|
|
104056
105341
|
},
|
|
104057
105342
|
getSyncUrl: () => ctx.syncUrl,
|
|
104058
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
|
+
},
|
|
104059
105366
|
readRemote: async () => {
|
|
104060
105367
|
if (ctx.backend === "cloudkit") {
|
|
104061
105368
|
return transport.cloudKitRead();
|
|
@@ -104069,6 +105376,9 @@ function createSyncBackendIO(ctx, transport) {
|
|
|
104069
105376
|
const remote2 = await transport.webdavGet();
|
|
104070
105377
|
webdavDocumentVersion = { exists: remote2.exists, strongEtag: remote2.strongEtag };
|
|
104071
105378
|
webdavDocumentSnapshot = snapshotWebdavRead(remote2);
|
|
105379
|
+
if (ctx.syncEncryptionOff && !ctx.allowLegacyWebdavPlaintext && remote2.exists && !remote2.strongEtag) {
|
|
105380
|
+
ctx.allowLegacyWebdavPlaintext = true;
|
|
105381
|
+
}
|
|
104072
105382
|
return remote2.data;
|
|
104073
105383
|
} catch (error2) {
|
|
104074
105384
|
webdavDocumentVersion = getWebdavDocumentVersionFromError(error2);
|
|
@@ -104223,7 +105533,7 @@ function createSyncBackendIO(ctx, transport) {
|
|
|
104223
105533
|
}
|
|
104224
105534
|
};
|
|
104225
105535
|
}
|
|
104226
|
-
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";
|
|
104227
105537
|
var init_sync_backend_io = __esm(() => {
|
|
104228
105538
|
init_dropbox();
|
|
104229
105539
|
init_sync_helpers();
|
|
@@ -104276,17 +105586,165 @@ var init_sync_fast_sync = __esm(() => {
|
|
|
104276
105586
|
init_sync_helpers();
|
|
104277
105587
|
});
|
|
104278
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
|
+
|
|
104279
105735
|
// ../../packages/core/src/sync-remote-fence-providers.ts
|
|
104280
105736
|
var FENCE_MAX_BYTES = 4096, webdavMutationFenceUrl = (documentUrl) => {
|
|
104281
|
-
const
|
|
104282
|
-
const
|
|
104283
|
-
|
|
104284
|
-
|
|
104285
|
-
|
|
104286
|
-
|
|
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}`;
|
|
104287
105745
|
}, createWebdavSyncRemoteMutationFencePort = (documentUrl, options = {}) => {
|
|
104288
105746
|
const url = webdavMutationFenceUrl(documentUrl);
|
|
104289
|
-
const readOptions = { ...options, maxBytes: FENCE_MAX_BYTES };
|
|
105747
|
+
const readOptions = { ...options, maxBytes: FENCE_MAX_BYTES, treatOversizeAsAbsent: true };
|
|
104290
105748
|
return {
|
|
104291
105749
|
read: () => webdavGetFileVersionedWithServerTime(url, readOptions),
|
|
104292
105750
|
write: (bytes, expectedVersion) => webdavPutFileVersioned(url, bytes, "application/json", expectedVersion, options),
|
|
@@ -105928,6 +107386,15 @@ function taskDraftToUpdatePatch(draft, task, options = {}) {
|
|
|
105928
107386
|
return null;
|
|
105929
107387
|
const resolvedProjectId = draft.projectId || undefined;
|
|
105930
107388
|
const recurrenceValue = draft.recurrence ? { rule: draft.recurrence, strategy: draft.recurrenceStrategy } : undefined;
|
|
107389
|
+
const storedRecurrence = task.recurrence && typeof task.recurrence === "object" ? task.recurrence : undefined;
|
|
107390
|
+
if (recurrenceValue && storedRecurrence?.rule === recurrenceValue.rule) {
|
|
107391
|
+
for (const field of RECURRENCE_ANCHOR_FIELDS) {
|
|
107392
|
+
const value = storedRecurrence[field];
|
|
107393
|
+
if (typeof value === "number") {
|
|
107394
|
+
recurrenceValue[field] = value;
|
|
107395
|
+
}
|
|
107396
|
+
}
|
|
107397
|
+
}
|
|
105931
107398
|
if (recurrenceValue && draft.recurrenceRRule) {
|
|
105932
107399
|
const parsed = parseRRuleString(draft.recurrenceRRule);
|
|
105933
107400
|
if (parsed.byDay && parsed.byDay.length > 0) {
|
|
@@ -105936,6 +107403,9 @@ function taskDraftToUpdatePatch(draft, task, options = {}) {
|
|
|
105936
107403
|
if (parsed.byMonthDay && parsed.byMonthDay.length > 0) {
|
|
105937
107404
|
recurrenceValue.byMonthDay = parsed.byMonthDay;
|
|
105938
107405
|
}
|
|
107406
|
+
if (parsed.weekStart) {
|
|
107407
|
+
recurrenceValue.weekStart = parsed.weekStart;
|
|
107408
|
+
}
|
|
105939
107409
|
if (parsed.count) {
|
|
105940
107410
|
recurrenceValue.count = parsed.count;
|
|
105941
107411
|
}
|
|
@@ -105979,8 +107449,32 @@ function taskDraftToUpdatePatch(draft, task, options = {}) {
|
|
|
105979
107449
|
...attachmentsPatch
|
|
105980
107450
|
};
|
|
105981
107451
|
}
|
|
107452
|
+
function taskDraftToChangedUpdatePatch(draft, baselineTask, options = {}) {
|
|
107453
|
+
const patch = taskDraftToUpdatePatch(draft, baselineTask, options);
|
|
107454
|
+
if (!patch)
|
|
107455
|
+
return null;
|
|
107456
|
+
const baseline = taskDraftToUpdatePatch(createTaskDraft(baselineTask), baselineTask, {
|
|
107457
|
+
attachments: baselineTask.attachments
|
|
107458
|
+
}) ?? {};
|
|
107459
|
+
const narrowed = { ...patch };
|
|
107460
|
+
for (const key of Object.keys(narrowed)) {
|
|
107461
|
+
const baselineValue = RAW_CONTAINER_TASK_FIELDS.has(key) ? baselineTask[key] : baseline[key];
|
|
107462
|
+
if (areSerializedTaskFieldValuesEqual(narrowed[key], baselineValue)) {
|
|
107463
|
+
delete narrowed[key];
|
|
107464
|
+
}
|
|
107465
|
+
}
|
|
107466
|
+
return narrowed;
|
|
107467
|
+
}
|
|
105982
107468
|
var trimmedDiffers = (draftValue, taskValue) => draftValue.trim() !== taskValue.trim(), getTaskDraftRecurrenceRRuleValue, TASK_DRAFT_FIELDS, TASK_DRAFT_FIELD_KEYS, attachmentFingerprint = (attachments) => (attachments ?? []).map((attachment) => `${attachment.id}\x00${attachment.uri ?? ""}\x00${attachment.title ?? ""}\x00${attachment.deletedAt ?? ""}`).join(`
|
|
105983
|
-
`)
|
|
107469
|
+
`), RECURRENCE_ANCHOR_FIELDS, RAW_CONTAINER_TASK_FIELDS, areSerializedTaskFieldValuesEqual = (left, right) => {
|
|
107470
|
+
if (left === "" && right == null || right === "" && left == null) {
|
|
107471
|
+
return true;
|
|
107472
|
+
}
|
|
107473
|
+
if (Array.isArray(left) || Array.isArray(right) || typeof left === "object" && left !== null || typeof right === "object" && right !== null) {
|
|
107474
|
+
return JSON.stringify(left ?? null) === JSON.stringify(right ?? null);
|
|
107475
|
+
}
|
|
107476
|
+
return (left ?? null) === (right ?? null);
|
|
107477
|
+
};
|
|
105984
107478
|
var init_task_draft = __esm(() => {
|
|
105985
107479
|
init_bulk_task_tokens();
|
|
105986
107480
|
init_date();
|
|
@@ -106051,6 +107545,13 @@ var init_task_draft = __esm(() => {
|
|
|
106051
107545
|
}
|
|
106052
107546
|
};
|
|
106053
107547
|
TASK_DRAFT_FIELD_KEYS = Object.keys(TASK_DRAFT_FIELDS);
|
|
107548
|
+
RECURRENCE_ANCHOR_FIELDS = [
|
|
107549
|
+
"anchorDay",
|
|
107550
|
+
"startAnchorDay",
|
|
107551
|
+
"dueAnchorDay",
|
|
107552
|
+
"reviewAnchorDay"
|
|
107553
|
+
];
|
|
107554
|
+
RAW_CONTAINER_TASK_FIELDS = new Set(["projectId", "sectionId", "areaId"]);
|
|
106054
107555
|
});
|
|
106055
107556
|
|
|
106056
107557
|
// ../../packages/core/src/contexts.ts
|
|
@@ -106790,7 +108291,7 @@ async function undoTaskCompletion(taskId, previousStatus, wasFocusedToday, optio
|
|
|
106790
108291
|
return;
|
|
106791
108292
|
const current = useTaskStore.getState();
|
|
106792
108293
|
const focusTaskLimit = normalizeFocusTaskLimit(current.settings.gtd?.focusTaskLimit);
|
|
106793
|
-
if (current.
|
|
108294
|
+
if (current.getFocusedCount() >= focusTaskLimit)
|
|
106794
108295
|
return;
|
|
106795
108296
|
const focusResult = await Promise.resolve(current.updateTask(taskId, {
|
|
106796
108297
|
isFocusedToday: true,
|
|
@@ -108070,6 +109571,30 @@ async function cloudGetFile(url, options = {}) {
|
|
|
108070
109571
|
return await readResponseBody(res, options.onProgress, options.maxBytes ?? MAX_DOWNLOAD_BYTES, signal);
|
|
108071
109572
|
});
|
|
108072
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
|
+
}
|
|
108073
109598
|
async function cloudDeleteFile(url, options = {}) {
|
|
108074
109599
|
assertCloudUrl(url, options);
|
|
108075
109600
|
const fetcher = options.fetcher ?? fetch;
|
|
@@ -108152,6 +109677,35 @@ var CLOUDKIT_ATTACHMENT_RECORD_TYPE = "MindwtrAttachment", CLOUDKIT_ATTACHMENT_A
|
|
|
108152
109677
|
return recordName || null;
|
|
108153
109678
|
};
|
|
108154
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
|
+
|
|
108155
109709
|
// ../../packages/core/src/attachment-draft-settlement.ts
|
|
108156
109710
|
function planAttachmentDraftSettlement({
|
|
108157
109711
|
baselineAttachments = [],
|
|
@@ -110369,7 +111923,8 @@ CREATE TABLE IF NOT EXISTS projects (
|
|
|
110369
111923
|
createdAt TEXT NOT NULL,
|
|
110370
111924
|
updatedAt TEXT NOT NULL,
|
|
110371
111925
|
deletedAt TEXT,
|
|
110372
|
-
purgedAt TEXT
|
|
111926
|
+
purgedAt TEXT,
|
|
111927
|
+
startDate TEXT
|
|
110373
111928
|
);
|
|
110374
111929
|
|
|
110375
111930
|
CREATE TABLE IF NOT EXISTS areas (
|
|
@@ -110776,7 +112331,7 @@ var toJson = (value) => value === undefined ? null : JSON.stringify(value), from
|
|
|
110776
112331
|
});
|
|
110777
112332
|
return fallback;
|
|
110778
112333
|
}
|
|
110779
|
-
}, 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) => {
|
|
110780
112335
|
if (value === null)
|
|
110781
112336
|
return null;
|
|
110782
112337
|
if (value === undefined)
|
|
@@ -110906,7 +112461,7 @@ var schema, TASK_SYNC_SCHEMA_VERSION, TASK_SYNC_SCHEMA_VERSION_POLICY, TASK_SYNC
|
|
|
110906
112461
|
relativeStartOffset: fromJson(row.relativeStartOffset, undefined),
|
|
110907
112462
|
dueDate: fromOptional(row.dueDate),
|
|
110908
112463
|
recurrence: fromJson(row.recurrence, null),
|
|
110909
|
-
showFutureRecurrence:
|
|
112464
|
+
showFutureRecurrence: fromPresentBool(row.showFutureRecurrence),
|
|
110910
112465
|
pushCount: row.pushCount === null || row.pushCount === undefined ? undefined : Number(row.pushCount),
|
|
110911
112466
|
repeatReminderMinutes: row.repeatReminderMinutes === null || row.repeatReminderMinutes === undefined ? undefined : Number(row.repeatReminderMinutes),
|
|
110912
112467
|
tags: toStringArray(fromJson(row.tags, [])),
|
|
@@ -110982,7 +112537,8 @@ var init_project_sync_schema_fixture = __esm(() => {
|
|
|
110982
112537
|
{ name: "createdAt", nullability: "required", cloudSynced: true, cloudWrite: "managed", sqliteColumn: "createdAt", sqliteOrder: 18, sqliteType: "TEXT" },
|
|
110983
112538
|
{ name: "updatedAt", nullability: "required", cloudSynced: true, cloudWrite: "managed", sqliteColumn: "updatedAt", sqliteOrder: 19, sqliteType: "TEXT" },
|
|
110984
112539
|
{ name: "deletedAt", nullability: "optional", cloudSynced: true, cloudWrite: "patch", sqliteColumn: "deletedAt", sqliteOrder: 20, sqliteType: "TEXT" },
|
|
110985
|
-
{ 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" }
|
|
110986
112542
|
],
|
|
110987
112543
|
fixture: {
|
|
110988
112544
|
id: "project-schema-fixture",
|
|
@@ -111013,7 +112569,8 @@ var init_project_sync_schema_fixture = __esm(() => {
|
|
|
111013
112569
|
createdAt: "2026-07-01T10:00:00.000Z",
|
|
111014
112570
|
updatedAt: "2026-07-14T11:00:00.000Z",
|
|
111015
112571
|
deletedAt: "2026-07-14T11:30:00.000Z",
|
|
111016
|
-
purgedAt: "2026-07-14T11:45:00.000Z"
|
|
112572
|
+
purgedAt: "2026-07-14T11:45:00.000Z",
|
|
112573
|
+
startDate: "2026-07-10T09:00:00.000Z"
|
|
111017
112574
|
}
|
|
111018
112575
|
};
|
|
111019
112576
|
});
|
|
@@ -111044,6 +112601,7 @@ var schema2, PROJECT_SYNC_SCHEMA_VERSION, PROJECT_SYNC_FIELD_SCHEMA, PROJECT_SYN
|
|
|
111044
112601
|
supportNotes: project.supportNotes ?? null,
|
|
111045
112602
|
attachments: toJson(project.attachments),
|
|
111046
112603
|
dueDate: project.dueDate ?? null,
|
|
112604
|
+
startDate: project.startDate ?? null,
|
|
111047
112605
|
reviewAt: project.reviewAt ?? null,
|
|
111048
112606
|
areaId: project.areaId ?? null,
|
|
111049
112607
|
areaTitle: project.areaTitle ?? null,
|
|
@@ -111070,6 +112628,7 @@ var schema2, PROJECT_SYNC_SCHEMA_VERSION, PROJECT_SYNC_FIELD_SCHEMA, PROJECT_SYN
|
|
|
111070
112628
|
supportNotes: fromOptional(row.supportNotes),
|
|
111071
112629
|
attachments: toAttachments(fromJson(row.attachments, undefined)),
|
|
111072
112630
|
dueDate: fromOptional(row.dueDate),
|
|
112631
|
+
startDate: fromOptional(row.startDate),
|
|
111073
112632
|
reviewAt: fromOptional(row.reviewAt),
|
|
111074
112633
|
areaId: fromOptional(row.areaId),
|
|
111075
112634
|
areaTitle: fromOptional(row.areaTitle),
|
|
@@ -113232,7 +114791,37 @@ var BACKUP_FILE_PREFIX = "mindwtr-backup-", MAX_BACKUP_SOURCE_BYTES, MAX_BACKUP_
|
|
|
113232
114791
|
delete nextSettings.security;
|
|
113233
114792
|
}
|
|
113234
114793
|
return nextSettings;
|
|
113235
|
-
}, sanitizeRestoredAttachments = (item) => item.attachments ? { ...item, attachments: normalizeAttachmentsForSyncMerge(item.attachments) } : item,
|
|
114794
|
+
}, sanitizeRestoredAttachments = (item) => item.attachments ? { ...item, attachments: normalizeAttachmentsForSyncMerge(item.attachments) } : item, prepareRestoredAttachmentsForSync = (item, restoredAt, previous) => {
|
|
114795
|
+
const restoredAttachments = normalizeAttachmentsForSyncMerge(item.attachments) ?? [];
|
|
114796
|
+
const previousAttachments = normalizeAttachmentsForSyncMerge(previous?.attachments) ?? [];
|
|
114797
|
+
if (restoredAttachments.length === 0 && previousAttachments.length === 0) {
|
|
114798
|
+
return sanitizeRestoredAttachments(item);
|
|
114799
|
+
}
|
|
114800
|
+
const restoredIds = new Set(restoredAttachments.map((attachment) => attachment.id));
|
|
114801
|
+
const previousAttachmentsById = new Map(previousAttachments.map((attachment) => [attachment.id, attachment]));
|
|
114802
|
+
const refreshed = restoredAttachments.map((attachment) => {
|
|
114803
|
+
const previousAttachment = previousAttachmentsById.get(attachment.id);
|
|
114804
|
+
const shouldPublishRestoredBytes = attachment.kind === "file" && !item.deletedAt && !attachment.deletedAt;
|
|
114805
|
+
return {
|
|
114806
|
+
...attachment,
|
|
114807
|
+
...attachment.kind === "file" ? {
|
|
114808
|
+
contentRev: nextRevision(Math.max(normalizeRevision(attachment.contentRev), normalizeRevision(previousAttachment?.contentRev)))
|
|
114809
|
+
} : {},
|
|
114810
|
+
...shouldPublishRestoredBytes ? { pendingContentUpload: true } : {},
|
|
114811
|
+
...attachment.deletedAt ? { deletedAt: restoredAt } : {},
|
|
114812
|
+
updatedAt: restoredAt
|
|
114813
|
+
};
|
|
114814
|
+
});
|
|
114815
|
+
const carriedTombstones = previousAttachments.filter((attachment) => !restoredIds.has(attachment.id)).map((attachment) => ({
|
|
114816
|
+
...attachment,
|
|
114817
|
+
deletedAt: restoredAt,
|
|
114818
|
+
updatedAt: restoredAt
|
|
114819
|
+
}));
|
|
114820
|
+
return {
|
|
114821
|
+
...item,
|
|
114822
|
+
attachments: [...refreshed, ...carriedTombstones]
|
|
114823
|
+
};
|
|
114824
|
+
}, prepareRestoredBackupDataForSync = (data, options = {}) => {
|
|
113236
114825
|
const restoredAt = toIsoString(options.restoredAt) ?? new Date().toISOString();
|
|
113237
114826
|
const restoredSettings = stripDeviceLocalRestoreSettings(data.settings);
|
|
113238
114827
|
const previous = options.previousData ?? null;
|
|
@@ -113245,11 +114834,11 @@ var BACKUP_FILE_PREFIX = "mindwtr-backup-", MAX_BACKUP_SOURCE_BYTES, MAX_BACKUP_
|
|
|
113245
114834
|
const tasks = prepare(data.tasks, previous?.tasks).map((task) => task.purgedAt ? compactPurgedTaskForLocalStorage({
|
|
113246
114835
|
...task,
|
|
113247
114836
|
attachments: previousTasksById.get(task.id)?.attachments
|
|
113248
|
-
}) :
|
|
114837
|
+
}) : prepareRestoredAttachmentsForSync(task, restoredAt, previousTasksById.get(task.id)));
|
|
113249
114838
|
const projects = prepare(data.projects, previous?.projects).map((project) => project.purgedAt ? compactPurgedProjectForLocalStorage({
|
|
113250
114839
|
...project,
|
|
113251
114840
|
attachments: previousProjectsById.get(project.id)?.attachments
|
|
113252
|
-
}) :
|
|
114841
|
+
}) : prepareRestoredAttachmentsForSync(project, restoredAt, previousProjectsById.get(project.id)));
|
|
113253
114842
|
const sections = compactSectionsForPurgedProjects(prepare(data.sections, previous?.sections), projects);
|
|
113254
114843
|
return {
|
|
113255
114844
|
...data,
|
|
@@ -115180,6 +116769,7 @@ function applyImport(currentData, parsed, opts) {
|
|
|
115180
116769
|
tagIds: project.tagIds ?? [],
|
|
115181
116770
|
supportNotes: project.supportNotes,
|
|
115182
116771
|
dueDate: project.dueDate,
|
|
116772
|
+
startDate: project.startDate,
|
|
115183
116773
|
createdAt,
|
|
115184
116774
|
updatedAt,
|
|
115185
116775
|
rev: nextRevision(),
|
|
@@ -116190,6 +117780,7 @@ var normalizeFolders = (rawFolders) => {
|
|
|
116190
117780
|
areaSourceId: record3.folderId,
|
|
116191
117781
|
color: record3.color,
|
|
116192
117782
|
dueDate: record3.dueDate,
|
|
117783
|
+
startDate: record3.startDate,
|
|
116193
117784
|
supportNotes,
|
|
116194
117785
|
isArchived: Boolean(record3.completedAt),
|
|
116195
117786
|
createdAt: record3.createdAt,
|
|
@@ -116567,6 +118158,7 @@ ${next}`;
|
|
|
116567
118158
|
const project2 = ensureProjectRecord(projectsByKey, row.name, allocateProjectOrder);
|
|
116568
118159
|
project2.status = parseProjectStatus(row.statusText || "");
|
|
116569
118160
|
project2.dueDate = dueMapping.value ?? project2.dueDate;
|
|
118161
|
+
project2.startDate = startMapping.value ?? project2.startDate;
|
|
116570
118162
|
project2.supportNotes = mergeProjectSupportNotes(project2.supportNotes, joinDescription([
|
|
116571
118163
|
row.notes,
|
|
116572
118164
|
plannedMapping.value ? `Planned date in OmniFocus: ${plannedMapping.value}` : undefined,
|
|
@@ -116958,6 +118550,7 @@ ${next}`;
|
|
|
116958
118550
|
areaSourceKey: ensureAreaRecord(project.folderId, project.folderName),
|
|
116959
118551
|
status: project.completed || rootTask?.completed ? "archived" : parseProjectStatus(project.statusText || rootTask?.statusText || ""),
|
|
116960
118552
|
dueDate: dateNotes.dueDate,
|
|
118553
|
+
startDate: dateNotes.startTime,
|
|
116961
118554
|
supportNotes: joinDescription([
|
|
116962
118555
|
project.note,
|
|
116963
118556
|
rootTask?.note,
|
|
@@ -116988,6 +118581,7 @@ ${next}`;
|
|
|
116988
118581
|
order: projects.length,
|
|
116989
118582
|
status: task.completed ? "archived" : parseProjectStatus(task.statusText || ""),
|
|
116990
118583
|
dueDate: dateNotes.dueDate,
|
|
118584
|
+
startDate: dateNotes.startTime,
|
|
116991
118585
|
supportNotes: joinDescription([
|
|
116992
118586
|
task.note,
|
|
116993
118587
|
dateNotes.plannedNote,
|
|
@@ -118527,6 +120121,42 @@ var init_capture = __esm(() => {
|
|
|
118527
120121
|
init_color_constants();
|
|
118528
120122
|
});
|
|
118529
120123
|
|
|
120124
|
+
// ../../packages/core/src/capture-session.ts
|
|
120125
|
+
class CaptureSessionCoordinator {
|
|
120126
|
+
currentSession = 0;
|
|
120127
|
+
submittingSession = null;
|
|
120128
|
+
beginSession() {
|
|
120129
|
+
this.currentSession += 1;
|
|
120130
|
+
this.submittingSession = null;
|
|
120131
|
+
return this.currentSession;
|
|
120132
|
+
}
|
|
120133
|
+
invalidateSession(session) {
|
|
120134
|
+
if (!this.isCurrent(session))
|
|
120135
|
+
return;
|
|
120136
|
+
this.currentSession += 1;
|
|
120137
|
+
this.submittingSession = null;
|
|
120138
|
+
}
|
|
120139
|
+
isCurrent(session) {
|
|
120140
|
+
return session === this.currentSession;
|
|
120141
|
+
}
|
|
120142
|
+
isSubmitting(session) {
|
|
120143
|
+
return this.isCurrent(session) && this.submittingSession === session;
|
|
120144
|
+
}
|
|
120145
|
+
tryBeginSubmission(session) {
|
|
120146
|
+
if (!this.isCurrent(session) || this.submittingSession !== null)
|
|
120147
|
+
return false;
|
|
120148
|
+
this.submittingSession = session;
|
|
120149
|
+
return true;
|
|
120150
|
+
}
|
|
120151
|
+
finishSubmission(session) {
|
|
120152
|
+
if (!this.isCurrent(session))
|
|
120153
|
+
return false;
|
|
120154
|
+
if (this.submittingSession === session)
|
|
120155
|
+
this.submittingSession = null;
|
|
120156
|
+
return true;
|
|
120157
|
+
}
|
|
120158
|
+
}
|
|
120159
|
+
|
|
118530
120160
|
// ../../packages/core/src/session-restore.ts
|
|
118531
120161
|
function shouldRestoreLastView(savedAtMs, nowMs = Date.now()) {
|
|
118532
120162
|
if (typeof savedAtMs !== "number" || !Number.isFinite(savedAtMs))
|
|
@@ -118770,6 +120400,39 @@ var init_import_runner = __esm(() => {
|
|
|
118770
120400
|
});
|
|
118771
120401
|
|
|
118772
120402
|
// ../../packages/core/src/global-search-filter.ts
|
|
120403
|
+
function getGlobalSearchFilterPresentation(t) {
|
|
120404
|
+
const translated = (key, fallback) => {
|
|
120405
|
+
const value = t(key);
|
|
120406
|
+
return value && value !== key ? value : fallback;
|
|
120407
|
+
};
|
|
120408
|
+
const scope = {
|
|
120409
|
+
all: translated("search.scope.all", "All"),
|
|
120410
|
+
projects: translated("search.scope.projects", "Projects only"),
|
|
120411
|
+
tasks: translated("search.scope.tasks", "Tasks only"),
|
|
120412
|
+
project_tasks: translated("search.scope.projectTasks", "Tasks in projects")
|
|
120413
|
+
};
|
|
120414
|
+
const due = {
|
|
120415
|
+
any: translated("search.due.any", "Any"),
|
|
120416
|
+
overdue: translated("search.due.overdue", "Overdue"),
|
|
120417
|
+
today: translated("search.due.today", "Today"),
|
|
120418
|
+
tomorrow: translated("search.due.tomorrow", "Tomorrow"),
|
|
120419
|
+
this_week: translated("search.due.thisWeek", "This week"),
|
|
120420
|
+
next_week: translated("search.due.nextWeek", "Next week"),
|
|
120421
|
+
none: translated("search.due.none", "No due date")
|
|
120422
|
+
};
|
|
120423
|
+
return {
|
|
120424
|
+
sections: {
|
|
120425
|
+
status: translated("taskEdit.statusLabel", "Status"),
|
|
120426
|
+
scope: translated("search.scope.label", "Scope"),
|
|
120427
|
+
area: translated("taskEdit.areaLabel", "Area"),
|
|
120428
|
+
due: translated("search.due.label", "Due date"),
|
|
120429
|
+
tokens: translated("filters.contexts", "Contexts & tags")
|
|
120430
|
+
},
|
|
120431
|
+
scope,
|
|
120432
|
+
due,
|
|
120433
|
+
clear: translated("filters.clear", "Clear")
|
|
120434
|
+
};
|
|
120435
|
+
}
|
|
118773
120436
|
var buildDueMatcher = (duePreset, weekStart) => {
|
|
118774
120437
|
const now3 = new Date;
|
|
118775
120438
|
const startOfToday3 = new Date(now3.getFullYear(), now3.getMonth(), now3.getDate());
|
|
@@ -119581,6 +121244,7 @@ var init_settings_search_keys = __esm(() => {
|
|
|
119581
121244
|
{ key: "density", section: "lookAndFeel" },
|
|
119582
121245
|
{ key: "textSize", section: "lookAndFeel" },
|
|
119583
121246
|
{ key: "showTaskAge", section: "lookAndFeel" },
|
|
121247
|
+
{ key: "sidebarViews", section: "lookAndFeel" },
|
|
119584
121248
|
{ key: "language", section: "localization" },
|
|
119585
121249
|
{ key: "weekStart", section: "localization" },
|
|
119586
121250
|
{ key: "dateFormat", section: "localization" },
|
|
@@ -119601,6 +121265,7 @@ var init_settings_search_keys = __esm(() => {
|
|
|
119601
121265
|
"focusTaskLimit",
|
|
119602
121266
|
"defaultProjectFlowMode",
|
|
119603
121267
|
"features",
|
|
121268
|
+
{ key: "featureTimeline", section: "features" },
|
|
119604
121269
|
{ key: "featurePomodoro", section: "features" },
|
|
119605
121270
|
{ key: "pomodoroCustomPreset", section: "features" },
|
|
119606
121271
|
{ key: "pomodoroLinkTask", section: "features" },
|
|
@@ -119736,6 +121401,7 @@ var init_settings_search_keys = __esm(() => {
|
|
|
119736
121401
|
"checkForUpdates",
|
|
119737
121402
|
"feedback",
|
|
119738
121403
|
"documentation",
|
|
121404
|
+
"videoTutorials",
|
|
119739
121405
|
"privacy",
|
|
119740
121406
|
"github",
|
|
119741
121407
|
"sponsorProject",
|
|
@@ -119765,6 +121431,7 @@ var init_settings_search_keys = __esm(() => {
|
|
|
119765
121431
|
SETTINGS_SEARCH_PAGE_IDS = Object.keys(SETTINGS_SEARCH_PAGE_KEYS);
|
|
119766
121432
|
SETTINGS_SEARCH_INDEX = SETTINGS_SEARCH_PAGE_IDS.flatMap((pageId) => getSettingsSearchEntries(pageId));
|
|
119767
121433
|
SETTINGS_SEARCH_MOBILE_EXCLUSIONS = {
|
|
121434
|
+
featureTimeline: "Timeline view exists on desktop only; the mobile GTD > Features screen has no row for it (#1145).",
|
|
119768
121435
|
density: "No adjustable list density setting on mobile.",
|
|
119769
121436
|
textSize: "Mobile follows the OS text-size setting automatically; no in-app override.",
|
|
119770
121437
|
keybindings: "No hardware-keyboard shortcuts configuration on mobile.",
|
|
@@ -119898,8 +121565,14 @@ __export(exports_src, {
|
|
|
119898
121565
|
taskMatchesAreaFilterSelection: () => taskMatchesAreaFilterSelection,
|
|
119899
121566
|
taskFromSqliteRow: () => taskFromSqliteRow,
|
|
119900
121567
|
taskDraftToUpdatePatch: () => taskDraftToUpdatePatch,
|
|
121568
|
+
taskDraftToChangedUpdatePatch: () => taskDraftToChangedUpdatePatch,
|
|
119901
121569
|
tFallback: () => tFallback,
|
|
119902
121570
|
syncPlaintextArtifactName: () => syncPlaintextArtifactName,
|
|
121571
|
+
syncEncryptionScopeLabel: () => syncEncryptionScopeLabel,
|
|
121572
|
+
syncEncryptionSaltPrefix: () => syncEncryptionSaltPrefix,
|
|
121573
|
+
syncEncryptionLogMessage: () => syncEncryptionLogMessage,
|
|
121574
|
+
syncEncryptionKdfLabel: () => syncEncryptionKdfLabel,
|
|
121575
|
+
syncEncryptionArtifactLabel: () => syncEncryptionArtifactLabel,
|
|
119903
121576
|
syncEncryptedArtifactName: () => syncEncryptedArtifactName,
|
|
119904
121577
|
summarizeTaskLifecycleCounts: () => summarizeTaskLifecycleCounts,
|
|
119905
121578
|
summarizeMergeStats: () => summarizeMergeStats,
|
|
@@ -119939,6 +121612,7 @@ __export(exports_src, {
|
|
|
119939
121612
|
setTaskViewSectionId: () => setTaskViewSectionId,
|
|
119940
121613
|
setTaskDraftField: () => setTaskDraftField,
|
|
119941
121614
|
setStorageAdapter: () => setStorageAdapter,
|
|
121615
|
+
setSleepBypass: () => setSleepBypass,
|
|
119942
121616
|
setSha256HexProvider: () => setSha256HexProvider,
|
|
119943
121617
|
setLogger: () => setLogger,
|
|
119944
121618
|
setComposerTitle: () => setComposerTitle,
|
|
@@ -119965,6 +121639,7 @@ __export(exports_src, {
|
|
|
119965
121639
|
selectVisiblePeople: () => selectVisiblePeople,
|
|
119966
121640
|
selectVisibleAreas: () => selectVisibleAreas,
|
|
119967
121641
|
selectProcessInboxCandidates: () => selectProcessInboxCandidates,
|
|
121642
|
+
selectFocusedCount: () => selectFocusedCount,
|
|
119968
121643
|
selectComposerTask: () => selectComposerTask,
|
|
119969
121644
|
sectionToSqliteRow: () => sectionToSqliteRow,
|
|
119970
121645
|
sectionFromSqliteRow: () => sectionFromSqliteRow,
|
|
@@ -120022,6 +121697,9 @@ __export(exports_src, {
|
|
|
120022
121697
|
resolveTextDirection: () => resolveTextDirection,
|
|
120023
121698
|
resolveTaskViewSection: () => resolveTaskViewSection,
|
|
120024
121699
|
resolveTaskTextDirection: () => resolveTaskTextDirection,
|
|
121700
|
+
resolveTaskSortByForFeatures: () => resolveTaskSortByForFeatures,
|
|
121701
|
+
resolveTaskPerspectiveForFeatures: () => resolveTaskPerspectiveForFeatures,
|
|
121702
|
+
resolveTaskGroupByForFeatures: () => resolveTaskGroupByForFeatures,
|
|
120025
121703
|
resolveSyncFailureCooldownMs: () => resolveSyncFailureCooldownMs,
|
|
120026
121704
|
resolveSyncBackend: () => resolveSyncBackend,
|
|
120027
121705
|
resolveSettingsSearchI18nKey: () => resolveSettingsSearchI18nKey,
|
|
@@ -120050,6 +121728,7 @@ __export(exports_src, {
|
|
|
120050
121728
|
resolveAnthropicModel: () => resolveAnthropicModel,
|
|
120051
121729
|
resetUnhashableAttachmentStatsForTests: () => resetUnhashableAttachmentStatsForTests,
|
|
120052
121730
|
resetPomodoroState: () => resetPomodoroState,
|
|
121731
|
+
resetLastSyncEncryptionError: () => resetLastSyncEncryptionError,
|
|
120053
121732
|
resetHeartbeatOptOutMarker: () => resetHeartbeatOptOutMarker,
|
|
120054
121733
|
resetForTests: () => resetForTests,
|
|
120055
121734
|
rescheduleTask: () => rescheduleTask,
|
|
@@ -120057,6 +121736,7 @@ __export(exports_src, {
|
|
|
120057
121736
|
replaceEntityInMap: () => replaceEntityInMap,
|
|
120058
121737
|
replaceEntityInArray: () => replaceEntityInArray,
|
|
120059
121738
|
replaceEntitiesInArray: () => replaceEntitiesInArray,
|
|
121739
|
+
repairMissingRemoteAttachments: () => repairMissingRemoteAttachments,
|
|
120060
121740
|
repairMergedSyncReferences: () => repairMergedSyncReferences,
|
|
120061
121741
|
removeAdvancedFilterCriteriaChip: () => removeAdvancedFilterCriteriaChip,
|
|
120062
121742
|
recordUpdateReminderShown: () => recordUpdateReminderShown,
|
|
@@ -120252,6 +121932,7 @@ __export(exports_src, {
|
|
|
120252
121932
|
isSyncFilePath: () => isSyncFilePath,
|
|
120253
121933
|
isSyncFileLockUnavailableError: () => isSyncFileLockUnavailableError,
|
|
120254
121934
|
isSyncFileGenerationCorruptError: () => isSyncFileGenerationCorruptError,
|
|
121935
|
+
isSyncEncryptionStateBlocked: () => isSyncEncryptionStateBlocked,
|
|
120255
121936
|
isSyncEncryptionRemoteVersionUnavailableError: () => isSyncEncryptionRemoteVersionUnavailableError,
|
|
120256
121937
|
isSupportedLanguage: () => isSupportedLanguage,
|
|
120257
121938
|
isSlotFreeForDay: () => isSlotFreeForDay,
|
|
@@ -120281,6 +121962,7 @@ __export(exports_src, {
|
|
|
120281
121962
|
isMindwtrMirrorEvent: () => isMindwtrMirrorEvent,
|
|
120282
121963
|
isMindwtrMirrorCalendar: () => isMindwtrMirrorCalendar,
|
|
120283
121964
|
isMarkdownEditorAssistEnabled: () => isMarkdownEditorAssistEnabled,
|
|
121965
|
+
isLocalPersistEquivalent: () => isLocalPersistEquivalent,
|
|
120284
121966
|
isLikelyOfflineSyncError: () => isLikelyOfflineSyncError,
|
|
120285
121967
|
isJalaliCalendarLocale: () => isJalaliCalendarLocale,
|
|
120286
121968
|
isFocusSequentialCandidate: () => isFocusSequentialCandidate,
|
|
@@ -120292,12 +121974,14 @@ __export(exports_src, {
|
|
|
120292
121974
|
isDropboxPathNotFoundTag: () => isDropboxPathNotFoundTag,
|
|
120293
121975
|
isDropboxPathConflictTag: () => isDropboxPathConflictTag,
|
|
120294
121976
|
isDropboxConflictError: () => isDropboxConflictError,
|
|
121977
|
+
isDeepJsonEqual: () => isDeepJsonEqual,
|
|
120295
121978
|
isCustomTimeEstimate: () => isCustomTimeEstimate,
|
|
120296
121979
|
isConnectionAllowed: () => isConnectionAllowed,
|
|
120297
121980
|
isCompletedCalendarTask: () => isCompletedCalendarTask,
|
|
120298
121981
|
isCalendarFeedTask: () => isCalendarFeedTask,
|
|
120299
121982
|
isAttachmentUploadTooLargeError: () => isAttachmentUploadTooLargeError,
|
|
120300
121983
|
isAttachmentUploadAdmissionError: () => isAttachmentUploadAdmissionError,
|
|
121984
|
+
isAttachmentPresenceRepairCandidate: () => isAttachmentPresenceRepairCandidate,
|
|
120301
121985
|
isAttachmentLocalResourceReferenced: () => isAttachmentLocalResourceReferenced,
|
|
120302
121986
|
isAttachmentCloudResourceReferenced: () => isAttachmentCloudResourceReferenced,
|
|
120303
121987
|
isAreaFilterSelectionActive: () => isAreaFilterSelectionActive,
|
|
@@ -120381,6 +122065,7 @@ __export(exports_src, {
|
|
|
120381
122065
|
getProjectsByArea: () => getProjectsByArea,
|
|
120382
122066
|
getProjectedRecurringTaskId: () => getProjectedRecurringTaskId,
|
|
120383
122067
|
getProjectedRecurringTaskCalendarDate: () => getProjectedRecurringTaskCalendarDate,
|
|
122068
|
+
getProjectSectionsForView: () => getProjectSectionsForView,
|
|
120384
122069
|
getProjectReviewReminderIntent: () => getProjectReviewReminderIntent,
|
|
120385
122070
|
getProjectNextActionState: () => getProjectNextActionState,
|
|
120386
122071
|
getProjectNextActionPromptData: () => getProjectNextActionPromptData,
|
|
@@ -120408,10 +122093,12 @@ __export(exports_src, {
|
|
|
120408
122093
|
getLocalizedWeekdayLabel: () => getLocalizedWeekdayLabel,
|
|
120409
122094
|
getLocalizedWeekdayButtons: () => getLocalizedWeekdayButtons,
|
|
120410
122095
|
getLocaleCoverageTier: () => getLocaleCoverageTier,
|
|
122096
|
+
getLastSyncEncryptionError: () => getLastSyncEncryptionError,
|
|
120411
122097
|
getInlineMarkdownPreview: () => getInlineMarkdownPreview,
|
|
120412
122098
|
getInMemorySyncChangeFingerprint: () => getInMemorySyncChangeFingerprint,
|
|
120413
122099
|
getInMemoryAppDataSnapshot: () => getInMemoryAppDataSnapshot,
|
|
120414
122100
|
getI18nKeyForEnglishText: () => getI18nKeyForEnglishText,
|
|
122101
|
+
getGlobalSearchFilterPresentation: () => getGlobalSearchFilterPresentation,
|
|
120415
122102
|
getFrequentTaskTokensFromUsage: () => getFrequentTaskTokensFromUsage,
|
|
120416
122103
|
getFrequentTaskTokens: () => getFrequentTaskTokens,
|
|
120417
122104
|
getFocusStarBlockedText: () => getFocusStarBlockedText,
|
|
@@ -120460,9 +122147,11 @@ __export(exports_src, {
|
|
|
120460
122147
|
formatTaskMovedMessage: () => formatTaskMovedMessage,
|
|
120461
122148
|
formatTaskMarkedDoneMessage: () => formatTaskMarkedDoneMessage,
|
|
120462
122149
|
formatSyncErrorMessage: () => formatSyncErrorMessage,
|
|
122150
|
+
formatSyncEncryptionDiagnostics: () => formatSyncEncryptionDiagnostics,
|
|
120463
122151
|
formatSettingsSearchPath: () => formatSettingsSearchPath,
|
|
120464
122152
|
formatRecurrenceLabel: () => formatRecurrenceLabel,
|
|
120465
122153
|
formatRecurrenceCountLabel: () => formatRecurrenceCountLabel,
|
|
122154
|
+
formatQuickAddHelp: () => formatQuickAddHelp,
|
|
120466
122155
|
formatPomodoroClock: () => formatPomodoroClock,
|
|
120467
122156
|
formatOpenAIExtraBodyParams: () => formatOpenAIExtraBodyParams,
|
|
120468
122157
|
formatLocalDateTime: () => formatLocalDateTime2,
|
|
@@ -120475,6 +122164,7 @@ __export(exports_src, {
|
|
|
120475
122164
|
formatCalendarDurationLabel: () => formatCalendarDurationLabel,
|
|
120476
122165
|
formatAIErrorAlertBody: () => formatAIErrorAlertBody,
|
|
120477
122166
|
flushPendingSave: () => flushPendingSave,
|
|
122167
|
+
findSyncEncryptionSentinel: () => findSyncEncryptionSentinel,
|
|
120478
122168
|
findSelectableProjectByTitleAndArea: () => findSelectableProjectByTitleAndArea,
|
|
120479
122169
|
findPendingAttachmentUploads: () => findPendingAttachmentUploads,
|
|
120480
122170
|
findOrphanedAttachments: () => findOrphanedAttachments,
|
|
@@ -120510,6 +122200,7 @@ __export(exports_src, {
|
|
|
120510
122200
|
ensureDeviceId: () => ensureDeviceId,
|
|
120511
122201
|
endOfCalendarMonth: () => endOfCalendarMonth,
|
|
120512
122202
|
encryptSyncArtifact: () => encryptSyncArtifact,
|
|
122203
|
+
editRRuleString: () => editRRuleString,
|
|
120513
122204
|
downloadDropboxFileVersionedWithServerTime: () => downloadDropboxFileVersionedWithServerTime,
|
|
120514
122205
|
downloadDropboxFileVersioned: () => downloadDropboxFileVersioned,
|
|
120515
122206
|
downloadDropboxFile: () => downloadDropboxFile,
|
|
@@ -120551,6 +122242,7 @@ __export(exports_src, {
|
|
|
120551
122242
|
createImportDiagnostic: () => createImportDiagnostic,
|
|
120552
122243
|
createImportArchiveBudget: () => createImportArchiveBudget,
|
|
120553
122244
|
createDropboxSyncRemoteMutationFencePort: () => createDropboxSyncRemoteMutationFencePort,
|
|
122245
|
+
createDropboxAttachmentPresenceIndex: () => createDropboxAttachmentPresenceIndex,
|
|
120554
122246
|
createDefaultSyncRunStoreBridge: () => createDefaultSyncRunStoreBridge,
|
|
120555
122247
|
createCustomTimeEstimate: () => createCustomTimeEstimate,
|
|
120556
122248
|
createCurrentRecurringCalendarTask: () => createCurrentRecurringCalendarTask,
|
|
@@ -120604,9 +122296,11 @@ __export(exports_src, {
|
|
|
120604
122296
|
cloudGetJson: () => cloudGetJson,
|
|
120605
122297
|
cloudGetFile: () => cloudGetFile,
|
|
120606
122298
|
cloudDeleteFile: () => cloudDeleteFile,
|
|
122299
|
+
cloudAttachmentExists: () => cloudAttachmentExists,
|
|
120607
122300
|
cloneSettings: () => cloneSettings,
|
|
120608
122301
|
cloneAppData: () => cloneAppData,
|
|
120609
122302
|
clearProviderModelsCache: () => clearProviderModelsCache,
|
|
122303
|
+
clearIdleSyncCycleSnapshot: () => clearIdleSyncCycleSnapshot,
|
|
120610
122304
|
clearDeletedTaskProjectArchiveMetadata: () => clearDeletedTaskProjectArchiveMetadata,
|
|
120611
122305
|
clearBreadcrumbs: () => clearBreadcrumbs,
|
|
120612
122306
|
checkAttachmentContentChange: () => checkAttachmentContentChange,
|
|
@@ -120624,6 +122318,12 @@ __export(exports_src, {
|
|
|
120624
122318
|
buildSyncPayloadTraceExtra: () => buildSyncPayloadTraceExtra,
|
|
120625
122319
|
buildSyncPayloadSurfaceTraceExtra: () => buildSyncPayloadSurfaceTraceExtra,
|
|
120626
122320
|
buildSyncPayloadDiffTraceExtra: () => buildSyncPayloadDiffTraceExtra,
|
|
122321
|
+
buildSyncLocationScope: () => buildSyncLocationScope,
|
|
122322
|
+
buildSyncEncryptionTransitionExtra: () => buildSyncEncryptionTransitionExtra,
|
|
122323
|
+
buildSyncEncryptionStateExtra: () => buildSyncEncryptionStateExtra,
|
|
122324
|
+
buildSyncEncryptionRemoteReadExtra: () => buildSyncEncryptionRemoteReadExtra,
|
|
122325
|
+
buildSyncEncryptionErrorExtra: () => buildSyncEncryptionErrorExtra,
|
|
122326
|
+
buildSyncEncryptionActivationExtra: () => buildSyncEncryptionActivationExtra,
|
|
120627
122327
|
buildSpeechTranscriptionPrompt: () => buildSpeechTranscriptionPrompt,
|
|
120628
122328
|
buildSpeechToTaskPrompt: () => buildSpeechToTaskPrompt,
|
|
120629
122329
|
buildSettingsSearchResults: () => buildSettingsSearchResults,
|
|
@@ -120778,8 +122478,13 @@ __export(exports_src, {
|
|
|
120778
122478
|
SYNC_FILE_GENERATION_CORRUPT_CODE: () => SYNC_FILE_GENERATION_CORRUPT_CODE,
|
|
120779
122479
|
SYNC_ENCRYPTION_TRANSITION_INCOMPLETE: () => SYNC_ENCRYPTION_TRANSITION_INCOMPLETE,
|
|
120780
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,
|
|
120781
122485
|
SYNC_ENCRYPTION_KEYED_STATES: () => SYNC_ENCRYPTION_KEYED_STATES,
|
|
120782
122486
|
SYNC_CRYPTO_DEFAULT_KDF_PARAMS: () => SYNC_CRYPTO_DEFAULT_KDF_PARAMS,
|
|
122487
|
+
SUSPENDED_REQUEST_MESSAGE: () => SUSPENDED_REQUEST_MESSAGE,
|
|
120783
122488
|
SUPPORTED_LANGUAGES: () => SUPPORTED_LANGUAGES,
|
|
120784
122489
|
STORE_REVIEW_MIN_DAYS_SINCE_FIRST_SEEN: () => STORE_REVIEW_MIN_DAYS_SINCE_FIRST_SEEN,
|
|
120785
122490
|
STORE_REVIEW_MIN_ACTIVE_DAYS: () => STORE_REVIEW_MIN_ACTIVE_DAYS,
|
|
@@ -120882,6 +122587,7 @@ __export(exports_src, {
|
|
|
120882
122587
|
DropboxFileNotFoundError: () => DropboxFileNotFoundError,
|
|
120883
122588
|
DropboxConflictError: () => DropboxConflictError,
|
|
120884
122589
|
DataTransferRefreshError: () => DataTransferRefreshError,
|
|
122590
|
+
DROPBOX_ATTACHMENTS_PATH: () => DROPBOX_ATTACHMENTS_PATH,
|
|
120885
122591
|
DRACULA_EXTERNAL_CALENDAR_COLOR_MAP: () => DRACULA_EXTERNAL_CALENDAR_COLOR_MAP,
|
|
120886
122592
|
DRACULA_CONTEXT_COLOR_PALETTE: () => DRACULA_CONTEXT_COLOR_PALETTE,
|
|
120887
122593
|
DONATION_PROMPT_SUPPORT_CLICK_COOLDOWN_MS: () => DONATION_PROMPT_SUPPORT_CLICK_COOLDOWN_MS,
|
|
@@ -120915,6 +122621,7 @@ __export(exports_src, {
|
|
|
120915
122621
|
DEFAULT_AREA_COLOR: () => DEFAULT_AREA_COLOR,
|
|
120916
122622
|
DEFAULT_ANTHROPIC_THINKING_BUDGET: () => DEFAULT_ANTHROPIC_THINKING_BUDGET,
|
|
120917
122623
|
CloudHttpError: () => CloudHttpError,
|
|
122624
|
+
CaptureSessionCoordinator: () => CaptureSessionCoordinator,
|
|
120918
122625
|
CUSTOM_TIME_ESTIMATE_PREFIX: () => CUSTOM_TIME_ESTIMATE_PREFIX,
|
|
120919
122626
|
COPILOT_REASONING_EFFORT: () => COPILOT_REASONING_EFFORT,
|
|
120920
122627
|
COMPLETION_DATE_GROUPS: () => COMPLETION_DATE_GROUPS,
|
|
@@ -120987,6 +122694,7 @@ var init_src = __esm(() => {
|
|
|
120987
122694
|
init_sync_fast_sync();
|
|
120988
122695
|
init_sync_crypto();
|
|
120989
122696
|
init_sync_encryption();
|
|
122697
|
+
init_sync_encryption_diagnostics();
|
|
120990
122698
|
init_sync_remote_fence();
|
|
120991
122699
|
init_sync_remote_fence_providers();
|
|
120992
122700
|
init_diceware();
|
|
@@ -134482,6 +136190,7 @@ var createCloudService = (options) => {
|
|
|
134482
136190
|
isSequential: input.isSequential,
|
|
134483
136191
|
isFocused: input.isFocused,
|
|
134484
136192
|
dueDate: input.dueDate ?? undefined,
|
|
136193
|
+
startDate: input.startDate ?? undefined,
|
|
134485
136194
|
reviewAt: input.reviewAt ?? undefined,
|
|
134486
136195
|
supportNotes: input.supportNotes ?? undefined
|
|
134487
136196
|
})
|
|
@@ -134504,6 +136213,8 @@ var createCloudService = (options) => {
|
|
|
134504
136213
|
patch.isFocused = input.isFocused;
|
|
134505
136214
|
if (input.dueDate !== undefined)
|
|
134506
136215
|
patch.dueDate = input.dueDate;
|
|
136216
|
+
if (input.startDate !== undefined)
|
|
136217
|
+
patch.startDate = input.startDate;
|
|
134507
136218
|
if (input.reviewAt !== undefined)
|
|
134508
136219
|
patch.reviewAt = input.reviewAt;
|
|
134509
136220
|
if (input.supportNotes !== undefined)
|
|
@@ -137011,7 +138722,8 @@ var getProjectColumns = (db) => {
|
|
|
137011
138722
|
const names = new Set(columns.map((col) => String(col.name)));
|
|
137012
138723
|
const hasOrderNum = names.has("orderNum");
|
|
137013
138724
|
const hasDueDate = names.has("dueDate");
|
|
137014
|
-
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"));
|
|
137015
138727
|
const resolved = { hasOrderNum, selectColumns };
|
|
137016
138728
|
projectColumnsCache.set(db, resolved);
|
|
137017
138729
|
return resolved;
|
|
@@ -137433,6 +139145,18 @@ var ensureCoreReady = async (options) => {
|
|
|
137433
139145
|
const runWriteTransaction = coreReadonly ? runDirectly : (operation) => withMcpWriteLock(resolvedPath, operation);
|
|
137434
139146
|
coreService = {
|
|
137435
139147
|
...createCorePersistenceService(core2, runWriteTransaction),
|
|
139148
|
+
getQuickAddSnapshot: async () => runWriteTransaction(async () => {
|
|
139149
|
+
const state = core2.useTaskStore.getState();
|
|
139150
|
+
await state.fetchData();
|
|
139151
|
+
const current = core2.useTaskStore.getState();
|
|
139152
|
+
return {
|
|
139153
|
+
tasks: current.tasks,
|
|
139154
|
+
projects: current.projects,
|
|
139155
|
+
areas: current.areas,
|
|
139156
|
+
people: current.people,
|
|
139157
|
+
settings: current.settings
|
|
139158
|
+
};
|
|
139159
|
+
}),
|
|
137436
139160
|
addProject: async ({ title, color, props }) => runWriteTransaction(async () => {
|
|
137437
139161
|
const state = core2.useTaskStore.getState();
|
|
137438
139162
|
await state.fetchData();
|
|
@@ -137824,8 +139548,9 @@ var createService = (options, deps = defaultServiceDeps) => {
|
|
|
137824
139548
|
const recurrence2 = normalizeOptionalTaskRecurrence(normalizedInput.recurrence);
|
|
137825
139549
|
return await runCoreWriteWithRetries(options, deps, async (core2) => {
|
|
137826
139550
|
if (normalizedInput.quickAdd) {
|
|
137827
|
-
const
|
|
137828
|
-
const
|
|
139551
|
+
const snapshot = await core2.getQuickAddSnapshot();
|
|
139552
|
+
const { projects, areas, tasks, people: people2, settings } = snapshot;
|
|
139553
|
+
const quick = deps.parseQuickAdd(normalizedInput.quickAdd, projects, undefined, areas, buildQuickAddParseOptions(settings, { tasks, people: people2 }));
|
|
137829
139554
|
let createdTask;
|
|
137830
139555
|
const capture2 = await executeCaptureTransaction({
|
|
137831
139556
|
parsed: {
|
|
@@ -137913,6 +139638,7 @@ var createService = (options, deps = defaultServiceDeps) => {
|
|
|
137913
139638
|
isSequential: input.isSequential,
|
|
137914
139639
|
isFocused: input.isFocused,
|
|
137915
139640
|
dueDate: input.dueDate ?? undefined,
|
|
139641
|
+
startDate: input.startDate ?? undefined,
|
|
137916
139642
|
reviewAt: input.reviewAt ?? undefined,
|
|
137917
139643
|
supportNotes: input.supportNotes ?? undefined
|
|
137918
139644
|
})
|
|
@@ -137934,6 +139660,8 @@ var createService = (options, deps = defaultServiceDeps) => {
|
|
|
137934
139660
|
updates.isFocused = input.isFocused;
|
|
137935
139661
|
if (input.dueDate !== undefined)
|
|
137936
139662
|
updates.dueDate = input.dueDate ?? undefined;
|
|
139663
|
+
if (input.startDate !== undefined)
|
|
139664
|
+
updates.startDate = input.startDate ?? undefined;
|
|
137937
139665
|
if (input.reviewAt !== undefined)
|
|
137938
139666
|
updates.reviewAt = input.reviewAt ?? undefined;
|
|
137939
139667
|
if (input.supportNotes !== undefined)
|
|
@@ -138310,6 +140038,7 @@ var addProjectSchema = objectType({
|
|
|
138310
140038
|
isSequential: booleanType().optional(),
|
|
138311
140039
|
isFocused: booleanType().optional(),
|
|
138312
140040
|
dueDate: isoDateLikeSchema.nullable().optional(),
|
|
140041
|
+
startDate: isoDateLikeSchema.nullable().optional(),
|
|
138313
140042
|
reviewAt: isoDateLikeSchema.nullable().optional(),
|
|
138314
140043
|
supportNotes: stringType().nullable().optional()
|
|
138315
140044
|
});
|
|
@@ -138322,6 +140051,7 @@ var updateProjectSchema = objectType({
|
|
|
138322
140051
|
isSequential: booleanType().optional(),
|
|
138323
140052
|
isFocused: booleanType().optional(),
|
|
138324
140053
|
dueDate: isoDateLikeSchema.nullable().optional(),
|
|
140054
|
+
startDate: isoDateLikeSchema.nullable().optional(),
|
|
138325
140055
|
reviewAt: isoDateLikeSchema.nullable().optional(),
|
|
138326
140056
|
supportNotes: stringType().nullable().optional()
|
|
138327
140057
|
});
|