fedipod 1.50.0 → 1.55.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/gateway.md +25 -0
- package/gui.md +11 -3
- package/lib/client/masto/render.mjs +11 -4
- package/lib/client/masto/timelines.mjs +5 -0
- package/lib/connections/acctfeed.mjs +4 -1
- package/lib/connections/tagfeed.mjs +4 -1
- package/lib/core/graphview.mjs +9 -1
- package/lib/core/intake/index.mjs +35 -2
- package/lib/core/intake/verify.mjs +3 -1
- package/lib/core/pod-only.mjs +4 -2
- package/lib/core/publisher/index.mjs +19 -5
- package/lib/core/publisher/restore.mjs +1 -0
- package/lib/core/store.mjs +27 -6
- package/lib/gateway/account-agent.mjs +11 -5
- package/lib/gateway/check-letter.mjs +123 -0
- package/lib/gateway/connected-feeds.mjs +116 -0
- package/lib/gateway/copy.mjs +19 -0
- package/lib/gateway/front-core.mjs +5 -3
- package/lib/gateway/held-mail.mjs +25 -1
- package/lib/gateway/keeper.mjs +2 -1
- package/lib/gateway/masto-gateway.mjs +47 -7
- package/lib/surface/routes/owner.mjs +7 -4
- package/package.json +3 -3
- package/scripts/stage-site.mjs +2 -3
- package/vendor/sanitize-html.cjs +358 -171
- package/web/admin/bar.js +45 -0
- package/web/admin/group.js +17 -0
- package/web/admin/index.html +12 -8
- package/web/admin/record.js +19 -41
- package/web/admin/upkeep.js +3 -0
- package/web/app/README.md +3 -3
- package/web/app/admin-facade.mjs +19 -16
- package/web/app/agent.mjs +68 -3
- package/web/app/atproto-browser.mjs +28 -22
- package/web/app/deliver-relay.mjs +2 -1
- package/web/app/dist/boot.js +1 -0
- package/web/app/dist/boot.js.map +2 -2
- package/web/app/dist/sw.js +601 -273
- package/web/app/dist/sw.js.map +4 -4
- package/web/app/fediacct-browser.mjs +32 -30
- package/web/app/idb-kv.mjs +4 -4
- package/web/app/shims/prelude.js +1 -0
- package/web/app/sw-src.mjs +44 -3
package/web/app/dist/sw.js
CHANGED
|
@@ -54,6 +54,7 @@ globalThis.Buffer ??= (() => {
|
|
|
54
54
|
concat: (list) => { const n = list.reduce((s, x) => s + x.length, 0); const o = new Buf(n); let i = 0; for (const x of list) { o.set(x, i); i += x.length; } return o; },
|
|
55
55
|
alloc: (n) => new Buf(n),
|
|
56
56
|
isBuffer: (x) => x instanceof Uint8Array,
|
|
57
|
+
byteLength: (d, enc) => (typeof d === 'string' ? fromString(d, enc).length : d.byteLength ?? d.length),
|
|
57
58
|
};
|
|
58
59
|
})();
|
|
59
60
|
|
|
@@ -3636,7 +3637,6 @@ var require_escape_string_regexp = __commonJS({
|
|
|
3636
3637
|
var require_is_plain_object = __commonJS({
|
|
3637
3638
|
"node_modules/is-plain-object/dist/is-plain-object.js"(exports) {
|
|
3638
3639
|
"use strict";
|
|
3639
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3640
3640
|
function isObject(o) {
|
|
3641
3641
|
return Object.prototype.toString.call(o) === "[object Object]";
|
|
3642
3642
|
}
|
|
@@ -3656,109 +3656,6 @@ var require_is_plain_object = __commonJS({
|
|
|
3656
3656
|
}
|
|
3657
3657
|
});
|
|
3658
3658
|
|
|
3659
|
-
// node_modules/deepmerge/dist/cjs.js
|
|
3660
|
-
var require_cjs = __commonJS({
|
|
3661
|
-
"node_modules/deepmerge/dist/cjs.js"(exports, module2) {
|
|
3662
|
-
"use strict";
|
|
3663
|
-
var isMergeableObject = function isMergeableObject2(value) {
|
|
3664
|
-
return isNonNullObject(value) && !isSpecial(value);
|
|
3665
|
-
};
|
|
3666
|
-
function isNonNullObject(value) {
|
|
3667
|
-
return !!value && typeof value === "object";
|
|
3668
|
-
}
|
|
3669
|
-
function isSpecial(value) {
|
|
3670
|
-
var stringValue = Object.prototype.toString.call(value);
|
|
3671
|
-
return stringValue === "[object RegExp]" || stringValue === "[object Date]" || isReactElement(value);
|
|
3672
|
-
}
|
|
3673
|
-
var canUseSymbol = typeof Symbol === "function" && Symbol.for;
|
|
3674
|
-
var REACT_ELEMENT_TYPE = canUseSymbol ? /* @__PURE__ */ Symbol.for("react.element") : 60103;
|
|
3675
|
-
function isReactElement(value) {
|
|
3676
|
-
return value.$$typeof === REACT_ELEMENT_TYPE;
|
|
3677
|
-
}
|
|
3678
|
-
function emptyTarget(val) {
|
|
3679
|
-
return Array.isArray(val) ? [] : {};
|
|
3680
|
-
}
|
|
3681
|
-
function cloneUnlessOtherwiseSpecified(value, options) {
|
|
3682
|
-
return options.clone !== false && options.isMergeableObject(value) ? deepmerge(emptyTarget(value), value, options) : value;
|
|
3683
|
-
}
|
|
3684
|
-
function defaultArrayMerge(target, source, options) {
|
|
3685
|
-
return target.concat(source).map(function(element) {
|
|
3686
|
-
return cloneUnlessOtherwiseSpecified(element, options);
|
|
3687
|
-
});
|
|
3688
|
-
}
|
|
3689
|
-
function getMergeFunction(key, options) {
|
|
3690
|
-
if (!options.customMerge) {
|
|
3691
|
-
return deepmerge;
|
|
3692
|
-
}
|
|
3693
|
-
var customMerge = options.customMerge(key);
|
|
3694
|
-
return typeof customMerge === "function" ? customMerge : deepmerge;
|
|
3695
|
-
}
|
|
3696
|
-
function getEnumerableOwnPropertySymbols(target) {
|
|
3697
|
-
return Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(target).filter(function(symbol) {
|
|
3698
|
-
return Object.propertyIsEnumerable.call(target, symbol);
|
|
3699
|
-
}) : [];
|
|
3700
|
-
}
|
|
3701
|
-
function getKeys(target) {
|
|
3702
|
-
return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target));
|
|
3703
|
-
}
|
|
3704
|
-
function propertyIsOnObject(object, property) {
|
|
3705
|
-
try {
|
|
3706
|
-
return property in object;
|
|
3707
|
-
} catch (_) {
|
|
3708
|
-
return false;
|
|
3709
|
-
}
|
|
3710
|
-
}
|
|
3711
|
-
function propertyIsUnsafe(target, key) {
|
|
3712
|
-
return propertyIsOnObject(target, key) && !(Object.hasOwnProperty.call(target, key) && Object.propertyIsEnumerable.call(target, key));
|
|
3713
|
-
}
|
|
3714
|
-
function mergeObject(target, source, options) {
|
|
3715
|
-
var destination = {};
|
|
3716
|
-
if (options.isMergeableObject(target)) {
|
|
3717
|
-
getKeys(target).forEach(function(key) {
|
|
3718
|
-
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
|
|
3719
|
-
});
|
|
3720
|
-
}
|
|
3721
|
-
getKeys(source).forEach(function(key) {
|
|
3722
|
-
if (propertyIsUnsafe(target, key)) {
|
|
3723
|
-
return;
|
|
3724
|
-
}
|
|
3725
|
-
if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) {
|
|
3726
|
-
destination[key] = getMergeFunction(key, options)(target[key], source[key], options);
|
|
3727
|
-
} else {
|
|
3728
|
-
destination[key] = cloneUnlessOtherwiseSpecified(source[key], options);
|
|
3729
|
-
}
|
|
3730
|
-
});
|
|
3731
|
-
return destination;
|
|
3732
|
-
}
|
|
3733
|
-
function deepmerge(target, source, options) {
|
|
3734
|
-
options = options || {};
|
|
3735
|
-
options.arrayMerge = options.arrayMerge || defaultArrayMerge;
|
|
3736
|
-
options.isMergeableObject = options.isMergeableObject || isMergeableObject;
|
|
3737
|
-
options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified;
|
|
3738
|
-
var sourceIsArray = Array.isArray(source);
|
|
3739
|
-
var targetIsArray = Array.isArray(target);
|
|
3740
|
-
var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;
|
|
3741
|
-
if (!sourceAndTargetTypesMatch) {
|
|
3742
|
-
return cloneUnlessOtherwiseSpecified(source, options);
|
|
3743
|
-
} else if (sourceIsArray) {
|
|
3744
|
-
return options.arrayMerge(target, source, options);
|
|
3745
|
-
} else {
|
|
3746
|
-
return mergeObject(target, source, options);
|
|
3747
|
-
}
|
|
3748
|
-
}
|
|
3749
|
-
deepmerge.all = function deepmergeAll(array, options) {
|
|
3750
|
-
if (!Array.isArray(array)) {
|
|
3751
|
-
throw new Error("first argument should be an array");
|
|
3752
|
-
}
|
|
3753
|
-
return array.reduce(function(prev, next) {
|
|
3754
|
-
return deepmerge(prev, next, options);
|
|
3755
|
-
}, {});
|
|
3756
|
-
};
|
|
3757
|
-
var deepmerge_1 = deepmerge;
|
|
3758
|
-
module2.exports = deepmerge_1;
|
|
3759
|
-
}
|
|
3760
|
-
});
|
|
3761
|
-
|
|
3762
3659
|
// node_modules/parse-srcset/src/parse-srcset.js
|
|
3763
3660
|
var require_parse_srcset = __commonJS({
|
|
3764
3661
|
"node_modules/parse-srcset/src/parse-srcset.js"(exports, module2) {
|
|
@@ -4037,14 +3934,7 @@ var require_css_syntax_error = __commonJS({
|
|
|
4037
3934
|
var require_stringifier = __commonJS({
|
|
4038
3935
|
"node_modules/postcss/lib/stringifier.js"(exports, module2) {
|
|
4039
3936
|
"use strict";
|
|
4040
|
-
var STYLE_TAG = /(<)(\/?style\b)/gi;
|
|
4041
|
-
var COMMENT_OPEN = /(<)(!--)/g;
|
|
4042
3937
|
var AT_NAME_END = /[\t\n\f\r "#'()/;[\\\]{}]/;
|
|
4043
|
-
function escapeHTMLInCSS(str) {
|
|
4044
|
-
if (typeof str !== "string") return str;
|
|
4045
|
-
if (!str.includes("<")) return str;
|
|
4046
|
-
return str.replace(STYLE_TAG, "\\3c $2").replace(COMMENT_OPEN, "\\3c $2");
|
|
4047
|
-
}
|
|
4048
3938
|
var DEFAULT_RAW = {
|
|
4049
3939
|
after: "\n",
|
|
4050
3940
|
beforeClose: "\n",
|
|
@@ -4073,6 +3963,11 @@ var require_stringifier = __commonJS({
|
|
|
4073
3963
|
}
|
|
4074
3964
|
return name + afterName + params;
|
|
4075
3965
|
}
|
|
3966
|
+
function isCustomProperty(node) {
|
|
3967
|
+
if (!node.prop.startsWith("--")) return false;
|
|
3968
|
+
let before = node.raws.before;
|
|
3969
|
+
return typeof before === "undefined" || !/[^\s;]$/.test(before);
|
|
3970
|
+
}
|
|
4076
3971
|
function pushBody(str, stack, node) {
|
|
4077
3972
|
let nodes = node.nodes;
|
|
4078
3973
|
let last = nodes.length - 1;
|
|
@@ -4085,7 +3980,7 @@ var require_stringifier = __commonJS({
|
|
|
4085
3980
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
4086
3981
|
let child = nodes[i];
|
|
4087
3982
|
let childSemicolon = last !== i || semicolon;
|
|
4088
|
-
if (!childSemicolon && i < nodes.length - 1 && (child.type === "atrule" && !child.nodes || child.type === "decl" && child
|
|
3983
|
+
if (!childSemicolon && i < nodes.length - 1 && (child.type === "atrule" && !child.nodes || child.type === "decl" && isCustomProperty(child))) {
|
|
4089
3984
|
childSemicolon = true;
|
|
4090
3985
|
}
|
|
4091
3986
|
stack.push({
|
|
@@ -4097,14 +3992,14 @@ var require_stringifier = __commonJS({
|
|
|
4097
3992
|
}
|
|
4098
3993
|
function pushBlock(str, stack, node, start) {
|
|
4099
3994
|
let between = str.raw(node, "between", "beforeOpen");
|
|
4100
|
-
str.builder(
|
|
3995
|
+
str.builder(start + between + "{", node, "start");
|
|
4101
3996
|
let hasNodes = node.nodes && node.nodes.length;
|
|
4102
3997
|
let close = () => {
|
|
4103
3998
|
let after = hasNodes ? str.raw(node, "after") : str.raw(node, "after", "emptyBody");
|
|
4104
|
-
if (after) str.builder(
|
|
3999
|
+
if (after) str.builder(after);
|
|
4105
4000
|
str.builder("}", node, "end");
|
|
4106
4001
|
if (node.type === "rule" && node.raws.ownSemicolon) {
|
|
4107
|
-
str.builder(
|
|
4002
|
+
str.builder(node.raws.ownSemicolon, node, "end");
|
|
4108
4003
|
}
|
|
4109
4004
|
};
|
|
4110
4005
|
if (hasNodes) {
|
|
@@ -4124,7 +4019,7 @@ var require_stringifier = __commonJS({
|
|
|
4124
4019
|
this.block(node, start);
|
|
4125
4020
|
} else {
|
|
4126
4021
|
let end = (node.raws.between || "") + (semicolon ? ";" : "");
|
|
4127
|
-
this.builder(
|
|
4022
|
+
this.builder(start + end, node);
|
|
4128
4023
|
}
|
|
4129
4024
|
}
|
|
4130
4025
|
beforeAfter(node, detect) {
|
|
@@ -4154,7 +4049,7 @@ var require_stringifier = __commonJS({
|
|
|
4154
4049
|
}
|
|
4155
4050
|
block(node, start) {
|
|
4156
4051
|
let between = this.raw(node, "between", "beforeOpen");
|
|
4157
|
-
this.builder(
|
|
4052
|
+
this.builder(start + between + "{", node, "start");
|
|
4158
4053
|
let after;
|
|
4159
4054
|
if (node.nodes && node.nodes.length) {
|
|
4160
4055
|
this.body(node);
|
|
@@ -4162,7 +4057,7 @@ var require_stringifier = __commonJS({
|
|
|
4162
4057
|
} else {
|
|
4163
4058
|
after = this.raw(node, "after", "emptyBody");
|
|
4164
4059
|
}
|
|
4165
|
-
if (after) this.builder(
|
|
4060
|
+
if (after) this.builder(after);
|
|
4166
4061
|
this.builder("}", node, "end");
|
|
4167
4062
|
}
|
|
4168
4063
|
body(node) {
|
|
@@ -4181,7 +4076,7 @@ var require_stringifier = __commonJS({
|
|
|
4181
4076
|
let child = entry.node;
|
|
4182
4077
|
let before = this.raw(child, "before");
|
|
4183
4078
|
if (before) {
|
|
4184
|
-
this.builder(
|
|
4079
|
+
this.builder(before);
|
|
4185
4080
|
}
|
|
4186
4081
|
if (expandable && child.type === "rule") {
|
|
4187
4082
|
pushBlock(this, stack, child, this.rawValue(child, "selector"));
|
|
@@ -4195,7 +4090,7 @@ var require_stringifier = __commonJS({
|
|
|
4195
4090
|
comment(node) {
|
|
4196
4091
|
let left = this.raw(node, "left", "commentLeft");
|
|
4197
4092
|
let right = this.raw(node, "right", "commentRight");
|
|
4198
|
-
this.builder(
|
|
4093
|
+
this.builder("/*" + left + node.text + right + "*/", node);
|
|
4199
4094
|
}
|
|
4200
4095
|
decl(node, semicolon) {
|
|
4201
4096
|
let raws = node.raws;
|
|
@@ -4205,7 +4100,7 @@ var require_stringifier = __commonJS({
|
|
|
4205
4100
|
string += raws.important || " !important";
|
|
4206
4101
|
}
|
|
4207
4102
|
if (semicolon) string += ";";
|
|
4208
|
-
this.builder(
|
|
4103
|
+
this.builder(string, node);
|
|
4209
4104
|
}
|
|
4210
4105
|
document(node) {
|
|
4211
4106
|
this.body(node);
|
|
@@ -4382,20 +4277,19 @@ var require_stringifier = __commonJS({
|
|
|
4382
4277
|
return value;
|
|
4383
4278
|
}
|
|
4384
4279
|
root(node) {
|
|
4385
|
-
|
|
4280
|
+
let inDocument = node.parent && node.parent.type === "document";
|
|
4281
|
+
if (!inDocument && node.source && node.source.input.hasBOM) {
|
|
4386
4282
|
this.builder("\uFEFF", node, "start");
|
|
4387
4283
|
}
|
|
4388
4284
|
this.body(node);
|
|
4389
4285
|
if (node.raws.after) {
|
|
4390
|
-
|
|
4391
|
-
let isDocument2 = node.parent && node.parent.type === "document";
|
|
4392
|
-
this.builder(isDocument2 ? after : escapeHTMLInCSS(after));
|
|
4286
|
+
this.builder(node.raws.after);
|
|
4393
4287
|
}
|
|
4394
4288
|
}
|
|
4395
4289
|
rule(node) {
|
|
4396
4290
|
this.block(node, this.rawValue(node, "selector"));
|
|
4397
4291
|
if (node.raws.ownSemicolon) {
|
|
4398
|
-
this.builder(
|
|
4292
|
+
this.builder(node.raws.ownSemicolon, node, "end");
|
|
4399
4293
|
}
|
|
4400
4294
|
}
|
|
4401
4295
|
stringify(node, semicolon) {
|
|
@@ -4417,9 +4311,78 @@ var require_stringify = __commonJS({
|
|
|
4417
4311
|
"node_modules/postcss/lib/stringify.js"(exports, module2) {
|
|
4418
4312
|
"use strict";
|
|
4419
4313
|
var Stringifier = require_stringifier();
|
|
4314
|
+
var STYLE_TAG = /(<)(\/?style\b)/gi;
|
|
4315
|
+
var COMMENT_OPEN = /(<)(!--)/g;
|
|
4316
|
+
function escapeHTMLInCSS(str) {
|
|
4317
|
+
if (!str.includes("<")) return str;
|
|
4318
|
+
return str.replace(STYLE_TAG, "\\3c $2").replace(COMMENT_OPEN, "\\3c $2");
|
|
4319
|
+
}
|
|
4320
|
+
function cutEscaped(chunks, css, escaped) {
|
|
4321
|
+
let parts = [];
|
|
4322
|
+
let at = 0;
|
|
4323
|
+
let into = 0;
|
|
4324
|
+
for (let i = 0; i < chunks.length; i += 3) {
|
|
4325
|
+
let from = into;
|
|
4326
|
+
let end = at + chunks[i].length;
|
|
4327
|
+
while (at < end) {
|
|
4328
|
+
if (css[at] === escaped[into]) {
|
|
4329
|
+
at += 1;
|
|
4330
|
+
into += 1;
|
|
4331
|
+
} else {
|
|
4332
|
+
at += 1;
|
|
4333
|
+
into += 4;
|
|
4334
|
+
}
|
|
4335
|
+
}
|
|
4336
|
+
parts.push(escaped.slice(from, into));
|
|
4337
|
+
}
|
|
4338
|
+
return parts;
|
|
4339
|
+
}
|
|
4340
|
+
var SafeStringifier = class extends Stringifier {
|
|
4341
|
+
escapeHTML(print) {
|
|
4342
|
+
let builder111 = this.builder;
|
|
4343
|
+
let chunks, css;
|
|
4344
|
+
this.builder = (str, child, type) => {
|
|
4345
|
+
if (chunks) {
|
|
4346
|
+
css += str;
|
|
4347
|
+
chunks.push(str, child, type);
|
|
4348
|
+
} else if (str.includes("<")) {
|
|
4349
|
+
css = str;
|
|
4350
|
+
chunks = [str, child, type];
|
|
4351
|
+
} else {
|
|
4352
|
+
builder111(str, child, type);
|
|
4353
|
+
}
|
|
4354
|
+
};
|
|
4355
|
+
print();
|
|
4356
|
+
this.builder = builder111;
|
|
4357
|
+
if (!chunks) return;
|
|
4358
|
+
let escaped = escapeHTMLInCSS(css);
|
|
4359
|
+
if (escaped === css) {
|
|
4360
|
+
for (let i = 0; i < chunks.length; i += 3) {
|
|
4361
|
+
builder111(chunks[i], chunks[i + 1], chunks[i + 2]);
|
|
4362
|
+
}
|
|
4363
|
+
} else {
|
|
4364
|
+
let parts = cutEscaped(chunks, css, escaped);
|
|
4365
|
+
for (let i = 0; i < chunks.length; i += 3) {
|
|
4366
|
+
builder111(parts[i / 3], chunks[i + 1], chunks[i + 2]);
|
|
4367
|
+
}
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
root(node) {
|
|
4371
|
+
if (node.parent && node.parent.type === "document") {
|
|
4372
|
+
this.escapeHTML(() => this.body(node));
|
|
4373
|
+
if (node.raws.after) this.builder(node.raws.after);
|
|
4374
|
+
} else {
|
|
4375
|
+
this.escapeHTML(() => super.root(node));
|
|
4376
|
+
}
|
|
4377
|
+
}
|
|
4378
|
+
};
|
|
4420
4379
|
function stringify(node, builder111) {
|
|
4421
|
-
let str = new
|
|
4422
|
-
|
|
4380
|
+
let str = new SafeStringifier(builder111);
|
|
4381
|
+
if (node.type === "root" || node.type === "document") {
|
|
4382
|
+
str.stringify(node);
|
|
4383
|
+
} else {
|
|
4384
|
+
str.escapeHTML(() => str.stringify(node));
|
|
4385
|
+
}
|
|
4423
4386
|
}
|
|
4424
4387
|
module2.exports = stringify;
|
|
4425
4388
|
stringify.default = stringify;
|
|
@@ -5419,9 +5382,16 @@ var require_fs = __commonJS({
|
|
|
5419
5382
|
var require_previous_map = __commonJS({
|
|
5420
5383
|
"node_modules/postcss/lib/previous-map.js"(exports, module2) {
|
|
5421
5384
|
"use strict";
|
|
5422
|
-
var { existsSync: existsSync2, readFileSync: readFileSync2 } = require_fs();
|
|
5385
|
+
var { existsSync: existsSync2, readFileSync: readFileSync2, realpathSync } = require_fs();
|
|
5423
5386
|
var { dirname: dirname2, isAbsolute, join: join3, relative, sep } = require_path();
|
|
5424
5387
|
var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
|
|
5388
|
+
function realPath(path) {
|
|
5389
|
+
try {
|
|
5390
|
+
return realpathSync(path);
|
|
5391
|
+
} catch {
|
|
5392
|
+
return path;
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5425
5395
|
function fromBase64(str) {
|
|
5426
5396
|
if (Buffer) {
|
|
5427
5397
|
return Buffer.from(str, "base64").toString();
|
|
@@ -5486,7 +5456,7 @@ var require_previous_map = __commonJS({
|
|
|
5486
5456
|
if (!trusted && !this.unsafeMap) {
|
|
5487
5457
|
if (!/\.map$/i.test(path)) return void 0;
|
|
5488
5458
|
if (!cssFile) return void 0;
|
|
5489
|
-
let rel = relative(dirname2(cssFile), path);
|
|
5459
|
+
let rel = relative(realPath(dirname2(cssFile)), realPath(path));
|
|
5490
5460
|
if (rel === ".." || rel.startsWith(".." + sep) || isAbsolute(rel)) {
|
|
5491
5461
|
return void 0;
|
|
5492
5462
|
}
|
|
@@ -5862,6 +5832,7 @@ var require_list = __commonJS({
|
|
|
5862
5832
|
return list3.split(string, spaces);
|
|
5863
5833
|
},
|
|
5864
5834
|
split(string, separators, last) {
|
|
5835
|
+
if (typeof string !== "string") return [];
|
|
5865
5836
|
let array = [];
|
|
5866
5837
|
let current = "";
|
|
5867
5838
|
let split = false;
|
|
@@ -5869,7 +5840,18 @@ var require_list = __commonJS({
|
|
|
5869
5840
|
let inQuote = false;
|
|
5870
5841
|
let prevQuote = "";
|
|
5871
5842
|
let escape2 = false;
|
|
5872
|
-
|
|
5843
|
+
let inComment = false;
|
|
5844
|
+
for (let i = 0; i < string.length; i++) {
|
|
5845
|
+
let letter = string[i];
|
|
5846
|
+
if (inComment) {
|
|
5847
|
+
current += letter;
|
|
5848
|
+
if (letter === "*" && string[i + 1] === "/") {
|
|
5849
|
+
current += "/";
|
|
5850
|
+
i += 1;
|
|
5851
|
+
inComment = false;
|
|
5852
|
+
}
|
|
5853
|
+
continue;
|
|
5854
|
+
}
|
|
5873
5855
|
if (escape2) {
|
|
5874
5856
|
escape2 = false;
|
|
5875
5857
|
} else if (letter === "\\") {
|
|
@@ -5881,6 +5863,11 @@ var require_list = __commonJS({
|
|
|
5881
5863
|
} else if (letter === '"' || letter === "'") {
|
|
5882
5864
|
inQuote = true;
|
|
5883
5865
|
prevQuote = letter;
|
|
5866
|
+
} else if (letter === "/" && string[i + 1] === "*") {
|
|
5867
|
+
current += "/*";
|
|
5868
|
+
i += 1;
|
|
5869
|
+
inComment = true;
|
|
5870
|
+
continue;
|
|
5884
5871
|
} else if (letter === "(") {
|
|
5885
5872
|
func += 1;
|
|
5886
5873
|
} else if (letter === ")") {
|
|
@@ -5889,14 +5876,16 @@ var require_list = __commonJS({
|
|
|
5889
5876
|
if (separators.includes(letter)) split = true;
|
|
5890
5877
|
}
|
|
5891
5878
|
if (split) {
|
|
5892
|
-
|
|
5879
|
+
let value2 = current.trim();
|
|
5880
|
+
if (last || value2 !== "") array.push(value2);
|
|
5893
5881
|
current = "";
|
|
5894
5882
|
split = false;
|
|
5895
5883
|
} else {
|
|
5896
5884
|
current += letter;
|
|
5897
5885
|
}
|
|
5898
5886
|
}
|
|
5899
|
-
|
|
5887
|
+
let value = current.trim();
|
|
5888
|
+
if (last || value !== "") array.push(value);
|
|
5900
5889
|
return array;
|
|
5901
5890
|
}
|
|
5902
5891
|
};
|
|
@@ -6092,15 +6081,20 @@ var require_map_generator = __commonJS({
|
|
|
6092
6081
|
}
|
|
6093
6082
|
}
|
|
6094
6083
|
} else if (this.css) {
|
|
6084
|
+
let annotation = "/*# sourceMappingURL=";
|
|
6085
|
+
let css = "";
|
|
6086
|
+
let cursor = 0;
|
|
6095
6087
|
let startIndex;
|
|
6096
|
-
while ((startIndex = this.css.
|
|
6097
|
-
let endIndex = this.css.indexOf("*/", startIndex +
|
|
6088
|
+
while ((startIndex = this.css.indexOf(annotation, cursor)) !== -1) {
|
|
6089
|
+
let endIndex = this.css.indexOf("*/", startIndex + annotation.length);
|
|
6098
6090
|
if (endIndex === -1) break;
|
|
6099
|
-
while (startIndex >
|
|
6091
|
+
while (startIndex > cursor && this.css[startIndex - 1] === "\n") {
|
|
6100
6092
|
startIndex--;
|
|
6101
6093
|
}
|
|
6102
|
-
|
|
6094
|
+
css += this.css.slice(cursor, startIndex);
|
|
6095
|
+
cursor = endIndex + 2;
|
|
6103
6096
|
}
|
|
6097
|
+
if (cursor > 0) this.css = css + this.css.slice(cursor);
|
|
6104
6098
|
}
|
|
6105
6099
|
}
|
|
6106
6100
|
generate() {
|
|
@@ -6881,7 +6875,7 @@ var require_parser = __commonJS({
|
|
|
6881
6875
|
prev.raws.ownSemicolon = this.spaces;
|
|
6882
6876
|
this.spaces = "";
|
|
6883
6877
|
prev.source.end = this.getPosition(token[2]);
|
|
6884
|
-
prev.source.end.offset
|
|
6878
|
+
prev.source.end.offset++;
|
|
6885
6879
|
}
|
|
6886
6880
|
}
|
|
6887
6881
|
}
|
|
@@ -6997,6 +6991,7 @@ var require_parser = __commonJS({
|
|
|
6997
6991
|
let token, type;
|
|
6998
6992
|
let length = tokens2.length;
|
|
6999
6993
|
let value = "";
|
|
6994
|
+
let last = "";
|
|
7000
6995
|
let clean = true;
|
|
7001
6996
|
let next, prev;
|
|
7002
6997
|
for (let i = 0; i < length; i += 1) {
|
|
@@ -7008,16 +7003,18 @@ var require_parser = __commonJS({
|
|
|
7008
7003
|
prev = tokens2[i - 1] ? tokens2[i - 1][0] : "empty";
|
|
7009
7004
|
next = tokens2[i + 1] ? tokens2[i + 1][0] : "empty";
|
|
7010
7005
|
if (!SAFE_COMMENT_NEIGHBOR[prev] && !SAFE_COMMENT_NEIGHBOR[next]) {
|
|
7011
|
-
if (
|
|
7006
|
+
if (last === ",") {
|
|
7012
7007
|
clean = false;
|
|
7013
7008
|
} else {
|
|
7014
7009
|
value += token[1];
|
|
7010
|
+
last = token[1].slice(-1);
|
|
7015
7011
|
}
|
|
7016
7012
|
} else {
|
|
7017
7013
|
clean = false;
|
|
7018
7014
|
}
|
|
7019
7015
|
} else {
|
|
7020
7016
|
value += token[1];
|
|
7017
|
+
last = token[1].slice(-1);
|
|
7021
7018
|
}
|
|
7022
7019
|
}
|
|
7023
7020
|
if (!clean) {
|
|
@@ -7667,14 +7664,19 @@ var require_lazy_result = __commonJS({
|
|
|
7667
7664
|
}
|
|
7668
7665
|
if (visit.iterator !== 0) {
|
|
7669
7666
|
let iterator = visit.iterator;
|
|
7667
|
+
if (visit.descending) {
|
|
7668
|
+
visit.descending = false;
|
|
7669
|
+
node.indexes[iterator] += 1;
|
|
7670
|
+
}
|
|
7670
7671
|
let child;
|
|
7671
7672
|
while (child = node.nodes[node.indexes[iterator]]) {
|
|
7672
|
-
node.indexes[iterator] += 1;
|
|
7673
7673
|
if (!child[isClean]) {
|
|
7674
7674
|
child[isClean] = true;
|
|
7675
|
+
visit.descending = true;
|
|
7675
7676
|
stack.push(toStack(child));
|
|
7676
7677
|
return;
|
|
7677
7678
|
}
|
|
7679
|
+
node.indexes[iterator] += 1;
|
|
7678
7680
|
}
|
|
7679
7681
|
visit.iterator = 0;
|
|
7680
7682
|
delete node.indexes[iterator];
|
|
@@ -7704,12 +7706,16 @@ var require_lazy_result = __commonJS({
|
|
|
7704
7706
|
let visitNode = visit.node;
|
|
7705
7707
|
if (visit.iterator !== 0) {
|
|
7706
7708
|
let iterator = visit.iterator;
|
|
7709
|
+
if (visit.descending) {
|
|
7710
|
+
visit.descending = false;
|
|
7711
|
+
visitNode.indexes[iterator] += 1;
|
|
7712
|
+
}
|
|
7707
7713
|
let child;
|
|
7708
7714
|
let descended = false;
|
|
7709
7715
|
while (child = visitNode.nodes[visitNode.indexes[iterator]]) {
|
|
7710
|
-
visitNode.indexes[iterator] += 1;
|
|
7711
7716
|
if (!child[isClean]) {
|
|
7712
7717
|
child[isClean] = true;
|
|
7718
|
+
visit.descending = true;
|
|
7713
7719
|
stack.push({
|
|
7714
7720
|
eventIndex: 0,
|
|
7715
7721
|
events: getEvents(child),
|
|
@@ -7719,6 +7725,7 @@ var require_lazy_result = __commonJS({
|
|
|
7719
7725
|
descended = true;
|
|
7720
7726
|
break;
|
|
7721
7727
|
}
|
|
7728
|
+
visitNode.indexes[iterator] += 1;
|
|
7722
7729
|
}
|
|
7723
7730
|
if (descended) continue;
|
|
7724
7731
|
visit.iterator = 0;
|
|
@@ -7881,7 +7888,7 @@ var require_processor = __commonJS({
|
|
|
7881
7888
|
var Root2 = require_root();
|
|
7882
7889
|
var Processor = class {
|
|
7883
7890
|
constructor(plugins = []) {
|
|
7884
|
-
this.version = "8.5.
|
|
7891
|
+
this.version = "8.5.31";
|
|
7885
7892
|
this.plugins = this.normalize(plugins);
|
|
7886
7893
|
}
|
|
7887
7894
|
normalize(plugins) {
|
|
@@ -7965,7 +7972,7 @@ var require_postcss = __commonJS({
|
|
|
7965
7972
|
console.warn(
|
|
7966
7973
|
name + ": postcss.plugin was deprecated. Migration guide:\nhttps://evilmartians.com/chronicles/postcss-8-plugin-migration"
|
|
7967
7974
|
);
|
|
7968
|
-
if (process.env.LANG && process.env.LANG.startsWith("
|
|
7975
|
+
if (process.env.LANG && process.env.LANG.startsWith("zh")) {
|
|
7969
7976
|
console.warn(
|
|
7970
7977
|
name + ": \u91CC\u9762 postcss.plugin \u88AB\u5F03\u7528. \u8FC1\u79FB\u6307\u5357:\nhttps://www.w3ctech.com/topic/2226"
|
|
7971
7978
|
);
|
|
@@ -8672,7 +8679,6 @@ var require_sanitize_html = __commonJS({
|
|
|
8672
8679
|
var htmlparser = (init_dist6(), __toCommonJS(dist_exports3));
|
|
8673
8680
|
var escapeStringRegexp = require_escape_string_regexp();
|
|
8674
8681
|
var { isPlainObject } = require_is_plain_object();
|
|
8675
|
-
var deepmerge = require_cjs();
|
|
8676
8682
|
var parseSrcset = require_parse_srcset();
|
|
8677
8683
|
var { parse: postcssParse } = require_postcss();
|
|
8678
8684
|
var { naughtyHref: launderNaughtyHref } = require_launder();
|
|
@@ -8696,6 +8702,15 @@ var require_sanitize_html = __commonJS({
|
|
|
8696
8702
|
"set"
|
|
8697
8703
|
];
|
|
8698
8704
|
var alwaysUrlAttributes = ["href"];
|
|
8705
|
+
var severities = ["debug", "info", "warn", "error"];
|
|
8706
|
+
function loggerFor(options) {
|
|
8707
|
+
const source = options && options.logger || console;
|
|
8708
|
+
const logger = {};
|
|
8709
|
+
for (const severity of severities) {
|
|
8710
|
+
logger[severity] = typeof source[severity] === "function" ? (...args) => source[severity](...args) : (...args) => console[severity](...args);
|
|
8711
|
+
}
|
|
8712
|
+
return logger;
|
|
8713
|
+
}
|
|
8699
8714
|
function each(obj, cb) {
|
|
8700
8715
|
if (obj) {
|
|
8701
8716
|
Object.keys(obj).forEach(function(key) {
|
|
@@ -8706,6 +8721,21 @@ var require_sanitize_html = __commonJS({
|
|
|
8706
8721
|
function has(obj, key) {
|
|
8707
8722
|
return {}.hasOwnProperty.call(obj, key);
|
|
8708
8723
|
}
|
|
8724
|
+
function mergeClasses(specific, wildcard) {
|
|
8725
|
+
if (!Array.isArray(specific) || !Array.isArray(wildcard)) {
|
|
8726
|
+
return wildcard;
|
|
8727
|
+
}
|
|
8728
|
+
return specific.concat(wildcard);
|
|
8729
|
+
}
|
|
8730
|
+
function mergeStyles(specific, wildcard) {
|
|
8731
|
+
const merged = /* @__PURE__ */ Object.create(null);
|
|
8732
|
+
for (const rules of [specific, wildcard]) {
|
|
8733
|
+
for (const prop of Object.keys(rules)) {
|
|
8734
|
+
merged[prop] = has(merged, prop) ? merged[prop].concat(rules[prop]) : rules[prop];
|
|
8735
|
+
}
|
|
8736
|
+
}
|
|
8737
|
+
return merged;
|
|
8738
|
+
}
|
|
8709
8739
|
function filter2(a, cb) {
|
|
8710
8740
|
const n = [];
|
|
8711
8741
|
each(a, function(v) {
|
|
@@ -8733,10 +8763,13 @@ var require_sanitize_html = __commonJS({
|
|
|
8733
8763
|
}
|
|
8734
8764
|
module2.exports = sanitizeHtml2;
|
|
8735
8765
|
var VALID_HTML_ATTRIBUTE_NAME = /^[^\0\t\n\f\r /<=>]+$/;
|
|
8736
|
-
|
|
8766
|
+
var MAX_IFRAME_FALLBACK_DEPTH = 8;
|
|
8767
|
+
function sanitizeHtml2(html, options, _fallback) {
|
|
8737
8768
|
if (html == null) {
|
|
8738
8769
|
return "";
|
|
8739
8770
|
}
|
|
8771
|
+
const baseDepth = _fallback && _fallback.depth || 0;
|
|
8772
|
+
const iframeFallbackDepth = _fallback && _fallback.iframeFallbackDepth || 0;
|
|
8740
8773
|
if (typeof html === "number") {
|
|
8741
8774
|
html = html.toString();
|
|
8742
8775
|
}
|
|
@@ -8765,19 +8798,15 @@ var require_sanitize_html = __commonJS({
|
|
|
8765
8798
|
}
|
|
8766
8799
|
options = Object.assign({}, sanitizeHtml2.defaults, options);
|
|
8767
8800
|
options.parser = Object.assign({}, htmlParserDefaults, options.parser);
|
|
8801
|
+
const logger = loggerFor(options);
|
|
8768
8802
|
const tagAllowed = function(name) {
|
|
8769
8803
|
return options.allowedTags === false || (options.allowedTags || []).indexOf(name) > -1;
|
|
8770
8804
|
};
|
|
8771
8805
|
vulnerableTags.forEach(function(tag) {
|
|
8772
8806
|
if (tagAllowed(tag) && !options.allowVulnerableTags) {
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
8776
|
-
vulnerable to XSS attacks. Please remove it from \`allowedTags\`.
|
|
8777
|
-
Or, to disable this warning, add the \`allowVulnerableTags\` option
|
|
8778
|
-
and ensure you are accounting for this risk.
|
|
8779
|
-
|
|
8780
|
-
`);
|
|
8807
|
+
logger.warn(
|
|
8808
|
+
`Your \`allowedTags\` option includes \`${tag}\`, which is inherently vulnerable to XSS attacks. Please remove it from \`allowedTags\`, or, to disable this warning, add the \`allowVulnerableTags\` option and ensure you are accounting for this risk.`
|
|
8809
|
+
);
|
|
8781
8810
|
}
|
|
8782
8811
|
});
|
|
8783
8812
|
const nonTextTagsArray = options.nonTextTags || [
|
|
@@ -8857,6 +8886,8 @@ and ensure you are accounting for this risk.
|
|
|
8857
8886
|
let transformMap;
|
|
8858
8887
|
let skipText;
|
|
8859
8888
|
let skipTextDepth;
|
|
8889
|
+
let rawTextEnd;
|
|
8890
|
+
let skipRawText;
|
|
8860
8891
|
let addedText = false;
|
|
8861
8892
|
initializeState();
|
|
8862
8893
|
const parser = new htmlparser.Parser({
|
|
@@ -8864,9 +8895,13 @@ and ensure you are accounting for this risk.
|
|
|
8864
8895
|
if (options.onOpenTag) {
|
|
8865
8896
|
options.onOpenTag(name, attribs);
|
|
8866
8897
|
}
|
|
8898
|
+
updateRawTextRegion();
|
|
8867
8899
|
if (options.enforceHtmlBoundary && name === "html") {
|
|
8868
8900
|
initializeState();
|
|
8869
8901
|
}
|
|
8902
|
+
if (skipRawText) {
|
|
8903
|
+
return;
|
|
8904
|
+
}
|
|
8870
8905
|
if (skipText) {
|
|
8871
8906
|
skipTextDepth++;
|
|
8872
8907
|
return;
|
|
@@ -8902,6 +8937,9 @@ and ensure you are accounting for this risk.
|
|
|
8902
8937
|
if (nonTextTagsArray.indexOf(name) !== -1) {
|
|
8903
8938
|
skipText = true;
|
|
8904
8939
|
skipTextDepth = 1;
|
|
8940
|
+
if (frame.tag.toLowerCase() === "noscript") {
|
|
8941
|
+
rawTextEnd = findRawTextEnd("noscript", parser.endIndex + 1);
|
|
8942
|
+
}
|
|
8905
8943
|
}
|
|
8906
8944
|
}
|
|
8907
8945
|
}
|
|
@@ -8977,6 +9015,10 @@ and ensure you are accounting for this risk.
|
|
|
8977
9015
|
return;
|
|
8978
9016
|
}
|
|
8979
9017
|
}
|
|
9018
|
+
if (name === "meta" && a.toLowerCase() === "content" && isRefresh(attribs) && naughtyRefresh(value)) {
|
|
9019
|
+
delete frame.attribs[a];
|
|
9020
|
+
return;
|
|
9021
|
+
}
|
|
8980
9022
|
if (name === "script" && a === "src") {
|
|
8981
9023
|
let allowed = true;
|
|
8982
9024
|
try {
|
|
@@ -9025,7 +9067,7 @@ and ensure you are accounting for this risk.
|
|
|
9025
9067
|
try {
|
|
9026
9068
|
let parsed = parseSrcset(value);
|
|
9027
9069
|
parsed.forEach(function(value2) {
|
|
9028
|
-
if (naughtyHref(
|
|
9070
|
+
if (naughtyHref(name, value2.url)) {
|
|
9029
9071
|
value2.evil = true;
|
|
9030
9072
|
}
|
|
9031
9073
|
});
|
|
@@ -9062,7 +9104,7 @@ and ensure you are accounting for this risk.
|
|
|
9062
9104
|
if (allowedSpecificClasses && allowedWildcardClasses) {
|
|
9063
9105
|
value = filterClasses(
|
|
9064
9106
|
value,
|
|
9065
|
-
|
|
9107
|
+
mergeClasses(allowedSpecificClasses, allowedWildcardClasses),
|
|
9066
9108
|
allowedClassesGlobs
|
|
9067
9109
|
);
|
|
9068
9110
|
} else {
|
|
@@ -9092,7 +9134,9 @@ and ensure you are accounting for this risk.
|
|
|
9092
9134
|
}
|
|
9093
9135
|
} catch (e) {
|
|
9094
9136
|
if (typeof window !== "undefined") {
|
|
9095
|
-
|
|
9137
|
+
logger.warn(
|
|
9138
|
+
`Failed to parse "${name} {${value}}". If you are running this in a browser, we recommend disabling style parsing with the parseStyleAttributes option, since it only works in a node environment due to a postcss dependency. More info: https://github.com/apostrophecms/sanitize-html/issues/547`
|
|
9139
|
+
);
|
|
9096
9140
|
}
|
|
9097
9141
|
delete frame.attribs[a];
|
|
9098
9142
|
return;
|
|
@@ -9133,7 +9177,8 @@ and ensure you are accounting for this risk.
|
|
|
9133
9177
|
frame.openingTagLength = result.length - frame.tagPosition;
|
|
9134
9178
|
},
|
|
9135
9179
|
ontext: function(text) {
|
|
9136
|
-
|
|
9180
|
+
updateRawTextRegion();
|
|
9181
|
+
if (skipText || skipRawText) {
|
|
9137
9182
|
return;
|
|
9138
9183
|
}
|
|
9139
9184
|
const lastFrame = stack[stack.length - 1];
|
|
@@ -9152,6 +9197,19 @@ and ensure you are accounting for this risk.
|
|
|
9152
9197
|
} else {
|
|
9153
9198
|
result += escapeHtml2(text, false);
|
|
9154
9199
|
}
|
|
9200
|
+
} else if (
|
|
9201
|
+
// htmlparser2 treats <iframe> as a raw-text element, so markup inside
|
|
9202
|
+
// (including after an unclosed <iframe>) arrives as a single text node.
|
|
9203
|
+
// When the iframe is discarded, re-sanitize that fallback markup as HTML
|
|
9204
|
+
// instead of escaping it as plain text (issue #5550).
|
|
9205
|
+
// The nested call continues from the current depth so that
|
|
9206
|
+
// `nestingLimit` applies to the whole output.
|
|
9207
|
+
tag === "iframe" && !tagAllowed(tag) && options.disallowedTagsMode === "discard" && iframeFallbackDepth < MAX_IFRAME_FALLBACK_DEPTH
|
|
9208
|
+
) {
|
|
9209
|
+
result += sanitizeHtml2(text, options, {
|
|
9210
|
+
depth,
|
|
9211
|
+
iframeFallbackDepth: iframeFallbackDepth + 1
|
|
9212
|
+
});
|
|
9155
9213
|
} else if (!addedText) {
|
|
9156
9214
|
const escaped = escapeHtml2(text, false);
|
|
9157
9215
|
if (options.textFilter) {
|
|
@@ -9169,10 +9227,19 @@ and ensure you are accounting for this risk.
|
|
|
9169
9227
|
if (options.onCloseTag) {
|
|
9170
9228
|
options.onCloseTag(name, isImplied);
|
|
9171
9229
|
}
|
|
9172
|
-
|
|
9230
|
+
updateRawTextRegion();
|
|
9231
|
+
if (skipRawText) {
|
|
9232
|
+
const lastFrame = stack[stack.length - 1];
|
|
9233
|
+
if (!lastFrame || lastFrame.tag !== name) {
|
|
9234
|
+
return;
|
|
9235
|
+
}
|
|
9236
|
+
} else if (skipText) {
|
|
9173
9237
|
skipTextDepth--;
|
|
9174
9238
|
if (!skipTextDepth) {
|
|
9175
9239
|
skipText = false;
|
|
9240
|
+
if (rawTextEnd !== null) {
|
|
9241
|
+
skipRawText = true;
|
|
9242
|
+
}
|
|
9176
9243
|
} else {
|
|
9177
9244
|
return;
|
|
9178
9245
|
}
|
|
@@ -9250,12 +9317,26 @@ and ensure you are accounting for this risk.
|
|
|
9250
9317
|
return result;
|
|
9251
9318
|
function initializeState() {
|
|
9252
9319
|
result = "";
|
|
9253
|
-
depth =
|
|
9320
|
+
depth = baseDepth;
|
|
9254
9321
|
stack = [];
|
|
9255
9322
|
skipMap = {};
|
|
9256
9323
|
transformMap = {};
|
|
9257
9324
|
skipText = false;
|
|
9258
9325
|
skipTextDepth = 0;
|
|
9326
|
+
rawTextEnd = null;
|
|
9327
|
+
skipRawText = false;
|
|
9328
|
+
}
|
|
9329
|
+
function updateRawTextRegion() {
|
|
9330
|
+
if (rawTextEnd !== null && parser.startIndex >= rawTextEnd) {
|
|
9331
|
+
rawTextEnd = null;
|
|
9332
|
+
skipRawText = false;
|
|
9333
|
+
}
|
|
9334
|
+
}
|
|
9335
|
+
function findRawTextEnd(tagName, from) {
|
|
9336
|
+
const re = new RegExp("</" + tagName + "[\\t\\n\\f\\r />]", "ig");
|
|
9337
|
+
re.lastIndex = from;
|
|
9338
|
+
const match = re.exec(html);
|
|
9339
|
+
return match ? match.index : Infinity;
|
|
9259
9340
|
}
|
|
9260
9341
|
function escapeHtml2(s, quote) {
|
|
9261
9342
|
if (typeof s !== "string") {
|
|
@@ -9280,13 +9361,83 @@ and ensure you are accounting for this risk.
|
|
|
9280
9361
|
allowProtocolRelative: options.allowProtocolRelative
|
|
9281
9362
|
});
|
|
9282
9363
|
}
|
|
9364
|
+
function isRefresh(attribs) {
|
|
9365
|
+
return Object.keys(attribs).some(function(a) {
|
|
9366
|
+
return a.toLowerCase() === "http-equiv" && String(attribs[a]).trim().toLowerCase() === "refresh";
|
|
9367
|
+
});
|
|
9368
|
+
}
|
|
9369
|
+
function naughtyRefresh(content) {
|
|
9370
|
+
const input = String(content);
|
|
9371
|
+
const isWhitespace2 = function(c) {
|
|
9372
|
+
return c === " " || c === " " || c === "\n" || c === "\f" || c === "\r";
|
|
9373
|
+
};
|
|
9374
|
+
let position = 0;
|
|
9375
|
+
const skipWhitespace = function() {
|
|
9376
|
+
while (position < input.length && isWhitespace2(input[position])) {
|
|
9377
|
+
position++;
|
|
9378
|
+
}
|
|
9379
|
+
};
|
|
9380
|
+
const lowerAt = function(i) {
|
|
9381
|
+
return (input[i] || "").toLowerCase();
|
|
9382
|
+
};
|
|
9383
|
+
skipWhitespace();
|
|
9384
|
+
const timeStart = position;
|
|
9385
|
+
while (position < input.length && /[0-9.]/.test(input[position])) {
|
|
9386
|
+
position++;
|
|
9387
|
+
}
|
|
9388
|
+
if (position === timeStart) {
|
|
9389
|
+
return true;
|
|
9390
|
+
}
|
|
9391
|
+
if (position < input.length) {
|
|
9392
|
+
const c = input[position];
|
|
9393
|
+
if (c !== ";" && c !== "," && !isWhitespace2(c)) {
|
|
9394
|
+
return true;
|
|
9395
|
+
}
|
|
9396
|
+
skipWhitespace();
|
|
9397
|
+
if (input[position] === ";" || input[position] === ",") {
|
|
9398
|
+
position++;
|
|
9399
|
+
}
|
|
9400
|
+
skipWhitespace();
|
|
9401
|
+
}
|
|
9402
|
+
if (position >= input.length) {
|
|
9403
|
+
return false;
|
|
9404
|
+
}
|
|
9405
|
+
let url = input.slice(position);
|
|
9406
|
+
let quoted = true;
|
|
9407
|
+
if (lowerAt(position) === "u") {
|
|
9408
|
+
quoted = false;
|
|
9409
|
+
if (lowerAt(position + 1) === "r" && lowerAt(position + 2) === "l") {
|
|
9410
|
+
position += 3;
|
|
9411
|
+
skipWhitespace();
|
|
9412
|
+
if (input[position] === "=") {
|
|
9413
|
+
position++;
|
|
9414
|
+
skipWhitespace();
|
|
9415
|
+
quoted = true;
|
|
9416
|
+
}
|
|
9417
|
+
}
|
|
9418
|
+
}
|
|
9419
|
+
if (quoted) {
|
|
9420
|
+
const quote = input[position];
|
|
9421
|
+
if (quote === '"' || quote === "'") {
|
|
9422
|
+
position++;
|
|
9423
|
+
}
|
|
9424
|
+
url = input.slice(position);
|
|
9425
|
+
if (quote === '"' || quote === "'") {
|
|
9426
|
+
const end = url.indexOf(quote);
|
|
9427
|
+
if (end !== -1) {
|
|
9428
|
+
url = url.slice(0, end);
|
|
9429
|
+
}
|
|
9430
|
+
}
|
|
9431
|
+
}
|
|
9432
|
+
return naughtyHref("meta", url);
|
|
9433
|
+
}
|
|
9283
9434
|
function animatesUrlAttribute(name, attribs) {
|
|
9284
|
-
if (svgAnimationTags.indexOf(name
|
|
9435
|
+
if (svgAnimationTags.indexOf(localPart(name)) === -1) {
|
|
9285
9436
|
return false;
|
|
9286
9437
|
}
|
|
9287
9438
|
const schemeCheckedAttributes = options.allowedSchemesAppliedToAttributes || [];
|
|
9288
9439
|
return Object.keys(attribs || {}).some(function(attributeName) {
|
|
9289
|
-
if (attributeName
|
|
9440
|
+
if (localPart(attributeName) !== "attributename") {
|
|
9290
9441
|
return false;
|
|
9291
9442
|
}
|
|
9292
9443
|
const target = (attribs[attributeName] || "").trim().toLowerCase();
|
|
@@ -9294,6 +9445,10 @@ and ensure you are accounting for this risk.
|
|
|
9294
9445
|
return alwaysUrlAttributes.indexOf(localName2) !== -1 || schemeCheckedAttributes.indexOf(target) !== -1 || schemeCheckedAttributes.indexOf(localName2) !== -1;
|
|
9295
9446
|
});
|
|
9296
9447
|
}
|
|
9448
|
+
function localPart(name) {
|
|
9449
|
+
const lower = name.toLowerCase();
|
|
9450
|
+
return lower.slice(lower.lastIndexOf(":") + 1);
|
|
9451
|
+
}
|
|
9297
9452
|
function parseUrl(value) {
|
|
9298
9453
|
value = value.replace(/^(\w+:)?\s*[\\/]\s*[\\/]/, "$1//");
|
|
9299
9454
|
if (value.startsWith("relative:")) {
|
|
@@ -9317,7 +9472,7 @@ and ensure you are accounting for this risk.
|
|
|
9317
9472
|
const astRules = abstractSyntaxTree.nodes[0];
|
|
9318
9473
|
let selectedRule;
|
|
9319
9474
|
if (allowedStyles[astRules.selector] && allowedStyles["*"]) {
|
|
9320
|
-
selectedRule =
|
|
9475
|
+
selectedRule = mergeStyles(
|
|
9321
9476
|
allowedStyles[astRules.selector],
|
|
9322
9477
|
allowedStyles["*"]
|
|
9323
9478
|
);
|
|
@@ -45791,6 +45946,7 @@ var PodStore = class {
|
|
|
45791
45946
|
this._held = 0;
|
|
45792
45947
|
this.chain = Promise.resolve();
|
|
45793
45948
|
this.verdicts = /* @__PURE__ */ new Map();
|
|
45949
|
+
this.unread = /* @__PURE__ */ new Set();
|
|
45794
45950
|
this.generation = 0;
|
|
45795
45951
|
this.onLoaded = null;
|
|
45796
45952
|
this.onWriting = null;
|
|
@@ -45804,6 +45960,7 @@ var PodStore = class {
|
|
|
45804
45960
|
this.cache.clear();
|
|
45805
45961
|
this.etags.clear();
|
|
45806
45962
|
this.lastText.clear();
|
|
45963
|
+
this.unread.clear();
|
|
45807
45964
|
}
|
|
45808
45965
|
this.storage = storage;
|
|
45809
45966
|
}
|
|
@@ -45826,8 +45983,8 @@ var PodStore = class {
|
|
|
45826
45983
|
if (listing.missing && this.storage.kind === "pod") {
|
|
45827
45984
|
throw new Error(`state container missing (HTTP 404) at ${this.base} \u2014 pod unreachable or state gone`);
|
|
45828
45985
|
}
|
|
45829
|
-
this.etags.set("", listing.etag);
|
|
45830
45986
|
const names = listing.names.filter((n) => n.endsWith(".json"));
|
|
45987
|
+
for (const name of this.unread) if (!names.includes(name)) this.unread.delete(name);
|
|
45831
45988
|
let fetched = 0;
|
|
45832
45989
|
const skipped = [];
|
|
45833
45990
|
for (const name of names) {
|
|
@@ -45838,10 +45995,12 @@ var PodStore = class {
|
|
|
45838
45995
|
if (name === "config.json" && !this.cache.has(name)) {
|
|
45839
45996
|
throw new Error(`state doc ${name} unreadable (HTTP ${r.status})`);
|
|
45840
45997
|
}
|
|
45998
|
+
if (!this.lastText.has(name)) this.unread.add(name);
|
|
45841
45999
|
skipped.push(`${name} (HTTP ${r.status})`);
|
|
45842
46000
|
continue;
|
|
45843
46001
|
}
|
|
45844
46002
|
fetched++;
|
|
46003
|
+
this.unread.delete(name);
|
|
45845
46004
|
this.etags.set(name, r.etag);
|
|
45846
46005
|
try {
|
|
45847
46006
|
this.cache.set(name, JSON.parse(r.body));
|
|
@@ -45851,7 +46010,9 @@ var PodStore = class {
|
|
|
45851
46010
|
}
|
|
45852
46011
|
}
|
|
45853
46012
|
this.lastSkipped = skipped;
|
|
45854
|
-
if (skipped.length) this.
|
|
46013
|
+
if (skipped.length) this.etags.delete("");
|
|
46014
|
+
else this.etags.set("", listing.etag);
|
|
46015
|
+
if (skipped.length) this.log(`state load skipped ${skipped.length}: ${skipped.join(", ")}` + (this.unread.size ? ` \u2014 not written until read: ${[...this.unread].join(", ")}` : ""));
|
|
45855
46016
|
this.log(`state loaded: ${this.cache.size} doc(s) from ${this.base} (${fetched} re-fetched)`);
|
|
45856
46017
|
this.onLoaded?.();
|
|
45857
46018
|
}
|
|
@@ -45866,6 +46027,7 @@ var PodStore = class {
|
|
|
45866
46027
|
continue;
|
|
45867
46028
|
}
|
|
45868
46029
|
this.lastText.set(name, text);
|
|
46030
|
+
this.unread.delete(name);
|
|
45869
46031
|
if (etag) this.etags.set(name, etag);
|
|
45870
46032
|
}
|
|
45871
46033
|
if (listingEtag) this.etags.set("", listingEtag);
|
|
@@ -45884,12 +46046,14 @@ var PodStore = class {
|
|
|
45884
46046
|
this.cache.delete(name);
|
|
45885
46047
|
this.lastText.delete(name);
|
|
45886
46048
|
this.etags.delete(name);
|
|
46049
|
+
this.unread.delete(name);
|
|
45887
46050
|
} else if (!r.ok) {
|
|
45888
46051
|
throw new Error(`state doc ${name} unreadable (HTTP ${r.status})`);
|
|
45889
46052
|
} else {
|
|
45890
46053
|
this.cache.set(name, JSON.parse(r.body));
|
|
45891
46054
|
this.lastText.set(name, r.body);
|
|
45892
46055
|
this.etags.set(name, r.etag);
|
|
46056
|
+
this.unread.delete(name);
|
|
45893
46057
|
}
|
|
45894
46058
|
this.onSettled?.(name);
|
|
45895
46059
|
}
|
|
@@ -45908,6 +46072,10 @@ var PodStore = class {
|
|
|
45908
46072
|
write(name, obj) {
|
|
45909
46073
|
this.cache.set(name, structuredClone(obj));
|
|
45910
46074
|
if (!this.storage) return;
|
|
46075
|
+
if (this.unread.has(name)) {
|
|
46076
|
+
this.verdicts.set(name, false);
|
|
46077
|
+
return;
|
|
46078
|
+
}
|
|
45911
46079
|
if (this.lastText.get(name) === serialise(obj)) {
|
|
45912
46080
|
clearTimeout(this.timers.get(name));
|
|
45913
46081
|
this.timers.delete(name);
|
|
@@ -45957,6 +46125,7 @@ var PodStore = class {
|
|
|
45957
46125
|
// the returned promise so one failure cannot poison the queue.
|
|
45958
46126
|
_put(name) {
|
|
45959
46127
|
const done = this.chain.then(async () => {
|
|
46128
|
+
if (this.unread.has(name)) return false;
|
|
45960
46129
|
const body = serialise(this.cache.get(name));
|
|
45961
46130
|
await Promise.resolve(this.onWriting?.(name, body)).catch(() => {
|
|
45962
46131
|
});
|
|
@@ -46011,6 +46180,8 @@ var PodStore = class {
|
|
|
46011
46180
|
// `since`: the generation the caller's work began in. Anything dropped since
|
|
46012
46181
|
// makes the answer false.
|
|
46013
46182
|
async commit({ since } = {}) {
|
|
46183
|
+
if (this.unread.size && this.storage) await this.refresh([...this.unread]).catch(() => {
|
|
46184
|
+
});
|
|
46014
46185
|
const pending = [];
|
|
46015
46186
|
for (const name of /* @__PURE__ */ new Set([...this.timers.keys(), ...this.dirty])) {
|
|
46016
46187
|
const t = this.timers.get(name);
|
|
@@ -57169,6 +57340,7 @@ function fromLiteral(term3) {
|
|
|
57169
57340
|
}
|
|
57170
57341
|
return term3.value;
|
|
57171
57342
|
}
|
|
57343
|
+
var isTagged = (term3) => term3.termType === "Literal" && !!term3.language;
|
|
57172
57344
|
function toValue(term3, ctx, depth, path) {
|
|
57173
57345
|
if (term3.termType === "Literal") return fromLiteral(term3);
|
|
57174
57346
|
if (isListHead(term3, ctx)) return readList(term3.value, ctx, depth, path);
|
|
@@ -57187,8 +57359,12 @@ function readProperty(subject, name, ctx, depth = 0, path = /* @__PURE__ */ new
|
|
|
57187
57359
|
}
|
|
57188
57360
|
const term3 = TERMS.get(name);
|
|
57189
57361
|
if (!term3) return void 0;
|
|
57190
|
-
|
|
57362
|
+
let values = preds.get(term3.iri);
|
|
57191
57363
|
if (!values || !values.length) return void 0;
|
|
57364
|
+
if (values.some(isTagged)) {
|
|
57365
|
+
const plain = values.filter((v) => !isTagged(v));
|
|
57366
|
+
values = plain.length ? plain : [values.find(isTagged)];
|
|
57367
|
+
}
|
|
57192
57368
|
const listed = values.filter((v) => isListHead(v, ctx));
|
|
57193
57369
|
if (term3.list) {
|
|
57194
57370
|
if (!listed.length) return void 0;
|
|
@@ -58104,6 +58280,7 @@ async function rebuildStatuses(publisher, { fromNotes = false } = {}) {
|
|
|
58104
58280
|
}
|
|
58105
58281
|
async function healStatuses(publisher) {
|
|
58106
58282
|
const { urls, store } = publisher;
|
|
58283
|
+
if (store.unread?.has("statuses.json")) return { missing: 0, recovered: 0 };
|
|
58107
58284
|
const own = store.read("outbox.json", []).map((i) => typeof i === "string" ? i : null).filter((id) => id && id.startsWith(urls.notes));
|
|
58108
58285
|
if (!own.length) return { missing: 0, recovered: 0 };
|
|
58109
58286
|
const have = new Set(store.getStatuses().map((s) => s.noteId));
|
|
@@ -58565,6 +58742,21 @@ var Publisher = class {
|
|
|
58565
58742
|
// `clientOrigin` is overridden only by the agent serving a client its own
|
|
58566
58743
|
// local actor: standalone, the published document cannot name a loopback
|
|
58567
58744
|
// address, but a client already talking to that address can be told it.
|
|
58745
|
+
// Whether follows wait for the owner, from the setting as saved now: this
|
|
58746
|
+
// config is a copy taken when the agent started, and the saved one may have
|
|
58747
|
+
// changed since.
|
|
58748
|
+
approvesByHand() {
|
|
58749
|
+
const saved = this.store?.getConfig?.() || {};
|
|
58750
|
+
return followsNeedApproval({
|
|
58751
|
+
...this.config,
|
|
58752
|
+
..."autoAcceptFollows" in saved ? { autoAcceptFollows: saved.autoAcceptFollows } : {},
|
|
58753
|
+
..."approveJoins" in saved ? { approveJoins: saved.approveJoins } : {}
|
|
58754
|
+
});
|
|
58755
|
+
}
|
|
58756
|
+
// Whether the profile last published says what the setting says.
|
|
58757
|
+
profileAgrees() {
|
|
58758
|
+
return this.store.read("published.json", {}).approvesByHand === this.approvesByHand();
|
|
58759
|
+
}
|
|
58568
58760
|
actorDocFor({
|
|
58569
58761
|
priv = false,
|
|
58570
58762
|
moderators = null,
|
|
@@ -58580,7 +58772,7 @@ var Publisher = class {
|
|
|
58580
58772
|
publicKeyPem: this.publicKeyPem,
|
|
58581
58773
|
movedTo,
|
|
58582
58774
|
kind: this.config.kind,
|
|
58583
|
-
approveJoins:
|
|
58775
|
+
approveJoins: this.approvesByHand(),
|
|
58584
58776
|
assertionKey: this.assertionKey,
|
|
58585
58777
|
summary: this.config.summary || null,
|
|
58586
58778
|
icon: this.config.icon || null,
|
|
@@ -58716,12 +58908,11 @@ var Publisher = class {
|
|
|
58716
58908
|
const updated = await this.announceProfileChange(actor, { force });
|
|
58717
58909
|
await this.ensurePrivateAcls();
|
|
58718
58910
|
const unreachable = await this.verifyPublicSurface();
|
|
58719
|
-
|
|
58720
|
-
this.store.
|
|
58721
|
-
|
|
58722
|
-
|
|
58723
|
-
|
|
58724
|
-
}
|
|
58911
|
+
this.store.write("published.json", {
|
|
58912
|
+
...this.store.read("published.json", {}),
|
|
58913
|
+
...!unreachable.length ? { surfaceDigest: surface } : {},
|
|
58914
|
+
approvesByHand: !!actorDoc2.manuallyApprovesFollowers
|
|
58915
|
+
});
|
|
58725
58916
|
const pubName = publicHandle(this.config);
|
|
58726
58917
|
const pubHost = this.config.gateway?.frontActor ? new URL(this.config.gateway.frontActor).host : host;
|
|
58727
58918
|
this.log(this.config.gateway?.frontActor || webfingerHost(urls.base) ? `profile published: @${pubName}@${pubHost} \u2192 ${urls.actor}` : `profile published \u2192 ${urls.actor} \u2014 NOT discoverable as @${pubName}@${pubHost}: this pod is suffixed, and WebFinger is only answered for a subdomained pod`);
|
|
@@ -59424,8 +59615,8 @@ async function isGone(intake, url) {
|
|
|
59424
59615
|
let res;
|
|
59425
59616
|
try {
|
|
59426
59617
|
res = await intake.deliverer.signedFetch(url, { headers: { accept: ACCEPT_AP2 } });
|
|
59427
|
-
} catch {
|
|
59428
|
-
return null;
|
|
59618
|
+
} catch (e) {
|
|
59619
|
+
return e?.answered && (e.status === 404 || e.status === 410) ? true : null;
|
|
59429
59620
|
}
|
|
59430
59621
|
if (res.status === 404 || res.status === 410) return true;
|
|
59431
59622
|
if (res.status < 400) {
|
|
@@ -65470,8 +65661,17 @@ var Intake = class {
|
|
|
65470
65661
|
rec.last = String(message || "").slice(0, 200);
|
|
65471
65662
|
all[url] = rec;
|
|
65472
65663
|
this.store.write(ATTEMPTS_DOC, all);
|
|
65664
|
+
if (rec.n === 2) this._trouble("failing", url, message);
|
|
65473
65665
|
return rec.n;
|
|
65474
65666
|
}
|
|
65667
|
+
// Mail that could not be read, as against mail refused: a second failed try,
|
|
65668
|
+
// or a piece set aside after its last. `onTrouble` tells the owner.
|
|
65669
|
+
_trouble(kind, url, reason) {
|
|
65670
|
+
try {
|
|
65671
|
+
this.onTrouble?.({ kind, url, reason: String(reason || "").slice(0, 200), at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
65672
|
+
} catch {
|
|
65673
|
+
}
|
|
65674
|
+
}
|
|
65475
65675
|
_clearAttempt(url) {
|
|
65476
65676
|
const all = this.store.read(ATTEMPTS_DOC, {});
|
|
65477
65677
|
if (!all[url]) return;
|
|
@@ -65515,12 +65715,24 @@ var Intake = class {
|
|
|
65515
65715
|
this._draining = null;
|
|
65516
65716
|
if (this._drainAgain) {
|
|
65517
65717
|
this._drainAgain = false;
|
|
65518
|
-
|
|
65519
|
-
|
|
65718
|
+
this._chainTimer = setTimeout(() => {
|
|
65719
|
+
this._chainTimer = null;
|
|
65720
|
+
this.drain().catch((e) => this.log(`drain: ${e.message}`));
|
|
65721
|
+
}, CHAIN_GAP_MS);
|
|
65722
|
+
this._chainTimer.unref?.();
|
|
65520
65723
|
}
|
|
65521
65724
|
});
|
|
65522
65725
|
return this._draining;
|
|
65523
65726
|
}
|
|
65727
|
+
// Resolves once no sweep is running and none is waiting to follow on, so a
|
|
65728
|
+
// browser worker can stay up until the round it started is done.
|
|
65729
|
+
async settled() {
|
|
65730
|
+
while (this._draining || this._chainTimer) {
|
|
65731
|
+
if (this._draining) await this._draining.catch(() => {
|
|
65732
|
+
});
|
|
65733
|
+
else await new Promise((r) => setTimeout(r, 500));
|
|
65734
|
+
}
|
|
65735
|
+
}
|
|
65524
65736
|
// Discard the content waiting in the inbox from before `before`, on the
|
|
65525
65737
|
// owner's say-so — the admin page asks, this does it. NOT a blind sweep:
|
|
65526
65738
|
// every item is read, because the type is the only thing that decides its
|
|
@@ -65723,6 +65935,7 @@ var Intake = class {
|
|
|
65723
65935
|
this.log(`inbox batch ${url} attempt ${n}/${MAX_ITEM_ATTEMPTS}: ${e.message}`);
|
|
65724
65936
|
if (n >= MAX_ITEM_ATTEMPTS) {
|
|
65725
65937
|
this.store.addDeadLetter({ inboxUrl: url, reason: `failed ${n}x: ${e.message}`, activity: null });
|
|
65938
|
+
this._trouble("set-aside", url, e.message);
|
|
65726
65939
|
pending.push(url);
|
|
65727
65940
|
}
|
|
65728
65941
|
}
|
|
@@ -65746,6 +65959,7 @@ var Intake = class {
|
|
|
65746
65959
|
this.log(`inbox item ${url} attempt ${n}/${MAX_ITEM_ATTEMPTS}: ${e.message}`);
|
|
65747
65960
|
if (n >= MAX_ITEM_ATTEMPTS) {
|
|
65748
65961
|
this.store.addDeadLetter({ inboxUrl: url, reason: `failed ${n}x: ${e.message}`, activity: trimActivity(at.activity) });
|
|
65962
|
+
this._trouble("set-aside", url, e.message);
|
|
65749
65963
|
pending.push(url);
|
|
65750
65964
|
}
|
|
65751
65965
|
}
|
|
@@ -65766,6 +65980,11 @@ var Intake = class {
|
|
|
65766
65980
|
const read2 = raw ? await readLenient(raw) : null;
|
|
65767
65981
|
if (read2?.degraded) this.log(`inbox item ${url} grounded to read: ${read2.degraded}`);
|
|
65768
65982
|
const activity = at.activity = read2?.view ?? read2?.doc ?? null;
|
|
65983
|
+
const from = typeof activity?.actor === "string" ? activity.actor : activity?.actor?.id;
|
|
65984
|
+
if (from && this.checkLetters?.actor && from === this.checkLetters.actor) {
|
|
65985
|
+
await this.checkLetters.taken(String(activity.id || ""));
|
|
65986
|
+
return;
|
|
65987
|
+
}
|
|
65769
65988
|
if (read2?.graph) {
|
|
65770
65989
|
const failure = await checkShapes(read2.graph);
|
|
65771
65990
|
if (failure) {
|
|
@@ -65820,6 +66039,7 @@ var Intake = class {
|
|
|
65820
66039
|
const batch = await this._batchEntries(url);
|
|
65821
66040
|
if (!batch) {
|
|
65822
66041
|
this.store.addDeadLetter({ inboxUrl: url, reason: "unreadable batch", activity: null });
|
|
66042
|
+
this._trouble("set-aside", url, "unreadable batch");
|
|
65823
66043
|
return { entries: 1, complete: true };
|
|
65824
66044
|
}
|
|
65825
66045
|
let complete = true;
|
|
@@ -65839,6 +66059,7 @@ var Intake = class {
|
|
|
65839
66059
|
this.log(`inbox batch entry ${key} attempt ${n}/${MAX_ITEM_ATTEMPTS}: ${err.message}`);
|
|
65840
66060
|
if (n >= MAX_ITEM_ATTEMPTS) {
|
|
65841
66061
|
this.store.addDeadLetter({ inboxUrl: key, reason: `failed ${n}x: ${err.message}`, activity: trimActivity(at.activity) });
|
|
66062
|
+
this._trouble("set-aside", key, err.message);
|
|
65842
66063
|
} else {
|
|
65843
66064
|
complete = false;
|
|
65844
66065
|
}
|
|
@@ -65877,6 +66098,7 @@ var Intake = class {
|
|
|
65877
66098
|
this.log(`held delivery ${key} attempt ${n}/${MAX_ITEM_ATTEMPTS}: ${err.message}`);
|
|
65878
66099
|
if (n >= MAX_ITEM_ATTEMPTS) {
|
|
65879
66100
|
this.store.addDeadLetter({ inboxUrl: key, reason: `failed ${n}x: ${err.message}`, activity: trimActivity(at.activity) });
|
|
66101
|
+
this._trouble("set-aside", key, err.message);
|
|
65880
66102
|
done.push(e.name);
|
|
65881
66103
|
}
|
|
65882
66104
|
}
|
|
@@ -68288,6 +68510,10 @@ var BskyFeed = class {
|
|
|
68288
68510
|
};
|
|
68289
68511
|
|
|
68290
68512
|
// lib/client/masto/render.mjs
|
|
68513
|
+
var once = (html) => {
|
|
68514
|
+
const m = (html.length - 1) / 2;
|
|
68515
|
+
return Number.isInteger(m) && html[m] === "," && html.slice(0, m) === html.slice(m + 1) ? html.slice(0, m) : html;
|
|
68516
|
+
};
|
|
68291
68517
|
var TRANSPARENT_PNG = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";
|
|
68292
68518
|
var DEFAULT_AVATAR = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAABd0lEQVR42u3ZoW4CQRDG8Xk6NBLbVCJ5gBpMTQ2iBlFR29RXNsFhz1JHXV9hydfkEkoobW5n2F34i0kIHMfN73ZvdwYbTabpmsMAAAAAAAAAAAAAAAAAAACiY3wzS/ePz+n1bZW6zTZ9fH59h17rPX2mYy4OQEktnl5+JP1b6Bgdey6IcIDb2Ty9r7s/Ez8MfUffbRpACfznrp8aDdEIFjnsh9z5YyMhcjqEAWge5ybfh87VFIDuWM7QPzYVokZBCICWM6/k+9A5mwHQmu4NoHM2A+A5/PenQTMA3sn3AQBTgIcgyyAbIbbCFEOUwzREaInRFKUtDgAAFQLcPSxDCqH9Z4V+o0oAXVhU4ofhiWCtJe+NYKV3e6V3idkAHvv9nDqhKIBnxVeqUrRaav5SvQKrqetTols0GGDdbaoB0LWcFUBP31qS72PoimCtD//caWC1tL1Ltc2ttbXfe08wCKC25HP+OgMAAAAAAAAAAAAAAAAArhNgB1PE/x/JOiuNAAAAAElFTkSuQmCC";
|
|
68293
68519
|
var selfIcon = (api, self2, cached) => (self2 ? api.store.getConfig()?.icon : null) || cached.icon;
|
|
@@ -68511,7 +68737,7 @@ function status(api, s, { all, depth = 0 } = {}) {
|
|
|
68511
68737
|
in_reply_to_id: s.inReplyTo ? api.store.idFor(s.inReplyTo) : null,
|
|
68512
68738
|
in_reply_to_account_id: null,
|
|
68513
68739
|
sensitive: !!(s.spoiler || s.sensitive),
|
|
68514
|
-
spoiler_text: s.spoiler || "",
|
|
68740
|
+
spoiler_text: once(s.spoiler || ""),
|
|
68515
68741
|
visibility: s.visibility || "public",
|
|
68516
68742
|
language: null,
|
|
68517
68743
|
edited_at: s.editedAt || null,
|
|
@@ -68528,7 +68754,7 @@ function status(api, s, { all, depth = 0 } = {}) {
|
|
|
68528
68754
|
muted: false,
|
|
68529
68755
|
bookmarked: !!s.bookmarked,
|
|
68530
68756
|
pinned: !!s.pinned,
|
|
68531
|
-
content: s.content || "",
|
|
68757
|
+
content: once(s.content || ""),
|
|
68532
68758
|
reblog: null,
|
|
68533
68759
|
application: null,
|
|
68534
68760
|
account: api.account(s.actor),
|
|
@@ -68570,7 +68796,7 @@ function status(api, s, { all, depth = 0 } = {}) {
|
|
|
68570
68796
|
}
|
|
68571
68797
|
function filtersFor(api, s) {
|
|
68572
68798
|
const now = Date.now();
|
|
68573
|
-
const hay = `${s.content || ""} ${s.spoiler || ""}`.replace(/<[^>]*>/gu, " ").toLowerCase();
|
|
68799
|
+
const hay = `${once(s.content || "")} ${once(s.spoiler || "")}`.replace(/<[^>]*>/gu, " ").toLowerCase();
|
|
68574
68800
|
if (!hay.trim()) return [];
|
|
68575
68801
|
const out = [];
|
|
68576
68802
|
for (const f of api.store.getFilters?.() || []) {
|
|
@@ -68657,7 +68883,7 @@ function pushNotify(api, n) {
|
|
|
68657
68883
|
notification_type: n.type,
|
|
68658
68884
|
preferred_locale: "en",
|
|
68659
68885
|
title: `${acct.display_name || acct.acct} ${verbs[n.type] || n.type}`,
|
|
68660
|
-
body: s ? htmlToText(s.content || "").slice(0, 140) : "",
|
|
68886
|
+
body: s ? htmlToText(once(s.content || "")).slice(0, 140) : "",
|
|
68661
68887
|
icon: acct.avatar || ""
|
|
68662
68888
|
});
|
|
68663
68889
|
}
|
|
@@ -69155,9 +69381,10 @@ async function handle4(api, ctx) {
|
|
|
69155
69381
|
const { req, res, pathname, url, send } = ctx;
|
|
69156
69382
|
if (pathname === "/api/v1/timelines/home" || pathname === "/api/v1/timelines/public" || pathname === "/api/v1/trends/statuses") {
|
|
69157
69383
|
const localOnly = pathname === "/api/v1/timelines/public" && url.searchParams.get("local") === "true";
|
|
69384
|
+
const hideTags = pathname === "/api/v1/timelines/home" && api.store.getConfig?.()?.tagsInHome === false;
|
|
69158
69385
|
const all = api.store.getStatuses();
|
|
69159
69386
|
const muted = new Set(api.store.getMuted().actors);
|
|
69160
|
-
let items = all.filter((s) => s.kind !== "remote" && s.kind !== "mention").filter((s) => !s.direct && s.visibility !== "direct").filter((s) => !muted.has(s.actor) && !muted.has(s.via)).filter((s) => !localOnly || s.kind === "post" && s.visibility !== "private").sort((a, b) => String(b.published || "").localeCompare(String(a.published || "")));
|
|
69387
|
+
let items = all.filter((s) => s.kind !== "remote" && s.kind !== "mention").filter((s) => !s.direct && s.visibility !== "direct").filter((s) => !muted.has(s.actor) && !muted.has(s.via)).filter((s) => !hideTags || s.kind !== "tag" || s.sourceAccts?.length).filter((s) => !localOnly || s.kind === "post" && s.visibility !== "private").sort((a, b) => String(b.published || "").localeCompare(String(a.published || "")));
|
|
69161
69388
|
const { items: page2, headers } = api.page(items, url);
|
|
69162
69389
|
return send(200, page2.map((s) => api.statusOrBoost(s, { all })), headers);
|
|
69163
69390
|
}
|
|
@@ -70167,8 +70394,9 @@ var TagFeed = class {
|
|
|
70167
70394
|
if (Array.isArray(patch.tags)) clean.tags = patch.tags.map((t) => String(t).replace(/^#/, "").trim()).filter(Boolean);
|
|
70168
70395
|
if (patch.intervalMin) clean.intervalMin = Math.max(5, Number(patch.intervalMin) || DEFAULTS2.intervalMin);
|
|
70169
70396
|
this.store.write("tagfeed.json", { ...this.config(), ...clean });
|
|
70397
|
+
const sweeping = this.stopped === false;
|
|
70170
70398
|
this.stop();
|
|
70171
|
-
this.start();
|
|
70399
|
+
if (sweeping) this.start();
|
|
70172
70400
|
return this.config();
|
|
70173
70401
|
}
|
|
70174
70402
|
// `lastSweptAt` and `onSwept` are for a browser worker the browser stops and
|
|
@@ -71008,6 +71236,7 @@ var RelayDeliverer = class extends Deliverer {
|
|
|
71008
71236
|
if (status2 >= 400) {
|
|
71009
71237
|
const err = new Error(`${method} ${url} \u2192 ${status2}`);
|
|
71010
71238
|
err.status = status2;
|
|
71239
|
+
err.answered = true;
|
|
71011
71240
|
if (r0.retryAfter) {
|
|
71012
71241
|
const secs = Number(r0.retryAfter);
|
|
71013
71242
|
const ms = Number.isFinite(secs) ? Math.max(secs, 1) * 1e3 : Math.max(Date.parse(r0.retryAfter) - Date.now(), 1e3);
|
|
@@ -71392,7 +71621,7 @@ var ImportWorker = class {
|
|
|
71392
71621
|
|
|
71393
71622
|
// web/app/admin-facade.mjs
|
|
71394
71623
|
var PERMANENT_CONFIG = ["handle", "remotePod", "issuer", "root", "kind"];
|
|
71395
|
-
var WIRE_CONFIG = ["name", "summary", "icon", "image", "fields", "aliases"];
|
|
71624
|
+
var WIRE_CONFIG = ["name", "summary", "icon", "image", "fields", "aliases", "autoAcceptFollows"];
|
|
71396
71625
|
var ADMIN_PATHS = /* @__PURE__ */ new Set([
|
|
71397
71626
|
"/status",
|
|
71398
71627
|
"/config",
|
|
@@ -71401,6 +71630,7 @@ var ADMIN_PATHS = /* @__PURE__ */ new Set([
|
|
|
71401
71630
|
"/rotate-key",
|
|
71402
71631
|
"/import",
|
|
71403
71632
|
"/deadletter",
|
|
71633
|
+
"/trouble",
|
|
71404
71634
|
"/blocks",
|
|
71405
71635
|
"/profiles",
|
|
71406
71636
|
"/modqueue",
|
|
@@ -71502,6 +71732,7 @@ var AdminFacade = class {
|
|
|
71502
71732
|
fields: cfg.fields || [],
|
|
71503
71733
|
aliases: cfg.aliases || [],
|
|
71504
71734
|
autoAcceptFollows: cfg.autoAcceptFollows !== false,
|
|
71735
|
+
tagsInHome: cfg.tagsInHome !== false,
|
|
71505
71736
|
quiescedAt: cfg.quiescedAt || null,
|
|
71506
71737
|
movedTo: cfg.movedTo || null,
|
|
71507
71738
|
mode: a.status().mode,
|
|
@@ -71560,8 +71791,7 @@ var AdminFacade = class {
|
|
|
71560
71791
|
return json2(200, []);
|
|
71561
71792
|
// person: no moderation queue
|
|
71562
71793
|
case "/log":
|
|
71563
|
-
return json2(200, { lines: [] });
|
|
71564
|
-
// no local log file in the browser
|
|
71794
|
+
return json2(200, { lines: await a.recentLog?.() || [] });
|
|
71565
71795
|
case "/fediacct":
|
|
71566
71796
|
return json2(200, { accounts: a.fediaccts?.status() || [] });
|
|
71567
71797
|
case "/import":
|
|
@@ -71598,6 +71828,13 @@ var AdminFacade = class {
|
|
|
71598
71828
|
return json2(400, { error: "expected JSON body" });
|
|
71599
71829
|
}
|
|
71600
71830
|
switch (p) {
|
|
71831
|
+
// The owner has opened the dead letters: the bar stops saying so.
|
|
71832
|
+
case "/trouble": {
|
|
71833
|
+
if (body.seen !== true) return json2(400, { error: "seen: true is the only thing to say here" });
|
|
71834
|
+
a.troubleSeen?.();
|
|
71835
|
+
await a.store.flush();
|
|
71836
|
+
return json2(200, { ok: true, trouble: a.status().trouble });
|
|
71837
|
+
}
|
|
71601
71838
|
case "/config": {
|
|
71602
71839
|
const fixed = PERMANENT_CONFIG.filter((k) => k in body);
|
|
71603
71840
|
if (fixed.length) return json2(400, { error: `${fixed.join(", ")} cannot be changed \u2014 that is the identity itself` });
|
|
@@ -71617,6 +71854,7 @@ var AdminFacade = class {
|
|
|
71617
71854
|
cfg.fields = (Array.isArray(body.fields) ? body.fields : []).filter((f) => f?.name?.trim()).map((f) => ({ name: String(f.name).trim(), value: String(f.value ?? "").trim() }));
|
|
71618
71855
|
}
|
|
71619
71856
|
if ("autoAcceptFollows" in body) cfg.autoAcceptFollows = !!body.autoAcceptFollows;
|
|
71857
|
+
if ("tagsInHome" in body) cfg.tagsInHome = !!body.tagsInHome;
|
|
71620
71858
|
const republish = WIRE_CONFIG.some((k) => k in body);
|
|
71621
71859
|
a.store.setConfig(cfg);
|
|
71622
71860
|
if ("autoAcceptFollows" in body && a.publisher) a.publisher.config.autoAcceptFollows = cfg.autoAcceptFollows;
|
|
@@ -71926,23 +72164,20 @@ var AdminFacade = class {
|
|
|
71926
72164
|
await a.store.flush();
|
|
71927
72165
|
return json2(200, { ok: true });
|
|
71928
72166
|
}
|
|
71929
|
-
// Bluesky settings: pause/resume the mirror
|
|
71930
|
-
//
|
|
72167
|
+
// Bluesky settings: pause/resume the mirror. Cross-post is default-on, not
|
|
72168
|
+
// toggled. The credential is kept on the pod, with nowhere else to move.
|
|
71931
72169
|
case "/atproto": {
|
|
71932
72170
|
if (!a.atproto?.connected()) return json2(400, { error: "no bluesky account connected" });
|
|
72171
|
+
if ("storage" in body) return json2(400, { error: "a connected account is kept on your pod" });
|
|
71933
72172
|
if ("feedPaused" in body) {
|
|
71934
72173
|
a.atproto.setFeedPaused(!!body.feedPaused);
|
|
71935
72174
|
a.restartBsky?.();
|
|
71936
72175
|
}
|
|
71937
|
-
if ("storage" in body) {
|
|
71938
|
-
if (!["pod", "browser"].includes(body.storage)) return json2(400, { error: "storage must be pod or browser" });
|
|
71939
|
-
a.atproto.setStorage(body.storage);
|
|
71940
|
-
}
|
|
71941
72176
|
return json2(200, { ok: true, ...a.atproto.status() });
|
|
71942
72177
|
}
|
|
71943
72178
|
// Connect a fediverse account on another server: start its OAuth at that
|
|
71944
72179
|
// server. The browser is then sent to `authorize`; the code comes back to
|
|
71945
|
-
// GET /fediacct/callback (above). The token
|
|
72180
|
+
// GET /fediacct/callback (above). The token is kept on the pod.
|
|
71946
72181
|
case "/fediacct/connect": {
|
|
71947
72182
|
if (!body.host) return json2(400, { error: "the address of the server is required" });
|
|
71948
72183
|
try {
|
|
@@ -71959,14 +72194,11 @@ var AdminFacade = class {
|
|
|
71959
72194
|
a.restartAccts?.();
|
|
71960
72195
|
return json2(200, { ok: true });
|
|
71961
72196
|
}
|
|
71962
|
-
// Pause/resume the mirror
|
|
72197
|
+
// Pause/resume the mirror. The credential is kept on the pod.
|
|
71963
72198
|
case "/fediacct": {
|
|
71964
72199
|
if (!body.id) return json2(400, { error: "id required" });
|
|
71965
|
-
|
|
71966
|
-
|
|
71967
|
-
if (!["pod", "browser"].includes(body.storage)) return json2(400, { error: "storage must be pod or browser" });
|
|
71968
|
-
row = a.fediaccts.setStorage(body.id, body.storage);
|
|
71969
|
-
} else row = a.fediaccts.setEnabled(body.id, !!body.enabled);
|
|
72200
|
+
if ("storage" in body) return json2(400, { error: "a connected account is kept on your pod" });
|
|
72201
|
+
const row = a.fediaccts.setEnabled(body.id, !!body.enabled);
|
|
71970
72202
|
if (!row) return json2(404, { error: "no such account" });
|
|
71971
72203
|
a.restartAccts?.();
|
|
71972
72204
|
return json2(200, { ok: true, account: row });
|
|
@@ -72432,8 +72664,10 @@ var BrowserAtproto = class extends Atproto {
|
|
|
72432
72664
|
}
|
|
72433
72665
|
// The IndexedDB copy into memory, so read() stays synchronous as the base
|
|
72434
72666
|
// class expects. The pod copy is already in the loaded store.
|
|
72435
|
-
|
|
72667
|
+
// `fromPod`: the pod's record read as well (agent.mjs says when).
|
|
72668
|
+
async load({ fromPod = false } = {}) {
|
|
72436
72669
|
this._idbRec = await kvGet(IDB_KEY).catch(() => null);
|
|
72670
|
+
if (fromPod) await this.store.refresh?.([POD_DOC], { ifChanged: true }).catch((e) => this.log(`Bluesky account: ${e.message}`));
|
|
72437
72671
|
return this;
|
|
72438
72672
|
}
|
|
72439
72673
|
// Whichever backend holds it, tagged with where it lives. The stamped-record
|
|
@@ -72441,15 +72675,13 @@ var BrowserAtproto = class extends Atproto {
|
|
|
72441
72675
|
read() {
|
|
72442
72676
|
let rec = null;
|
|
72443
72677
|
let where = null;
|
|
72444
|
-
|
|
72678
|
+
const p = this.store.read(POD_DOC, null);
|
|
72679
|
+
if (p) {
|
|
72680
|
+
rec = p;
|
|
72681
|
+
where = "pod";
|
|
72682
|
+
} else if (this._idbRec) {
|
|
72445
72683
|
rec = this._idbRec;
|
|
72446
72684
|
where = "browser";
|
|
72447
|
-
} else {
|
|
72448
|
-
const p = this.store.read(POD_DOC, null);
|
|
72449
|
-
if (p) {
|
|
72450
|
-
rec = p;
|
|
72451
|
-
where = "pod";
|
|
72452
|
-
}
|
|
72453
72685
|
}
|
|
72454
72686
|
if (!rec) return null;
|
|
72455
72687
|
if (rec.mintedFor && this.actorId && rec.mintedFor !== this.actorId) {
|
|
@@ -72458,25 +72690,25 @@ var BrowserAtproto = class extends Atproto {
|
|
|
72458
72690
|
}
|
|
72459
72691
|
return { ...rec, storage: where };
|
|
72460
72692
|
}
|
|
72461
|
-
// Write to the record's chosen backend (default browser), and clear the other
|
|
72462
|
-
// so a moved credential leaves no copy behind.
|
|
72463
72693
|
write(rec) {
|
|
72464
|
-
|
|
72465
|
-
|
|
72466
|
-
|
|
72467
|
-
|
|
72468
|
-
|
|
72469
|
-
|
|
72470
|
-
|
|
72471
|
-
|
|
72472
|
-
|
|
72473
|
-
|
|
72474
|
-
this.
|
|
72475
|
-
|
|
72476
|
-
this.store.write(POD_DOC, null);
|
|
72477
|
-
this.store.flush?.().catch(() => {
|
|
72478
|
-
});
|
|
72694
|
+
this.store.write(POD_DOC, { ...rec, storage: "pod" });
|
|
72695
|
+
this.store.flush?.().catch(() => {
|
|
72696
|
+
});
|
|
72697
|
+
}
|
|
72698
|
+
// A record still in this browser, onto the pod, and out of the browser once
|
|
72699
|
+
// the pod has it. One the pod already holds is newer there.
|
|
72700
|
+
async moveToPod() {
|
|
72701
|
+
const rec = this._idbRec;
|
|
72702
|
+
if (!rec || rec.mintedFor && this.actorId && rec.mintedFor !== this.actorId) return false;
|
|
72703
|
+
if (!this.store.read(POD_DOC, null)) {
|
|
72704
|
+
this.store.write(POD_DOC, { ...rec, storage: "pod" });
|
|
72705
|
+
if (!await this.store.commit()) return false;
|
|
72479
72706
|
}
|
|
72707
|
+
this._idbRec = null;
|
|
72708
|
+
await kvDel(IDB_KEY).catch(() => {
|
|
72709
|
+
});
|
|
72710
|
+
this.log("the Bluesky account moved from this browser to the pod");
|
|
72711
|
+
return true;
|
|
72480
72712
|
}
|
|
72481
72713
|
status() {
|
|
72482
72714
|
const rec = this.read();
|
|
@@ -72499,11 +72731,6 @@ var BrowserAtproto = class extends Atproto {
|
|
|
72499
72731
|
const rec = this.read();
|
|
72500
72732
|
if (rec) this.write({ ...rec, feedPaused: !!on });
|
|
72501
72733
|
}
|
|
72502
|
-
// Move the credential between backends (the Options menu's Storage control).
|
|
72503
|
-
setStorage(where) {
|
|
72504
|
-
const rec = this.read();
|
|
72505
|
-
if (rec && (where === "pod" || where === "browser")) this.write({ ...rec, storage: where });
|
|
72506
|
-
}
|
|
72507
72734
|
async disconnect() {
|
|
72508
72735
|
const rec = this.read();
|
|
72509
72736
|
if (rec?.refreshJwt) {
|
|
@@ -72762,7 +72989,9 @@ var BrowserFediAccounts = class extends FediAccounts {
|
|
|
72762
72989
|
this._recs = /* @__PURE__ */ new Map();
|
|
72763
72990
|
this._apps = /* @__PURE__ */ new Map();
|
|
72764
72991
|
}
|
|
72765
|
-
|
|
72992
|
+
// `fromPod`: the pod's records read as well (agent.mjs says when).
|
|
72993
|
+
async load({ fromPod = false } = {}) {
|
|
72994
|
+
if (fromPod) await this.store.refresh?.([POD_DOC2], { ifChanged: true }).catch((e) => this.log(`connected accounts: ${e.message}`));
|
|
72766
72995
|
const all = await kvAll().catch(() => ({}));
|
|
72767
72996
|
for (const [k, v] of Object.entries(all)) {
|
|
72768
72997
|
if (k.startsWith("rec:")) this._recs.set(k.slice(4), v);
|
|
@@ -72787,15 +73016,13 @@ var BrowserFediAccounts = class extends FediAccounts {
|
|
|
72787
73016
|
read(id) {
|
|
72788
73017
|
let rec = null;
|
|
72789
73018
|
let where = null;
|
|
72790
|
-
|
|
73019
|
+
const p = this._podMap()[id];
|
|
73020
|
+
if (p) {
|
|
73021
|
+
rec = p;
|
|
73022
|
+
where = "pod";
|
|
73023
|
+
} else if (this._recs.has(id)) {
|
|
72791
73024
|
rec = this._recs.get(id);
|
|
72792
73025
|
where = "browser";
|
|
72793
|
-
} else {
|
|
72794
|
-
const p = this._podMap()[id];
|
|
72795
|
-
if (p) {
|
|
72796
|
-
rec = p;
|
|
72797
|
-
where = "pod";
|
|
72798
|
-
}
|
|
72799
73026
|
}
|
|
72800
73027
|
if (!rec) return null;
|
|
72801
73028
|
if (rec.mintedFor && this.actorId && rec.mintedFor !== this.actorId) {
|
|
@@ -72805,27 +73032,28 @@ var BrowserFediAccounts = class extends FediAccounts {
|
|
|
72805
73032
|
return { ...rec, storage: where };
|
|
72806
73033
|
}
|
|
72807
73034
|
write(rec) {
|
|
72808
|
-
const
|
|
72809
|
-
const
|
|
72810
|
-
|
|
72811
|
-
|
|
72812
|
-
|
|
72813
|
-
|
|
72814
|
-
|
|
72815
|
-
|
|
72816
|
-
|
|
73035
|
+
const clean = { ...rec, storage: "pod" };
|
|
73036
|
+
const map = { ...this._podMap(), [clean.id]: clean };
|
|
73037
|
+
this.store.write(POD_DOC2, map);
|
|
73038
|
+
this.store.flush?.().catch(() => {
|
|
73039
|
+
});
|
|
73040
|
+
}
|
|
73041
|
+
// The records still in this browser, onto the pod, and out of the browser
|
|
73042
|
+
// once the pod has them. One the pod already holds is newer there.
|
|
73043
|
+
async moveToPod() {
|
|
73044
|
+
const moving = [...this._recs.values()].filter((r) => !r.mintedFor || !this.actorId || r.mintedFor === this.actorId);
|
|
73045
|
+
if (!moving.length) return 0;
|
|
73046
|
+
const map = { ...this._podMap() };
|
|
73047
|
+
for (const r of moving) if (!(r.id in map)) map[r.id] = { ...r, storage: "pod" };
|
|
73048
|
+
this.store.write(POD_DOC2, map);
|
|
73049
|
+
if (!await this.store.commit()) return 0;
|
|
73050
|
+
for (const r of moving) {
|
|
73051
|
+
this._recs.delete(r.id);
|
|
73052
|
+
await kvDel("rec:" + r.id).catch(() => {
|
|
72817
73053
|
});
|
|
72818
|
-
} else {
|
|
72819
|
-
this._recs.set(clean.id, clean);
|
|
72820
|
-
kvPut("rec:" + clean.id, clean).catch((e) => this.log(`fediacct persist: ${e.message}`));
|
|
72821
|
-
const map = this._podMap();
|
|
72822
|
-
if (clean.id in map) {
|
|
72823
|
-
delete map[clean.id];
|
|
72824
|
-
this.store.write(POD_DOC2, map);
|
|
72825
|
-
this.store.flush?.().catch(() => {
|
|
72826
|
-
});
|
|
72827
|
-
}
|
|
72828
73054
|
}
|
|
73055
|
+
this.log(`${moving.length} connected account(s) moved from this browser to the pod`);
|
|
73056
|
+
return moving.length;
|
|
72829
73057
|
}
|
|
72830
73058
|
// Best-effort: tell the server to revoke our token (RFC 7009), so a
|
|
72831
73059
|
// disconnect actually invalidates it there — not just locally. Mirrors
|
|
@@ -72878,15 +73106,6 @@ var BrowserFediAccounts = class extends FediAccounts {
|
|
|
72878
73106
|
cooldownFor: Math.max(0, Math.round(((this.pausedUntil.get(r.host) || 0) - Date.now()) / 1e3))
|
|
72879
73107
|
}));
|
|
72880
73108
|
}
|
|
72881
|
-
// Move a connection between backends (the Options menu's Storage control).
|
|
72882
|
-
setStorage(id, where) {
|
|
72883
|
-
const rec = this.read(id);
|
|
72884
|
-
if (rec && (where === "pod" || where === "browser")) {
|
|
72885
|
-
this.write({ ...rec, storage: where });
|
|
72886
|
-
return this.roster().find((r) => r.id === id) || null;
|
|
72887
|
-
}
|
|
72888
|
-
return null;
|
|
72889
|
-
}
|
|
72890
73109
|
// One app registration per host, remembered — over IndexedDB.
|
|
72891
73110
|
async appFor(host, redirectUri) {
|
|
72892
73111
|
const cached = this._apps.get(host);
|
|
@@ -73062,8 +73281,11 @@ var AcctFeed = class {
|
|
|
73062
73281
|
}
|
|
73063
73282
|
return map;
|
|
73064
73283
|
}
|
|
73284
|
+
// A server that does not say what is left (not every Mastodon-API server
|
|
73285
|
+
// does) is not taken to have nothing left.
|
|
73065
73286
|
_rateGuard(id, handle7, res) {
|
|
73066
|
-
const
|
|
73287
|
+
const said = res.headers.get("x-ratelimit-remaining");
|
|
73288
|
+
const left = said == null || said.trim() === "" ? NaN : Number(said);
|
|
73067
73289
|
if (!Number.isFinite(left) || left > RATE_FLOOR) return false;
|
|
73068
73290
|
const reset = Date.parse(res.headers.get("x-ratelimit-reset") || "");
|
|
73069
73291
|
const wait = Number.isFinite(reset) ? Math.max(0, reset - Date.now()) : BACKOFF_MIN_MS3;
|
|
@@ -73173,7 +73395,8 @@ var fail2 = () => {
|
|
|
73173
73395
|
var promises_default = new Proxy({}, { get: () => fail2 });
|
|
73174
73396
|
|
|
73175
73397
|
// lib/core/pod-only.mjs
|
|
73176
|
-
var
|
|
73398
|
+
var CONNECTED = /* @__PURE__ */ new Set(["fediaccts.json", "atproto.json"]);
|
|
73399
|
+
var podOnly = (name) => name === "keys.json" || name === "lease.json" || name.startsWith("conn-") || CONNECTED.has(name);
|
|
73177
73400
|
|
|
73178
73401
|
// lib/core/storage.mjs
|
|
73179
73402
|
var LDP2 = Namespace("http://www.w3.org/ns/ldp#");
|
|
@@ -73735,6 +73958,41 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
73735
73958
|
// (lib/gateway/held-mail.mjs: /api/push). Named a moment later, once written,
|
|
73736
73959
|
// so a burst is one call. One from another network is not pushed.
|
|
73737
73960
|
static PUSH_AFTER_MS = 2e3;
|
|
73961
|
+
// Mail FediPod could not read: counted until its owner opens the dead
|
|
73962
|
+
// letters, shown in the bar meanwhile, and told to their phones at most
|
|
73963
|
+
// once an hour (lib/gateway/held-mail.mjs: /api/alert).
|
|
73964
|
+
static TROUBLE_ALERT_MS = 60 * 6e4;
|
|
73965
|
+
noteTrouble(t, { tell = true } = {}) {
|
|
73966
|
+
const had = this.store.read("trouble.json", null) || { count: 0 };
|
|
73967
|
+
const now = Date.now();
|
|
73968
|
+
const due = tell && now - (had.alertedAt ? Date.parse(had.alertedAt) : 0) >= _BrowserAgent.TROUBLE_ALERT_MS;
|
|
73969
|
+
const next = {
|
|
73970
|
+
...had,
|
|
73971
|
+
count: (had.count || 0) + 1,
|
|
73972
|
+
firstAt: had.firstAt || t.at,
|
|
73973
|
+
lastAt: t.at,
|
|
73974
|
+
last: { kind: t.kind, reason: t.reason },
|
|
73975
|
+
...due ? { alertedAt: new Date(now).toISOString() } : {}
|
|
73976
|
+
};
|
|
73977
|
+
this.store.write("trouble.json", next);
|
|
73978
|
+
this.log(`could not read mail (${t.kind}): ${t.reason}`);
|
|
73979
|
+
if (due) {
|
|
73980
|
+
const many = next.count === 1 ? "a piece of your mail" : `${next.count} pieces of your mail`;
|
|
73981
|
+
this.tellGateway("alert", { handle: this.doorKey, text: `Could not read ${many}. Show dead letters on your manage page lists what it gave up on.` }, { standing: false }).catch(() => {
|
|
73982
|
+
});
|
|
73983
|
+
}
|
|
73984
|
+
}
|
|
73985
|
+
// The owner has looked: the count starts again, and the hourly limit stands.
|
|
73986
|
+
troubleSeen() {
|
|
73987
|
+
const had = this.store.read("trouble.json", null);
|
|
73988
|
+
if (had?.count) {
|
|
73989
|
+
this.store.write("trouble.json", {
|
|
73990
|
+
count: 0,
|
|
73991
|
+
...had.alertedAt ? { alertedAt: had.alertedAt } : {},
|
|
73992
|
+
...had.letterMissing ? { letterMissing: had.letterMissing } : {}
|
|
73993
|
+
});
|
|
73994
|
+
}
|
|
73995
|
+
}
|
|
73738
73996
|
notePush(n) {
|
|
73739
73997
|
if (!this.gatewayApi || n?.bsky || n?.via) return;
|
|
73740
73998
|
if (!Object.keys(this.store.read("webpush.json", { subs: {} }).subs || {}).length) return;
|
|
@@ -73795,6 +74053,10 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
73795
74053
|
const said = await this.tellGateway("here", { handle: this.doorKey, nextAt: this.store ? nextDue(this.store) : null });
|
|
73796
74054
|
if (said?.status === 200) saveMeta(this.webId, { hereAt: Date.now() }).catch(() => {
|
|
73797
74055
|
});
|
|
74056
|
+
if (said?.status === 200 && said.missingLetter && this.store?.read("trouble.json", null)?.letterMissing !== said.missingLetter) {
|
|
74057
|
+
this.noteTrouble({ kind: "test-letter", reason: "the gateway's test letter has not arrived", at: (/* @__PURE__ */ new Date()).toISOString() }, { tell: false });
|
|
74058
|
+
this.store.write("trouble.json", { ...this.store.read("trouble.json", {}), letterMissing: said.missingLetter });
|
|
74059
|
+
}
|
|
73798
74060
|
if (said?.status === 200 && typeof said.hold === "boolean") {
|
|
73799
74061
|
await followHold(this, this.frontOrigin, said.hold).catch((e) => this.log(`the gateway's hold: ${e.message}`));
|
|
73800
74062
|
}
|
|
@@ -73866,6 +74128,11 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
73866
74128
|
this.store.onEvent = (type, n) => {
|
|
73867
74129
|
if (type === "notification") this.notePush(n);
|
|
73868
74130
|
};
|
|
74131
|
+
const tried = this.store.read("published.json", {}).healTriedAt;
|
|
74132
|
+
if (!this.publisher.profileAgrees() && !(tried && Date.now() - Date.parse(tried) < 60 * 6e4)) {
|
|
74133
|
+
this.store.write("published.json", { ...this.store.read("published.json", {}), healTriedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
74134
|
+
await this.publisher.publishProfile({ force: true }).catch((e) => this.log(`profile: ${e.message}`));
|
|
74135
|
+
}
|
|
73869
74136
|
const now = Date.now();
|
|
73870
74137
|
const hereDue = !warm || now - (warm.hereAt || 0) >= _BrowserAgent.HERE_EVERY_MS;
|
|
73871
74138
|
const here = hereDue ? await this.hereAtGateway() : null;
|
|
@@ -73884,6 +74151,8 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
73884
74151
|
}, 3e4);
|
|
73885
74152
|
const drainNow = !warm || now - (warm.drainedAt || 0) >= DRAIN_EVERY_MS || here?.flushed > 0;
|
|
73886
74153
|
await this.intake.start({ drainNow, subscribe: !warm || !!warm.resubscribe });
|
|
74154
|
+
await this.atproto.moveToPod?.().catch((e) => this.log(`Bluesky account to the pod: ${e.message}`));
|
|
74155
|
+
await this.fediaccts.moveToPod?.().catch((e) => this.log(`connected accounts to the pod: ${e.message}`));
|
|
73887
74156
|
this.startBsky();
|
|
73888
74157
|
this.startAccts();
|
|
73889
74158
|
this.tagfeed?.start(this.mirrorStart("tags"));
|
|
@@ -74022,7 +74291,7 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
74022
74291
|
const fullLoad = () => this.store.load().catch((e) => {
|
|
74023
74292
|
unread = e;
|
|
74024
74293
|
});
|
|
74025
|
-
if (this._warm) await this.store.refresh(this._warm.pending).catch(fullLoad);
|
|
74294
|
+
if (this._warm && warmFrom.listingEtag) await this.store.refresh(this._warm.pending).catch(fullLoad);
|
|
74026
74295
|
else await fullLoad();
|
|
74027
74296
|
const cfg = config || this.store.getConfig();
|
|
74028
74297
|
if (!cfg) throw await accountNotRead({ unread, podBase: remotePod, state: this.urls.state, webId, actorUrl: this.urls.actor });
|
|
@@ -74097,6 +74366,16 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
74097
74366
|
lease: this.lease,
|
|
74098
74367
|
ownerPost: (a, o) => this.c2s.dispatch(a, o)
|
|
74099
74368
|
});
|
|
74369
|
+
this.intake.onTrouble = (t) => this.noteTrouble(t);
|
|
74370
|
+
if (this.gatewayApi) {
|
|
74371
|
+
this.intake.checkLetters = {
|
|
74372
|
+
actor: `${this.frontOrigin.replace(/\/$/u, "")}/check/actor`,
|
|
74373
|
+
taken: async (letter) => {
|
|
74374
|
+
const said = await this.tellGateway("check", { handle: this.doorKey, letter }, { standing: false });
|
|
74375
|
+
if (said?.status !== 200) throw new Error(`the gateway did not take the answer to its test letter (${said?.status || "no answer"})`);
|
|
74376
|
+
}
|
|
74377
|
+
};
|
|
74378
|
+
}
|
|
74100
74379
|
this.masto = new MastoApi({
|
|
74101
74380
|
agent: this,
|
|
74102
74381
|
log: this.log,
|
|
@@ -74112,8 +74391,11 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
74112
74391
|
this.tagfeed = new TagFeed({ store: this.store, intake: this.intake, log: this.log, fetcher: relayGet });
|
|
74113
74392
|
this.provisioning = (async () => {
|
|
74114
74393
|
if (!this._warm) await provisionPrivate(this.remote, this.urls);
|
|
74115
|
-
|
|
74116
|
-
await this.
|
|
74394
|
+
const readConn = !this._warm || !this._warm.connRead;
|
|
74395
|
+
await this.atproto.load({ fromPod: readConn });
|
|
74396
|
+
await this.fediaccts.load({ fromPod: readConn });
|
|
74397
|
+
if (readConn) saveMeta(this.webId, { connRead: true }).catch(() => {
|
|
74398
|
+
});
|
|
74117
74399
|
this.viewer = !(this._warm && !this._warm.renewDue ? true : await this.lease.acquire());
|
|
74118
74400
|
if (this.viewer) {
|
|
74119
74401
|
this._watched = true;
|
|
@@ -74157,7 +74439,8 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
74157
74439
|
podRequests: this.remote?.stats?.() || null,
|
|
74158
74440
|
update: null,
|
|
74159
74441
|
inboxCooldownFor: 0,
|
|
74160
|
-
stateSkipped: this.store?.lastSkipped || []
|
|
74442
|
+
stateSkipped: this.store?.lastSkipped || [],
|
|
74443
|
+
trouble: this.store?.read("trouble.json", null) || null
|
|
74161
74444
|
};
|
|
74162
74445
|
}
|
|
74163
74446
|
// Rotate the signing key (POST /rotate-key). Mint a fresh keypair, replace the
|
|
@@ -74619,6 +74902,28 @@ async function bridge(request, url, { sameOrigin: sameOrigin2 = false } = {}) {
|
|
|
74619
74902
|
// web/app/sw-src.mjs
|
|
74620
74903
|
var agent = null;
|
|
74621
74904
|
var booting = null;
|
|
74905
|
+
var LOG_KEEP = 300;
|
|
74906
|
+
var logLines = [];
|
|
74907
|
+
var logTimer = null;
|
|
74908
|
+
var logRead = kvGet("log").then((kept) => {
|
|
74909
|
+
logLines = [...Array.isArray(kept) ? kept : [], ...logLines].slice(-LOG_KEEP);
|
|
74910
|
+
}).catch(() => {
|
|
74911
|
+
});
|
|
74912
|
+
function agentLog(m) {
|
|
74913
|
+
console.log("[sw-agent]", m);
|
|
74914
|
+
const at = (/* @__PURE__ */ new Date()).toLocaleString(void 0, { month: "2-digit", day: "2-digit", hour: "numeric", minute: "2-digit", second: "2-digit" });
|
|
74915
|
+
logLines.push(`${at} ${m}`);
|
|
74916
|
+
if (logLines.length > LOG_KEEP) logLines.splice(0, logLines.length - LOG_KEEP);
|
|
74917
|
+
clearTimeout(logTimer);
|
|
74918
|
+
logTimer = setTimeout(() => {
|
|
74919
|
+
logRead.then(() => kvPut("log", logLines)).catch(() => {
|
|
74920
|
+
});
|
|
74921
|
+
}, 1500);
|
|
74922
|
+
}
|
|
74923
|
+
var recentLog = async () => {
|
|
74924
|
+
await logRead;
|
|
74925
|
+
return logLines;
|
|
74926
|
+
};
|
|
74622
74927
|
var FACADE = /^\/(api\/v[12]\/|oauth\/|nodeinfo\/)/;
|
|
74623
74928
|
var FACADE_EXACT = /* @__PURE__ */ new Set(["/.well-known/nodeinfo", "/.well-known/oauth-authorization-server", "/nodeinfo/2.0"]);
|
|
74624
74929
|
var isFacade = (p) => FACADE.test(p) || FACADE_EXACT.has(p);
|
|
@@ -74657,7 +74962,8 @@ self.addEventListener("activate", (e) => e.waitUntil(self.clients.claim()));
|
|
|
74657
74962
|
async function bootFromSession(frontOrigin, restart) {
|
|
74658
74963
|
const oidc = await getSession();
|
|
74659
74964
|
if (!oidc) throw new Error("no session \u2014 sign in first");
|
|
74660
|
-
const a = new BrowserAgent({ log:
|
|
74965
|
+
const a = new BrowserAgent({ log: agentLog });
|
|
74966
|
+
a.recentLog = recentLog;
|
|
74661
74967
|
await a.boot({ oidc, frontOrigin: frontOrigin || self.location.origin, restart });
|
|
74662
74968
|
agent = a;
|
|
74663
74969
|
return a;
|
|
@@ -74679,7 +74985,9 @@ self.addEventListener("message", (e) => {
|
|
|
74679
74985
|
return;
|
|
74680
74986
|
}
|
|
74681
74987
|
if (e.data?.type !== "boot") return;
|
|
74682
|
-
ensureBooting(e.data.frontOrigin)
|
|
74988
|
+
const booted = ensureBooting(e.data.frontOrigin);
|
|
74989
|
+
e.waitUntil(stillWorking(booted));
|
|
74990
|
+
booted.then(() => e.source?.postMessage({ type: "booted" })).catch((err) => e.source?.postMessage({
|
|
74683
74991
|
type: "boot-error",
|
|
74684
74992
|
error: err.message,
|
|
74685
74993
|
code: err.code || null,
|
|
@@ -74690,8 +74998,28 @@ self.addEventListener("fetch", (e) => {
|
|
|
74690
74998
|
const url = new URL(e.request.url);
|
|
74691
74999
|
if (url.origin !== self.location.origin || !(isFacade(url.pathname) || isAdmin(url.pathname))) return;
|
|
74692
75000
|
if (url.pathname.startsWith("/oauth/") && !sameOriginReferrer(e.request)) return;
|
|
74693
|
-
|
|
75001
|
+
const served = serve(e.request, url);
|
|
75002
|
+
e.respondWith(served);
|
|
75003
|
+
e.waitUntil(stillWorking(served));
|
|
74694
75004
|
});
|
|
75005
|
+
var STILL_WORKING_MS = 4 * 6e4;
|
|
75006
|
+
function stillWorking(first) {
|
|
75007
|
+
const work = (async () => {
|
|
75008
|
+
await Promise.resolve(first).catch(() => {
|
|
75009
|
+
});
|
|
75010
|
+
const a = agent;
|
|
75011
|
+
if (!a) return;
|
|
75012
|
+
await a.provisioning?.catch(() => {
|
|
75013
|
+
});
|
|
75014
|
+
await a.intake?.settled?.();
|
|
75015
|
+
})().catch(() => {
|
|
75016
|
+
});
|
|
75017
|
+
let timer;
|
|
75018
|
+
const cap = new Promise((r) => {
|
|
75019
|
+
timer = setTimeout(r, STILL_WORKING_MS);
|
|
75020
|
+
});
|
|
75021
|
+
return Promise.race([work, cap]).finally(() => clearTimeout(timer));
|
|
75022
|
+
}
|
|
74695
75023
|
async function serve(request, url) {
|
|
74696
75024
|
const refuse = notAllowed(request, url);
|
|
74697
75025
|
if (refuse) {
|