fedipod 1.50.2 → 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/timelines.mjs +5 -0
- package/lib/connections/acctfeed.mjs +4 -1
- package/lib/connections/tagfeed.mjs +4 -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/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 +65 -2
- 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 +567 -265
- 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
|
);
|
|
@@ -58587,6 +58742,21 @@ var Publisher = class {
|
|
|
58587
58742
|
// `clientOrigin` is overridden only by the agent serving a client its own
|
|
58588
58743
|
// local actor: standalone, the published document cannot name a loopback
|
|
58589
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
|
+
}
|
|
58590
58760
|
actorDocFor({
|
|
58591
58761
|
priv = false,
|
|
58592
58762
|
moderators = null,
|
|
@@ -58602,7 +58772,7 @@ var Publisher = class {
|
|
|
58602
58772
|
publicKeyPem: this.publicKeyPem,
|
|
58603
58773
|
movedTo,
|
|
58604
58774
|
kind: this.config.kind,
|
|
58605
|
-
approveJoins:
|
|
58775
|
+
approveJoins: this.approvesByHand(),
|
|
58606
58776
|
assertionKey: this.assertionKey,
|
|
58607
58777
|
summary: this.config.summary || null,
|
|
58608
58778
|
icon: this.config.icon || null,
|
|
@@ -58738,12 +58908,11 @@ var Publisher = class {
|
|
|
58738
58908
|
const updated = await this.announceProfileChange(actor, { force });
|
|
58739
58909
|
await this.ensurePrivateAcls();
|
|
58740
58910
|
const unreachable = await this.verifyPublicSurface();
|
|
58741
|
-
|
|
58742
|
-
this.store.
|
|
58743
|
-
|
|
58744
|
-
|
|
58745
|
-
|
|
58746
|
-
}
|
|
58911
|
+
this.store.write("published.json", {
|
|
58912
|
+
...this.store.read("published.json", {}),
|
|
58913
|
+
...!unreachable.length ? { surfaceDigest: surface } : {},
|
|
58914
|
+
approvesByHand: !!actorDoc2.manuallyApprovesFollowers
|
|
58915
|
+
});
|
|
58747
58916
|
const pubName = publicHandle(this.config);
|
|
58748
58917
|
const pubHost = this.config.gateway?.frontActor ? new URL(this.config.gateway.frontActor).host : host;
|
|
58749
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`);
|
|
@@ -59446,8 +59615,8 @@ async function isGone(intake, url) {
|
|
|
59446
59615
|
let res;
|
|
59447
59616
|
try {
|
|
59448
59617
|
res = await intake.deliverer.signedFetch(url, { headers: { accept: ACCEPT_AP2 } });
|
|
59449
|
-
} catch {
|
|
59450
|
-
return null;
|
|
59618
|
+
} catch (e) {
|
|
59619
|
+
return e?.answered && (e.status === 404 || e.status === 410) ? true : null;
|
|
59451
59620
|
}
|
|
59452
59621
|
if (res.status === 404 || res.status === 410) return true;
|
|
59453
59622
|
if (res.status < 400) {
|
|
@@ -65492,8 +65661,17 @@ var Intake = class {
|
|
|
65492
65661
|
rec.last = String(message || "").slice(0, 200);
|
|
65493
65662
|
all[url] = rec;
|
|
65494
65663
|
this.store.write(ATTEMPTS_DOC, all);
|
|
65664
|
+
if (rec.n === 2) this._trouble("failing", url, message);
|
|
65495
65665
|
return rec.n;
|
|
65496
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
|
+
}
|
|
65497
65675
|
_clearAttempt(url) {
|
|
65498
65676
|
const all = this.store.read(ATTEMPTS_DOC, {});
|
|
65499
65677
|
if (!all[url]) return;
|
|
@@ -65537,12 +65715,24 @@ var Intake = class {
|
|
|
65537
65715
|
this._draining = null;
|
|
65538
65716
|
if (this._drainAgain) {
|
|
65539
65717
|
this._drainAgain = false;
|
|
65540
|
-
|
|
65541
|
-
|
|
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?.();
|
|
65542
65723
|
}
|
|
65543
65724
|
});
|
|
65544
65725
|
return this._draining;
|
|
65545
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
|
+
}
|
|
65546
65736
|
// Discard the content waiting in the inbox from before `before`, on the
|
|
65547
65737
|
// owner's say-so — the admin page asks, this does it. NOT a blind sweep:
|
|
65548
65738
|
// every item is read, because the type is the only thing that decides its
|
|
@@ -65745,6 +65935,7 @@ var Intake = class {
|
|
|
65745
65935
|
this.log(`inbox batch ${url} attempt ${n}/${MAX_ITEM_ATTEMPTS}: ${e.message}`);
|
|
65746
65936
|
if (n >= MAX_ITEM_ATTEMPTS) {
|
|
65747
65937
|
this.store.addDeadLetter({ inboxUrl: url, reason: `failed ${n}x: ${e.message}`, activity: null });
|
|
65938
|
+
this._trouble("set-aside", url, e.message);
|
|
65748
65939
|
pending.push(url);
|
|
65749
65940
|
}
|
|
65750
65941
|
}
|
|
@@ -65768,6 +65959,7 @@ var Intake = class {
|
|
|
65768
65959
|
this.log(`inbox item ${url} attempt ${n}/${MAX_ITEM_ATTEMPTS}: ${e.message}`);
|
|
65769
65960
|
if (n >= MAX_ITEM_ATTEMPTS) {
|
|
65770
65961
|
this.store.addDeadLetter({ inboxUrl: url, reason: `failed ${n}x: ${e.message}`, activity: trimActivity(at.activity) });
|
|
65962
|
+
this._trouble("set-aside", url, e.message);
|
|
65771
65963
|
pending.push(url);
|
|
65772
65964
|
}
|
|
65773
65965
|
}
|
|
@@ -65788,6 +65980,11 @@ var Intake = class {
|
|
|
65788
65980
|
const read2 = raw ? await readLenient(raw) : null;
|
|
65789
65981
|
if (read2?.degraded) this.log(`inbox item ${url} grounded to read: ${read2.degraded}`);
|
|
65790
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
|
+
}
|
|
65791
65988
|
if (read2?.graph) {
|
|
65792
65989
|
const failure = await checkShapes(read2.graph);
|
|
65793
65990
|
if (failure) {
|
|
@@ -65842,6 +66039,7 @@ var Intake = class {
|
|
|
65842
66039
|
const batch = await this._batchEntries(url);
|
|
65843
66040
|
if (!batch) {
|
|
65844
66041
|
this.store.addDeadLetter({ inboxUrl: url, reason: "unreadable batch", activity: null });
|
|
66042
|
+
this._trouble("set-aside", url, "unreadable batch");
|
|
65845
66043
|
return { entries: 1, complete: true };
|
|
65846
66044
|
}
|
|
65847
66045
|
let complete = true;
|
|
@@ -65861,6 +66059,7 @@ var Intake = class {
|
|
|
65861
66059
|
this.log(`inbox batch entry ${key} attempt ${n}/${MAX_ITEM_ATTEMPTS}: ${err.message}`);
|
|
65862
66060
|
if (n >= MAX_ITEM_ATTEMPTS) {
|
|
65863
66061
|
this.store.addDeadLetter({ inboxUrl: key, reason: `failed ${n}x: ${err.message}`, activity: trimActivity(at.activity) });
|
|
66062
|
+
this._trouble("set-aside", key, err.message);
|
|
65864
66063
|
} else {
|
|
65865
66064
|
complete = false;
|
|
65866
66065
|
}
|
|
@@ -65899,6 +66098,7 @@ var Intake = class {
|
|
|
65899
66098
|
this.log(`held delivery ${key} attempt ${n}/${MAX_ITEM_ATTEMPTS}: ${err.message}`);
|
|
65900
66099
|
if (n >= MAX_ITEM_ATTEMPTS) {
|
|
65901
66100
|
this.store.addDeadLetter({ inboxUrl: key, reason: `failed ${n}x: ${err.message}`, activity: trimActivity(at.activity) });
|
|
66101
|
+
this._trouble("set-aside", key, err.message);
|
|
65902
66102
|
done.push(e.name);
|
|
65903
66103
|
}
|
|
65904
66104
|
}
|
|
@@ -69181,9 +69381,10 @@ async function handle4(api, ctx) {
|
|
|
69181
69381
|
const { req, res, pathname, url, send } = ctx;
|
|
69182
69382
|
if (pathname === "/api/v1/timelines/home" || pathname === "/api/v1/timelines/public" || pathname === "/api/v1/trends/statuses") {
|
|
69183
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;
|
|
69184
69385
|
const all = api.store.getStatuses();
|
|
69185
69386
|
const muted = new Set(api.store.getMuted().actors);
|
|
69186
|
-
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 || "")));
|
|
69187
69388
|
const { items: page2, headers } = api.page(items, url);
|
|
69188
69389
|
return send(200, page2.map((s) => api.statusOrBoost(s, { all })), headers);
|
|
69189
69390
|
}
|
|
@@ -70193,8 +70394,9 @@ var TagFeed = class {
|
|
|
70193
70394
|
if (Array.isArray(patch.tags)) clean.tags = patch.tags.map((t) => String(t).replace(/^#/, "").trim()).filter(Boolean);
|
|
70194
70395
|
if (patch.intervalMin) clean.intervalMin = Math.max(5, Number(patch.intervalMin) || DEFAULTS2.intervalMin);
|
|
70195
70396
|
this.store.write("tagfeed.json", { ...this.config(), ...clean });
|
|
70397
|
+
const sweeping = this.stopped === false;
|
|
70196
70398
|
this.stop();
|
|
70197
|
-
this.start();
|
|
70399
|
+
if (sweeping) this.start();
|
|
70198
70400
|
return this.config();
|
|
70199
70401
|
}
|
|
70200
70402
|
// `lastSweptAt` and `onSwept` are for a browser worker the browser stops and
|
|
@@ -71034,6 +71236,7 @@ var RelayDeliverer = class extends Deliverer {
|
|
|
71034
71236
|
if (status2 >= 400) {
|
|
71035
71237
|
const err = new Error(`${method} ${url} \u2192 ${status2}`);
|
|
71036
71238
|
err.status = status2;
|
|
71239
|
+
err.answered = true;
|
|
71037
71240
|
if (r0.retryAfter) {
|
|
71038
71241
|
const secs = Number(r0.retryAfter);
|
|
71039
71242
|
const ms = Number.isFinite(secs) ? Math.max(secs, 1) * 1e3 : Math.max(Date.parse(r0.retryAfter) - Date.now(), 1e3);
|
|
@@ -71418,7 +71621,7 @@ var ImportWorker = class {
|
|
|
71418
71621
|
|
|
71419
71622
|
// web/app/admin-facade.mjs
|
|
71420
71623
|
var PERMANENT_CONFIG = ["handle", "remotePod", "issuer", "root", "kind"];
|
|
71421
|
-
var WIRE_CONFIG = ["name", "summary", "icon", "image", "fields", "aliases"];
|
|
71624
|
+
var WIRE_CONFIG = ["name", "summary", "icon", "image", "fields", "aliases", "autoAcceptFollows"];
|
|
71422
71625
|
var ADMIN_PATHS = /* @__PURE__ */ new Set([
|
|
71423
71626
|
"/status",
|
|
71424
71627
|
"/config",
|
|
@@ -71427,6 +71630,7 @@ var ADMIN_PATHS = /* @__PURE__ */ new Set([
|
|
|
71427
71630
|
"/rotate-key",
|
|
71428
71631
|
"/import",
|
|
71429
71632
|
"/deadletter",
|
|
71633
|
+
"/trouble",
|
|
71430
71634
|
"/blocks",
|
|
71431
71635
|
"/profiles",
|
|
71432
71636
|
"/modqueue",
|
|
@@ -71528,6 +71732,7 @@ var AdminFacade = class {
|
|
|
71528
71732
|
fields: cfg.fields || [],
|
|
71529
71733
|
aliases: cfg.aliases || [],
|
|
71530
71734
|
autoAcceptFollows: cfg.autoAcceptFollows !== false,
|
|
71735
|
+
tagsInHome: cfg.tagsInHome !== false,
|
|
71531
71736
|
quiescedAt: cfg.quiescedAt || null,
|
|
71532
71737
|
movedTo: cfg.movedTo || null,
|
|
71533
71738
|
mode: a.status().mode,
|
|
@@ -71586,8 +71791,7 @@ var AdminFacade = class {
|
|
|
71586
71791
|
return json2(200, []);
|
|
71587
71792
|
// person: no moderation queue
|
|
71588
71793
|
case "/log":
|
|
71589
|
-
return json2(200, { lines: [] });
|
|
71590
|
-
// no local log file in the browser
|
|
71794
|
+
return json2(200, { lines: await a.recentLog?.() || [] });
|
|
71591
71795
|
case "/fediacct":
|
|
71592
71796
|
return json2(200, { accounts: a.fediaccts?.status() || [] });
|
|
71593
71797
|
case "/import":
|
|
@@ -71624,6 +71828,13 @@ var AdminFacade = class {
|
|
|
71624
71828
|
return json2(400, { error: "expected JSON body" });
|
|
71625
71829
|
}
|
|
71626
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
|
+
}
|
|
71627
71838
|
case "/config": {
|
|
71628
71839
|
const fixed = PERMANENT_CONFIG.filter((k) => k in body);
|
|
71629
71840
|
if (fixed.length) return json2(400, { error: `${fixed.join(", ")} cannot be changed \u2014 that is the identity itself` });
|
|
@@ -71643,6 +71854,7 @@ var AdminFacade = class {
|
|
|
71643
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() }));
|
|
71644
71855
|
}
|
|
71645
71856
|
if ("autoAcceptFollows" in body) cfg.autoAcceptFollows = !!body.autoAcceptFollows;
|
|
71857
|
+
if ("tagsInHome" in body) cfg.tagsInHome = !!body.tagsInHome;
|
|
71646
71858
|
const republish = WIRE_CONFIG.some((k) => k in body);
|
|
71647
71859
|
a.store.setConfig(cfg);
|
|
71648
71860
|
if ("autoAcceptFollows" in body && a.publisher) a.publisher.config.autoAcceptFollows = cfg.autoAcceptFollows;
|
|
@@ -71952,23 +72164,20 @@ var AdminFacade = class {
|
|
|
71952
72164
|
await a.store.flush();
|
|
71953
72165
|
return json2(200, { ok: true });
|
|
71954
72166
|
}
|
|
71955
|
-
// Bluesky settings: pause/resume the mirror
|
|
71956
|
-
//
|
|
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.
|
|
71957
72169
|
case "/atproto": {
|
|
71958
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" });
|
|
71959
72172
|
if ("feedPaused" in body) {
|
|
71960
72173
|
a.atproto.setFeedPaused(!!body.feedPaused);
|
|
71961
72174
|
a.restartBsky?.();
|
|
71962
72175
|
}
|
|
71963
|
-
if ("storage" in body) {
|
|
71964
|
-
if (!["pod", "browser"].includes(body.storage)) return json2(400, { error: "storage must be pod or browser" });
|
|
71965
|
-
a.atproto.setStorage(body.storage);
|
|
71966
|
-
}
|
|
71967
72176
|
return json2(200, { ok: true, ...a.atproto.status() });
|
|
71968
72177
|
}
|
|
71969
72178
|
// Connect a fediverse account on another server: start its OAuth at that
|
|
71970
72179
|
// server. The browser is then sent to `authorize`; the code comes back to
|
|
71971
|
-
// GET /fediacct/callback (above). The token
|
|
72180
|
+
// GET /fediacct/callback (above). The token is kept on the pod.
|
|
71972
72181
|
case "/fediacct/connect": {
|
|
71973
72182
|
if (!body.host) return json2(400, { error: "the address of the server is required" });
|
|
71974
72183
|
try {
|
|
@@ -71985,14 +72194,11 @@ var AdminFacade = class {
|
|
|
71985
72194
|
a.restartAccts?.();
|
|
71986
72195
|
return json2(200, { ok: true });
|
|
71987
72196
|
}
|
|
71988
|
-
// Pause/resume the mirror
|
|
72197
|
+
// Pause/resume the mirror. The credential is kept on the pod.
|
|
71989
72198
|
case "/fediacct": {
|
|
71990
72199
|
if (!body.id) return json2(400, { error: "id required" });
|
|
71991
|
-
|
|
71992
|
-
|
|
71993
|
-
if (!["pod", "browser"].includes(body.storage)) return json2(400, { error: "storage must be pod or browser" });
|
|
71994
|
-
row = a.fediaccts.setStorage(body.id, body.storage);
|
|
71995
|
-
} 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);
|
|
71996
72202
|
if (!row) return json2(404, { error: "no such account" });
|
|
71997
72203
|
a.restartAccts?.();
|
|
71998
72204
|
return json2(200, { ok: true, account: row });
|
|
@@ -72458,8 +72664,10 @@ var BrowserAtproto = class extends Atproto {
|
|
|
72458
72664
|
}
|
|
72459
72665
|
// The IndexedDB copy into memory, so read() stays synchronous as the base
|
|
72460
72666
|
// class expects. The pod copy is already in the loaded store.
|
|
72461
|
-
|
|
72667
|
+
// `fromPod`: the pod's record read as well (agent.mjs says when).
|
|
72668
|
+
async load({ fromPod = false } = {}) {
|
|
72462
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}`));
|
|
72463
72671
|
return this;
|
|
72464
72672
|
}
|
|
72465
72673
|
// Whichever backend holds it, tagged with where it lives. The stamped-record
|
|
@@ -72467,15 +72675,13 @@ var BrowserAtproto = class extends Atproto {
|
|
|
72467
72675
|
read() {
|
|
72468
72676
|
let rec = null;
|
|
72469
72677
|
let where = null;
|
|
72470
|
-
|
|
72678
|
+
const p = this.store.read(POD_DOC, null);
|
|
72679
|
+
if (p) {
|
|
72680
|
+
rec = p;
|
|
72681
|
+
where = "pod";
|
|
72682
|
+
} else if (this._idbRec) {
|
|
72471
72683
|
rec = this._idbRec;
|
|
72472
72684
|
where = "browser";
|
|
72473
|
-
} else {
|
|
72474
|
-
const p = this.store.read(POD_DOC, null);
|
|
72475
|
-
if (p) {
|
|
72476
|
-
rec = p;
|
|
72477
|
-
where = "pod";
|
|
72478
|
-
}
|
|
72479
72685
|
}
|
|
72480
72686
|
if (!rec) return null;
|
|
72481
72687
|
if (rec.mintedFor && this.actorId && rec.mintedFor !== this.actorId) {
|
|
@@ -72484,25 +72690,25 @@ var BrowserAtproto = class extends Atproto {
|
|
|
72484
72690
|
}
|
|
72485
72691
|
return { ...rec, storage: where };
|
|
72486
72692
|
}
|
|
72487
|
-
// Write to the record's chosen backend (default browser), and clear the other
|
|
72488
|
-
// so a moved credential leaves no copy behind.
|
|
72489
72693
|
write(rec) {
|
|
72490
|
-
|
|
72491
|
-
|
|
72492
|
-
|
|
72493
|
-
|
|
72494
|
-
|
|
72495
|
-
|
|
72496
|
-
|
|
72497
|
-
|
|
72498
|
-
|
|
72499
|
-
|
|
72500
|
-
this.
|
|
72501
|
-
|
|
72502
|
-
this.store.write(POD_DOC, null);
|
|
72503
|
-
this.store.flush?.().catch(() => {
|
|
72504
|
-
});
|
|
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;
|
|
72505
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;
|
|
72506
72712
|
}
|
|
72507
72713
|
status() {
|
|
72508
72714
|
const rec = this.read();
|
|
@@ -72525,11 +72731,6 @@ var BrowserAtproto = class extends Atproto {
|
|
|
72525
72731
|
const rec = this.read();
|
|
72526
72732
|
if (rec) this.write({ ...rec, feedPaused: !!on });
|
|
72527
72733
|
}
|
|
72528
|
-
// Move the credential between backends (the Options menu's Storage control).
|
|
72529
|
-
setStorage(where) {
|
|
72530
|
-
const rec = this.read();
|
|
72531
|
-
if (rec && (where === "pod" || where === "browser")) this.write({ ...rec, storage: where });
|
|
72532
|
-
}
|
|
72533
72734
|
async disconnect() {
|
|
72534
72735
|
const rec = this.read();
|
|
72535
72736
|
if (rec?.refreshJwt) {
|
|
@@ -72788,7 +72989,9 @@ var BrowserFediAccounts = class extends FediAccounts {
|
|
|
72788
72989
|
this._recs = /* @__PURE__ */ new Map();
|
|
72789
72990
|
this._apps = /* @__PURE__ */ new Map();
|
|
72790
72991
|
}
|
|
72791
|
-
|
|
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}`));
|
|
72792
72995
|
const all = await kvAll().catch(() => ({}));
|
|
72793
72996
|
for (const [k, v] of Object.entries(all)) {
|
|
72794
72997
|
if (k.startsWith("rec:")) this._recs.set(k.slice(4), v);
|
|
@@ -72813,15 +73016,13 @@ var BrowserFediAccounts = class extends FediAccounts {
|
|
|
72813
73016
|
read(id) {
|
|
72814
73017
|
let rec = null;
|
|
72815
73018
|
let where = null;
|
|
72816
|
-
|
|
73019
|
+
const p = this._podMap()[id];
|
|
73020
|
+
if (p) {
|
|
73021
|
+
rec = p;
|
|
73022
|
+
where = "pod";
|
|
73023
|
+
} else if (this._recs.has(id)) {
|
|
72817
73024
|
rec = this._recs.get(id);
|
|
72818
73025
|
where = "browser";
|
|
72819
|
-
} else {
|
|
72820
|
-
const p = this._podMap()[id];
|
|
72821
|
-
if (p) {
|
|
72822
|
-
rec = p;
|
|
72823
|
-
where = "pod";
|
|
72824
|
-
}
|
|
72825
73026
|
}
|
|
72826
73027
|
if (!rec) return null;
|
|
72827
73028
|
if (rec.mintedFor && this.actorId && rec.mintedFor !== this.actorId) {
|
|
@@ -72831,27 +73032,28 @@ var BrowserFediAccounts = class extends FediAccounts {
|
|
|
72831
73032
|
return { ...rec, storage: where };
|
|
72832
73033
|
}
|
|
72833
73034
|
write(rec) {
|
|
72834
|
-
const
|
|
72835
|
-
const
|
|
72836
|
-
|
|
72837
|
-
|
|
72838
|
-
|
|
72839
|
-
|
|
72840
|
-
|
|
72841
|
-
|
|
72842
|
-
|
|
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(() => {
|
|
72843
73053
|
});
|
|
72844
|
-
} else {
|
|
72845
|
-
this._recs.set(clean.id, clean);
|
|
72846
|
-
kvPut("rec:" + clean.id, clean).catch((e) => this.log(`fediacct persist: ${e.message}`));
|
|
72847
|
-
const map = this._podMap();
|
|
72848
|
-
if (clean.id in map) {
|
|
72849
|
-
delete map[clean.id];
|
|
72850
|
-
this.store.write(POD_DOC2, map);
|
|
72851
|
-
this.store.flush?.().catch(() => {
|
|
72852
|
-
});
|
|
72853
|
-
}
|
|
72854
73054
|
}
|
|
73055
|
+
this.log(`${moving.length} connected account(s) moved from this browser to the pod`);
|
|
73056
|
+
return moving.length;
|
|
72855
73057
|
}
|
|
72856
73058
|
// Best-effort: tell the server to revoke our token (RFC 7009), so a
|
|
72857
73059
|
// disconnect actually invalidates it there — not just locally. Mirrors
|
|
@@ -72904,15 +73106,6 @@ var BrowserFediAccounts = class extends FediAccounts {
|
|
|
72904
73106
|
cooldownFor: Math.max(0, Math.round(((this.pausedUntil.get(r.host) || 0) - Date.now()) / 1e3))
|
|
72905
73107
|
}));
|
|
72906
73108
|
}
|
|
72907
|
-
// Move a connection between backends (the Options menu's Storage control).
|
|
72908
|
-
setStorage(id, where) {
|
|
72909
|
-
const rec = this.read(id);
|
|
72910
|
-
if (rec && (where === "pod" || where === "browser")) {
|
|
72911
|
-
this.write({ ...rec, storage: where });
|
|
72912
|
-
return this.roster().find((r) => r.id === id) || null;
|
|
72913
|
-
}
|
|
72914
|
-
return null;
|
|
72915
|
-
}
|
|
72916
73109
|
// One app registration per host, remembered — over IndexedDB.
|
|
72917
73110
|
async appFor(host, redirectUri) {
|
|
72918
73111
|
const cached = this._apps.get(host);
|
|
@@ -73088,8 +73281,11 @@ var AcctFeed = class {
|
|
|
73088
73281
|
}
|
|
73089
73282
|
return map;
|
|
73090
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.
|
|
73091
73286
|
_rateGuard(id, handle7, res) {
|
|
73092
|
-
const
|
|
73287
|
+
const said = res.headers.get("x-ratelimit-remaining");
|
|
73288
|
+
const left = said == null || said.trim() === "" ? NaN : Number(said);
|
|
73093
73289
|
if (!Number.isFinite(left) || left > RATE_FLOOR) return false;
|
|
73094
73290
|
const reset = Date.parse(res.headers.get("x-ratelimit-reset") || "");
|
|
73095
73291
|
const wait = Number.isFinite(reset) ? Math.max(0, reset - Date.now()) : BACKOFF_MIN_MS3;
|
|
@@ -73199,7 +73395,8 @@ var fail2 = () => {
|
|
|
73199
73395
|
var promises_default = new Proxy({}, { get: () => fail2 });
|
|
73200
73396
|
|
|
73201
73397
|
// lib/core/pod-only.mjs
|
|
73202
|
-
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);
|
|
73203
73400
|
|
|
73204
73401
|
// lib/core/storage.mjs
|
|
73205
73402
|
var LDP2 = Namespace("http://www.w3.org/ns/ldp#");
|
|
@@ -73761,6 +73958,41 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
73761
73958
|
// (lib/gateway/held-mail.mjs: /api/push). Named a moment later, once written,
|
|
73762
73959
|
// so a burst is one call. One from another network is not pushed.
|
|
73763
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
|
+
}
|
|
73764
73996
|
notePush(n) {
|
|
73765
73997
|
if (!this.gatewayApi || n?.bsky || n?.via) return;
|
|
73766
73998
|
if (!Object.keys(this.store.read("webpush.json", { subs: {} }).subs || {}).length) return;
|
|
@@ -73821,6 +74053,10 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
73821
74053
|
const said = await this.tellGateway("here", { handle: this.doorKey, nextAt: this.store ? nextDue(this.store) : null });
|
|
73822
74054
|
if (said?.status === 200) saveMeta(this.webId, { hereAt: Date.now() }).catch(() => {
|
|
73823
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
|
+
}
|
|
73824
74060
|
if (said?.status === 200 && typeof said.hold === "boolean") {
|
|
73825
74061
|
await followHold(this, this.frontOrigin, said.hold).catch((e) => this.log(`the gateway's hold: ${e.message}`));
|
|
73826
74062
|
}
|
|
@@ -73892,6 +74128,11 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
73892
74128
|
this.store.onEvent = (type, n) => {
|
|
73893
74129
|
if (type === "notification") this.notePush(n);
|
|
73894
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
|
+
}
|
|
73895
74136
|
const now = Date.now();
|
|
73896
74137
|
const hereDue = !warm || now - (warm.hereAt || 0) >= _BrowserAgent.HERE_EVERY_MS;
|
|
73897
74138
|
const here = hereDue ? await this.hereAtGateway() : null;
|
|
@@ -73910,6 +74151,8 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
73910
74151
|
}, 3e4);
|
|
73911
74152
|
const drainNow = !warm || now - (warm.drainedAt || 0) >= DRAIN_EVERY_MS || here?.flushed > 0;
|
|
73912
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}`));
|
|
73913
74156
|
this.startBsky();
|
|
73914
74157
|
this.startAccts();
|
|
73915
74158
|
this.tagfeed?.start(this.mirrorStart("tags"));
|
|
@@ -74123,6 +74366,16 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
74123
74366
|
lease: this.lease,
|
|
74124
74367
|
ownerPost: (a, o) => this.c2s.dispatch(a, o)
|
|
74125
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
|
+
}
|
|
74126
74379
|
this.masto = new MastoApi({
|
|
74127
74380
|
agent: this,
|
|
74128
74381
|
log: this.log,
|
|
@@ -74138,8 +74391,11 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
74138
74391
|
this.tagfeed = new TagFeed({ store: this.store, intake: this.intake, log: this.log, fetcher: relayGet });
|
|
74139
74392
|
this.provisioning = (async () => {
|
|
74140
74393
|
if (!this._warm) await provisionPrivate(this.remote, this.urls);
|
|
74141
|
-
|
|
74142
|
-
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
|
+
});
|
|
74143
74399
|
this.viewer = !(this._warm && !this._warm.renewDue ? true : await this.lease.acquire());
|
|
74144
74400
|
if (this.viewer) {
|
|
74145
74401
|
this._watched = true;
|
|
@@ -74183,7 +74439,8 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
74183
74439
|
podRequests: this.remote?.stats?.() || null,
|
|
74184
74440
|
update: null,
|
|
74185
74441
|
inboxCooldownFor: 0,
|
|
74186
|
-
stateSkipped: this.store?.lastSkipped || []
|
|
74442
|
+
stateSkipped: this.store?.lastSkipped || [],
|
|
74443
|
+
trouble: this.store?.read("trouble.json", null) || null
|
|
74187
74444
|
};
|
|
74188
74445
|
}
|
|
74189
74446
|
// Rotate the signing key (POST /rotate-key). Mint a fresh keypair, replace the
|
|
@@ -74645,6 +74902,28 @@ async function bridge(request, url, { sameOrigin: sameOrigin2 = false } = {}) {
|
|
|
74645
74902
|
// web/app/sw-src.mjs
|
|
74646
74903
|
var agent = null;
|
|
74647
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
|
+
};
|
|
74648
74927
|
var FACADE = /^\/(api\/v[12]\/|oauth\/|nodeinfo\/)/;
|
|
74649
74928
|
var FACADE_EXACT = /* @__PURE__ */ new Set(["/.well-known/nodeinfo", "/.well-known/oauth-authorization-server", "/nodeinfo/2.0"]);
|
|
74650
74929
|
var isFacade = (p) => FACADE.test(p) || FACADE_EXACT.has(p);
|
|
@@ -74683,7 +74962,8 @@ self.addEventListener("activate", (e) => e.waitUntil(self.clients.claim()));
|
|
|
74683
74962
|
async function bootFromSession(frontOrigin, restart) {
|
|
74684
74963
|
const oidc = await getSession();
|
|
74685
74964
|
if (!oidc) throw new Error("no session \u2014 sign in first");
|
|
74686
|
-
const a = new BrowserAgent({ log:
|
|
74965
|
+
const a = new BrowserAgent({ log: agentLog });
|
|
74966
|
+
a.recentLog = recentLog;
|
|
74687
74967
|
await a.boot({ oidc, frontOrigin: frontOrigin || self.location.origin, restart });
|
|
74688
74968
|
agent = a;
|
|
74689
74969
|
return a;
|
|
@@ -74705,7 +74985,9 @@ self.addEventListener("message", (e) => {
|
|
|
74705
74985
|
return;
|
|
74706
74986
|
}
|
|
74707
74987
|
if (e.data?.type !== "boot") return;
|
|
74708
|
-
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({
|
|
74709
74991
|
type: "boot-error",
|
|
74710
74992
|
error: err.message,
|
|
74711
74993
|
code: err.code || null,
|
|
@@ -74716,8 +74998,28 @@ self.addEventListener("fetch", (e) => {
|
|
|
74716
74998
|
const url = new URL(e.request.url);
|
|
74717
74999
|
if (url.origin !== self.location.origin || !(isFacade(url.pathname) || isAdmin(url.pathname))) return;
|
|
74718
75000
|
if (url.pathname.startsWith("/oauth/") && !sameOriginReferrer(e.request)) return;
|
|
74719
|
-
|
|
75001
|
+
const served = serve(e.request, url);
|
|
75002
|
+
e.respondWith(served);
|
|
75003
|
+
e.waitUntil(stillWorking(served));
|
|
74720
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
|
+
}
|
|
74721
75023
|
async function serve(request, url) {
|
|
74722
75024
|
const refuse = notAllowed(request, url);
|
|
74723
75025
|
if (refuse) {
|