@fedify/fedify 2.4.0-dev.1951 → 2.4.0-dev.1959
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{builder-P44yYQ5Z.mjs → builder-sMkz-MdT.mjs} +2 -2
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{context-BOnn653X.d.cts → context-COLwHogJ.d.cts} +27 -0
- package/dist/{context-CmjP-cgJ.d.ts → context-DiiCt4S7.d.ts} +27 -0
- package/dist/{deno-U6Pe1U6h.mjs → deno-Xg7DR4LS.mjs} +1 -1
- package/dist/{docloader-DantBD_9.mjs → docloader-4YqMWBpt.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +3 -3
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/keycache.test.mjs +30 -4
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +195 -8
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +2 -2
- package/dist/federation/mod.d.ts +2 -2
- package/dist/federation/mod.js +1 -1
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/tasks/enqueue.test.mjs +3 -2
- package/dist/federation/tasks/tasks.test.mjs +4 -3
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{federation-BAtfz-C3.cjs → federation-BNJgxgH6.cjs} +32 -13
- package/dist/{http-CnBZmc4J.js → http-Bh37_81O.js} +1 -1
- package/dist/{http-BTD1L4Sv.cjs → http-BuOvqNbW.cjs} +1 -1
- package/dist/{http-Cssq59HU.mjs → http-DyXZdUng.mjs} +3 -3
- package/dist/{key-GeKuVU-k.mjs → key-CXsAkAt6.mjs} +2 -2
- package/dist/{keycache-0Jk78XmB.mjs → keycache-ZLqIfrkL.mjs} +3 -1
- package/dist/kv-DBRWVx3Q.mjs +104 -0
- package/dist/{kv-cache-D3gKJwUK.cjs → kv-cache-Btl0s7i7.cjs} +1 -1
- package/dist/{kv-cache-CoMnysg5.mjs → kv-cache-BubmP7z9.mjs} +1 -1
- package/dist/{kv-cache-CMUnx7rx.js → kv-cache-DjFxdXjk.js} +1 -1
- package/dist/{ld-BLl_mzo2.mjs → ld-C5Qv0_xn.mjs} +3 -3
- package/dist/{metrics-KDlQIBxX.mjs → metrics-B7-JxJSv.mjs} +1 -1
- package/dist/{middleware-CIlcGav-.mjs → middleware-BfRUvR8e.mjs} +1 -1
- package/dist/{middleware-aheUmEPU.js → middleware-CF539vn2.js} +32 -13
- package/dist/{middleware-D-vIOT8Y.mjs → middleware-DB_evWhA.mjs} +39 -22
- package/dist/{mod-kUSY5n3f.d.cts → mod-BZldCEU0.d.cts} +1 -1
- package/dist/{mod-BYuZ0WXt.d.ts → mod-CSH1Ee-I.d.ts} +1 -1
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +2 -2
- package/dist/mod.d.ts +2 -2
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/{owner-C111mU7b.mjs → owner-DFzwGoyv.mjs} +2 -2
- package/dist/{proof-CLZurGKe.js → proof-3rlJfM0Z.js} +1 -1
- package/dist/{proof-B_yPn2BI.cjs → proof-BVpjHUMS.cjs} +1 -1
- package/dist/{proof-B_5-ezjh.mjs → proof-DJGBYtRT.mjs} +4 -4
- package/dist/{send-r_mRJ1qS.mjs → send-BOXP7DyW.mjs} +3 -3
- package/dist/sig/http.test.mjs +2 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/proof.test.mjs +1 -1
- package/dist/{testing-D13ymFKy.mjs → tasks-dbCShlCb.mjs} +0 -1
- package/dist/{temporal-CIBMJUty.mjs → temporal-D6yzxQ23.mjs} +1 -1
- package/dist/testing/kv.test.d.mts +2 -0
- package/dist/testing/kv.test.mjs +101 -0
- package/dist/testing/mod.d.mts +70 -1
- package/dist/testing/mod.mjs +4 -2
- package/dist/testing-hbky2gMN.mjs +8 -0
- package/dist/utils/docloader.test.mjs +2 -2
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +7 -7
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
2
|
const require_rolldown_runtime = require("./rolldown-runtime-Dmm3t92W.cjs");
|
|
3
3
|
const require_transformers = require("./transformers-BalCrSsr.cjs");
|
|
4
|
-
const require_http = require("./http-
|
|
5
|
-
const require_proof = require("./proof-
|
|
4
|
+
const require_http = require("./http-BuOvqNbW.cjs");
|
|
5
|
+
const require_proof = require("./proof-BVpjHUMS.cjs");
|
|
6
6
|
const require_types = require("./types-RXm5YxpC.cjs");
|
|
7
|
-
const require_kv_cache = require("./kv-cache-
|
|
7
|
+
const require_kv_cache = require("./kv-cache-Btl0s7i7.cjs");
|
|
8
8
|
let _logtape_logtape = require("@logtape/logtape");
|
|
9
9
|
let _fedify_uri_template = require("@fedify/uri-template");
|
|
10
10
|
let _fedify_vocab = require("@fedify/vocab");
|
|
@@ -1463,12 +1463,14 @@ var KvKeyCache = class {
|
|
|
1463
1463
|
prefix;
|
|
1464
1464
|
options;
|
|
1465
1465
|
unavailableKeyTtl;
|
|
1466
|
+
keyTtl;
|
|
1466
1467
|
nullKeys;
|
|
1467
1468
|
constructor(kv, prefix, options = {}) {
|
|
1468
1469
|
this.kv = kv;
|
|
1469
1470
|
this.prefix = prefix;
|
|
1470
1471
|
this.options = options;
|
|
1471
1472
|
this.unavailableKeyTtl = options.unavailableKeyTtl ?? Temporal$8.Duration.from({ minutes: 10 });
|
|
1473
|
+
this.keyTtl = options.keyTtl ?? Temporal$8.Duration.from({ days: 30 });
|
|
1472
1474
|
this.nullKeys = /* @__PURE__ */ new Map();
|
|
1473
1475
|
}
|
|
1474
1476
|
#getFetchErrorKey(keyId) {
|
|
@@ -1509,7 +1511,7 @@ var KvKeyCache = class {
|
|
|
1509
1511
|
}
|
|
1510
1512
|
this.nullKeys.delete(keyId.href);
|
|
1511
1513
|
const serialized = await key.toJsonLd(this.options);
|
|
1512
|
-
await this.kv.set([...this.prefix, keyId.href], serialized);
|
|
1514
|
+
await this.kv.set([...this.prefix, keyId.href], serialized, { ttl: this.keyTtl });
|
|
1513
1515
|
}
|
|
1514
1516
|
async getFetchError(keyId) {
|
|
1515
1517
|
const cached = await this.kv.get(this.#getFetchErrorKey(keyId));
|
|
@@ -2467,7 +2469,7 @@ async function handleInbox(request, options) {
|
|
|
2467
2469
|
* @returns A promise that resolves to an HTTP response.
|
|
2468
2470
|
*/
|
|
2469
2471
|
async function handleInboxInternal(request, parameters, span) {
|
|
2470
|
-
const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, unverifiedActivityHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, inboxChallengePolicy, meterProvider, tracerProvider } = parameters;
|
|
2472
|
+
const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, publicKeyTtl, queue, actorDispatcher, inboxListeners, inboxErrorHandler, unverifiedActivityHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, inboxChallengePolicy, meterProvider, tracerProvider } = parameters;
|
|
2471
2473
|
const logger = (0, _logtape_logtape.getLogger)([
|
|
2472
2474
|
"fedify",
|
|
2473
2475
|
"federation",
|
|
@@ -2538,7 +2540,12 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2538
2540
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
2539
2541
|
});
|
|
2540
2542
|
}
|
|
2541
|
-
const keyCache = new KvKeyCache(kv, kvPrefixes.publicKey,
|
|
2543
|
+
const keyCache = new KvKeyCache(kv, kvPrefixes.publicKey, {
|
|
2544
|
+
documentLoader: ctx.documentLoader,
|
|
2545
|
+
contextLoader: ctx.contextLoader,
|
|
2546
|
+
tracerProvider,
|
|
2547
|
+
keyTtl: publicKeyTtl
|
|
2548
|
+
});
|
|
2542
2549
|
const jsonWithoutSig = require_proof.detachSignature(json);
|
|
2543
2550
|
const hasLdSignature = require_proof.hasSignature(json);
|
|
2544
2551
|
const canAttemptAlternateAuthAfterLdSignatureFailure = skipSignatureVerification || hasHttpSignatureHeaders(request) || hasObjectIntegrityProof(jsonWithoutSig);
|
|
@@ -4763,6 +4770,8 @@ function createFederation(options) {
|
|
|
4763
4770
|
var FederationImpl = class extends FederationBuilderImpl {
|
|
4764
4771
|
kv;
|
|
4765
4772
|
kvPrefixes;
|
|
4773
|
+
publicKeyTtl;
|
|
4774
|
+
httpMessageSignaturesSpecTtl;
|
|
4766
4775
|
inboxQueue;
|
|
4767
4776
|
outboxQueue;
|
|
4768
4777
|
fanoutQueue;
|
|
@@ -4828,6 +4837,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4828
4837
|
taskDeduplication: ["_fedify", "taskDeduplication"],
|
|
4829
4838
|
...options.kvPrefixes ?? {}
|
|
4830
4839
|
};
|
|
4840
|
+
this.publicKeyTtl = Temporal$2.Duration.from(options.publicKeyTtl ?? { days: 30 });
|
|
4841
|
+
this.httpMessageSignaturesSpecTtl = Temporal$2.Duration.from(options.httpMessageSignaturesSpecTtl ?? { days: 90 });
|
|
4831
4842
|
if (options.queue == null) {
|
|
4832
4843
|
this.inboxQueue = void 0;
|
|
4833
4844
|
this.outboxQueue = void 0;
|
|
@@ -4930,7 +4941,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4930
4941
|
this.authenticatedDocumentLoaderFactory = (identity, factoryOpts) => require_http.instrumentDocumentLoader(userAuthFactory != null ? userAuthFactory(identity, factoryOpts) : require_kv_cache.getAuthenticatedDocumentLoader(identity, {
|
|
4931
4942
|
allowPrivateAddress: factoryOpts?.allowPrivateAddress ?? allowPrivateAddress,
|
|
4932
4943
|
userAgent: factoryOpts?.userAgent ?? userAgent,
|
|
4933
|
-
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, options.firstKnock),
|
|
4944
|
+
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, options.firstKnock, { specTtl: this.httpMessageSignaturesSpecTtl }),
|
|
4934
4945
|
tracerProvider: this.tracerProvider
|
|
4935
4946
|
}), {
|
|
4936
4947
|
meterProvider: this._meterProvider,
|
|
@@ -5305,7 +5316,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5305
5316
|
inbox,
|
|
5306
5317
|
sharedInbox: message.sharedInbox,
|
|
5307
5318
|
headers: new Headers(message.headers),
|
|
5308
|
-
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock),
|
|
5319
|
+
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock, { specTtl: this.httpMessageSignaturesSpecTtl }),
|
|
5309
5320
|
meterProvider: this.meterProvider,
|
|
5310
5321
|
tracerProvider: this.tracerProvider
|
|
5311
5322
|
});
|
|
@@ -5926,7 +5937,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5926
5937
|
inbox: new URL(inbox),
|
|
5927
5938
|
sharedInbox: inboxes[inbox].sharedInbox,
|
|
5928
5939
|
headers: collectionSync == null ? void 0 : new Headers({ "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) }),
|
|
5929
|
-
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock),
|
|
5940
|
+
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock, { specTtl: this.httpMessageSignaturesSpecTtl }),
|
|
5930
5941
|
meterProvider: this.meterProvider,
|
|
5931
5942
|
tracerProvider: this.tracerProvider
|
|
5932
5943
|
}));
|
|
@@ -6239,6 +6250,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
6239
6250
|
inboxContextFactory,
|
|
6240
6251
|
kv: this.kv,
|
|
6241
6252
|
kvPrefixes: this.kvPrefixes,
|
|
6253
|
+
publicKeyTtl: this.publicKeyTtl,
|
|
6242
6254
|
queue: this.inboxQueue,
|
|
6243
6255
|
actorDispatcher: this.actorCallbacks?.dispatcher,
|
|
6244
6256
|
inboxListeners: this.inboxListeners,
|
|
@@ -6980,7 +6992,12 @@ var ContextImpl = class ContextImpl {
|
|
|
6980
6992
|
]);
|
|
6981
6993
|
const contextLoader = options.contextLoader ?? this.contextLoader;
|
|
6982
6994
|
const json = await activity.toJsonLd({ contextLoader });
|
|
6983
|
-
const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey,
|
|
6995
|
+
const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, {
|
|
6996
|
+
documentLoader: this.documentLoader,
|
|
6997
|
+
contextLoader: this.contextLoader,
|
|
6998
|
+
tracerProvider: this.tracerProvider,
|
|
6999
|
+
keyTtl: this.federation.publicKeyTtl
|
|
7000
|
+
});
|
|
6984
7001
|
if (await require_proof.verifyObject(_fedify_vocab.Activity, json, {
|
|
6985
7002
|
contextLoader,
|
|
6986
7003
|
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
@@ -7255,7 +7272,7 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
|
|
|
7255
7272
|
sharedInbox: inboxes[inbox].sharedInbox,
|
|
7256
7273
|
meterProvider: ctx.meterProvider,
|
|
7257
7274
|
tracerProvider: ctx.tracerProvider,
|
|
7258
|
-
specDeterminer: new KvSpecDeterminer(ctx.federation.kv, ctx.federation.kvPrefixes.httpMessageSignaturesSpec, ctx.federation.firstKnock)
|
|
7275
|
+
specDeterminer: new KvSpecDeterminer(ctx.federation.kv, ctx.federation.kvPrefixes.httpMessageSignaturesSpec, ctx.federation.firstKnock, { specTtl: ctx.federation.httpMessageSignaturesSpecTtl })
|
|
7259
7276
|
}));
|
|
7260
7277
|
await Promise.all(promises);
|
|
7261
7278
|
return true;
|
|
@@ -7426,16 +7443,18 @@ var KvSpecDeterminer = class {
|
|
|
7426
7443
|
kv;
|
|
7427
7444
|
prefix;
|
|
7428
7445
|
defaultSpec;
|
|
7429
|
-
|
|
7446
|
+
specTtl;
|
|
7447
|
+
constructor(kv, prefix, defaultSpec = "rfc9421", options = {}) {
|
|
7430
7448
|
this.kv = kv;
|
|
7431
7449
|
this.prefix = prefix;
|
|
7432
7450
|
this.defaultSpec = defaultSpec;
|
|
7451
|
+
this.specTtl = options.specTtl ?? Temporal$2.Duration.from({ days: 90 });
|
|
7433
7452
|
}
|
|
7434
7453
|
async determineSpec(origin) {
|
|
7435
7454
|
return await this.kv.get([...this.prefix, origin]) ?? this.defaultSpec;
|
|
7436
7455
|
}
|
|
7437
7456
|
async rememberSpec(origin, spec) {
|
|
7438
|
-
await this.kv.set([...this.prefix, origin], spec);
|
|
7457
|
+
await this.kv.set([...this.prefix, origin], spec, { ttl: this.specTtl });
|
|
7439
7458
|
}
|
|
7440
7459
|
};
|
|
7441
7460
|
function notFound(_request) {
|
|
@@ -10,7 +10,7 @@ import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } fro
|
|
|
10
10
|
import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
|
|
11
11
|
//#region deno.json
|
|
12
12
|
var name = "@fedify/fedify";
|
|
13
|
-
var version = "2.4.0-dev.
|
|
13
|
+
var version = "2.4.0-dev.1959+0da7be03";
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/sig/accept.ts
|
|
16
16
|
/**
|
|
@@ -9,7 +9,7 @@ let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conve
|
|
|
9
9
|
let byte_encodings_base64 = require("byte-encodings/base64");
|
|
10
10
|
//#region deno.json
|
|
11
11
|
var name = "@fedify/fedify";
|
|
12
|
-
var version = "2.4.0-dev.
|
|
12
|
+
var version = "2.4.0-dev.1959+0da7be03";
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region ../../node_modules/.pnpm/temporal-polyfill@1.0.1/node_modules/temporal-polyfill/chunks/root.js
|
|
15
15
|
const NativeTemporal = globalThis.Temporal;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-
|
|
4
|
+
import { n as version, t as name } from "./deno-Xg7DR4LS.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-B7-JxJSv.mjs";
|
|
6
6
|
import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CPVqki78.mjs";
|
|
7
|
-
import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-
|
|
7
|
+
import { o as validateCryptoKey, r as fetchKeyDetailed } from "./key-CXsAkAt6.mjs";
|
|
8
8
|
import { getLogger } from "@logtape/logtape";
|
|
9
9
|
import { CryptographicKey } from "@fedify/vocab";
|
|
10
10
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-
|
|
4
|
+
import { n as version, t as name } from "./deno-Xg7DR4LS.mjs";
|
|
5
|
+
import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-B7-JxJSv.mjs";
|
|
6
6
|
import { getLogger } from "@logtape/logtape";
|
|
7
7
|
import { CryptographicKey, Multikey, Object as Object$1, isActor } from "@fedify/vocab";
|
|
8
8
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -8,12 +8,14 @@ var KvKeyCache = class {
|
|
|
8
8
|
prefix;
|
|
9
9
|
options;
|
|
10
10
|
unavailableKeyTtl;
|
|
11
|
+
keyTtl;
|
|
11
12
|
nullKeys;
|
|
12
13
|
constructor(kv, prefix, options = {}) {
|
|
13
14
|
this.kv = kv;
|
|
14
15
|
this.prefix = prefix;
|
|
15
16
|
this.options = options;
|
|
16
17
|
this.unavailableKeyTtl = options.unavailableKeyTtl ?? Temporal.Duration.from({ minutes: 10 });
|
|
18
|
+
this.keyTtl = options.keyTtl ?? Temporal.Duration.from({ days: 30 });
|
|
17
19
|
this.nullKeys = /* @__PURE__ */ new Map();
|
|
18
20
|
}
|
|
19
21
|
#getFetchErrorKey(keyId) {
|
|
@@ -54,7 +56,7 @@ var KvKeyCache = class {
|
|
|
54
56
|
}
|
|
55
57
|
this.nullKeys.delete(keyId.href);
|
|
56
58
|
const serialized = await key.toJsonLd(this.options);
|
|
57
|
-
await this.kv.set([...this.prefix, keyId.href], serialized);
|
|
59
|
+
await this.kv.set([...this.prefix, keyId.href], serialized, { ttl: this.keyTtl });
|
|
58
60
|
}
|
|
59
61
|
async getFetchError(keyId) {
|
|
60
62
|
const cached = await this.kv.get(this.#getFetchErrorKey(keyId));
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Temporal } from "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { t as MemoryKvStore } from "./kv-DCHkaJ9-.mjs";
|
|
5
|
+
//#region src/testing/kv.ts
|
|
6
|
+
/**
|
|
7
|
+
* A {@link KvStore} decorator whose entry expiry is driven by a virtual clock
|
|
8
|
+
* instead of wall-clock time.
|
|
9
|
+
*
|
|
10
|
+
* {@link MemoryKvStore} decides expiry by comparing timestamps rather than by
|
|
11
|
+
* scheduling timers, so a test that wants to observe a TTL elapsing would
|
|
12
|
+
* otherwise have to sleep for longer than the TTL and hope the runner keeps
|
|
13
|
+
* up. That makes such tests both slow and load-sensitive.
|
|
14
|
+
*
|
|
15
|
+
* This decorator keeps the TTLs itself and never passes them to the store it
|
|
16
|
+
* wraps, so nothing expires until {@link advance} moves the clock. Cache
|
|
17
|
+
* hits, expiry, and repopulation therefore all become deterministic, without
|
|
18
|
+
* patching any global and without a test-only entry point in the library
|
|
19
|
+
* itself. The clock starts at the Unix epoch and only ever moves forward.
|
|
20
|
+
*/
|
|
21
|
+
var ManualClockKvStore = class {
|
|
22
|
+
#inner;
|
|
23
|
+
#expirations = /* @__PURE__ */ new Map();
|
|
24
|
+
#now = Temporal.Instant.fromEpochMilliseconds(0);
|
|
25
|
+
/**
|
|
26
|
+
* Present only when the wrapped store has its own `cas()`. Callers such as
|
|
27
|
+
* the task deduplication planner test `kv.cas != null` to decide whether a
|
|
28
|
+
* conditional write is available, so the decorator must not advertise a
|
|
29
|
+
* capability the wrapped store lacks.
|
|
30
|
+
*/
|
|
31
|
+
cas;
|
|
32
|
+
constructor(inner = new MemoryKvStore()) {
|
|
33
|
+
this.#inner = inner;
|
|
34
|
+
const innerCas = inner.cas;
|
|
35
|
+
if (innerCas != null) this.cas = async (key, expectedValue, newValue, options) => {
|
|
36
|
+
await this.#evictIfExpired(key);
|
|
37
|
+
const swapped = await innerCas.call(inner, key, expectedValue, newValue);
|
|
38
|
+
if (swapped) this.#recordTtl(key, options);
|
|
39
|
+
return swapped;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The current reading of the virtual clock.
|
|
44
|
+
*/
|
|
45
|
+
get now() {
|
|
46
|
+
return this.#now;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Moves the virtual clock forward. Any entry whose TTL has elapsed by the
|
|
50
|
+
* new time reads as missing from this point on, exactly as it would once a
|
|
51
|
+
* real `KvStore` had let it expire.
|
|
52
|
+
*/
|
|
53
|
+
advance(duration) {
|
|
54
|
+
this.#now = this.#now.add(Temporal.Duration.from(duration).round({ largestUnit: "hour" }));
|
|
55
|
+
}
|
|
56
|
+
#encodeKey(key) {
|
|
57
|
+
return JSON.stringify(key);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Drops the entry if its TTL has elapsed. Mirrors {@link MemoryKvStore},
|
|
61
|
+
* which treats an entry as live up to and including its expiration instant.
|
|
62
|
+
*/
|
|
63
|
+
async #evictIfExpired(key) {
|
|
64
|
+
const encodedKey = this.#encodeKey(key);
|
|
65
|
+
const expiration = this.#expirations.get(encodedKey);
|
|
66
|
+
if (expiration == null) return;
|
|
67
|
+
if (this.#now.until(expiration).sign >= 0) return;
|
|
68
|
+
this.#expirations.delete(encodedKey);
|
|
69
|
+
await this.#inner.delete(key);
|
|
70
|
+
}
|
|
71
|
+
async #evictAllExpired() {
|
|
72
|
+
for (const [encodedKey, expiration] of [...this.#expirations]) {
|
|
73
|
+
if (this.#now.until(expiration).sign >= 0) continue;
|
|
74
|
+
this.#expirations.delete(encodedKey);
|
|
75
|
+
await this.#inner.delete(JSON.parse(encodedKey));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
#recordTtl(key, options) {
|
|
79
|
+
const encodedKey = this.#encodeKey(key);
|
|
80
|
+
if (options?.ttl == null) {
|
|
81
|
+
this.#expirations.delete(encodedKey);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.#expirations.set(encodedKey, this.#now.add(options.ttl.round({ largestUnit: "hour" })));
|
|
85
|
+
}
|
|
86
|
+
async get(key) {
|
|
87
|
+
await this.#evictIfExpired(key);
|
|
88
|
+
return await this.#inner.get(key);
|
|
89
|
+
}
|
|
90
|
+
async set(key, value, options) {
|
|
91
|
+
this.#recordTtl(key, options);
|
|
92
|
+
await this.#inner.set(key, value);
|
|
93
|
+
}
|
|
94
|
+
async delete(key) {
|
|
95
|
+
this.#expirations.delete(this.#encodeKey(key));
|
|
96
|
+
await this.#inner.delete(key);
|
|
97
|
+
}
|
|
98
|
+
async *list(prefix) {
|
|
99
|
+
await this.#evictAllExpired();
|
|
100
|
+
yield* this.#inner.list(prefix);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
//#endregion
|
|
104
|
+
export { ManualClockKvStore as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
|
-
const require_http = require("./http-
|
|
2
|
+
const require_http = require("./http-BuOvqNbW.cjs");
|
|
3
3
|
let _logtape_logtape = require("@logtape/logtape");
|
|
4
4
|
let es_toolkit = require("es-toolkit");
|
|
5
5
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { p as recordDocumentCache } from "./metrics-
|
|
4
|
+
import { p as recordDocumentCache } from "./metrics-B7-JxJSv.mjs";
|
|
5
5
|
import { getLogger } from "@logtape/logtape";
|
|
6
6
|
import { preloadedContexts } from "@fedify/vocab-runtime";
|
|
7
7
|
//#region src/utils/kv-cache.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { C as recordDocumentCache, d as validateCryptoKey, t as doubleKnock } from "./http-
|
|
3
|
+
import { C as recordDocumentCache, d as validateCryptoKey, t as doubleKnock } from "./http-Bh37_81O.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
import { curry } from "es-toolkit";
|
|
6
6
|
import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-
|
|
6
|
-
import { n as fetchKey, o as validateCryptoKey } from "./key-
|
|
4
|
+
import { n as version, t as name } from "./deno-Xg7DR4LS.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-B7-JxJSv.mjs";
|
|
6
|
+
import { n as fetchKey, o as validateCryptoKey } from "./key-CXsAkAt6.mjs";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
8
8
|
import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
|
|
9
9
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
4
|
+
import { n as version, t as name } from "./deno-Xg7DR4LS.mjs";
|
|
5
5
|
import { metrics } from "@opentelemetry/api";
|
|
6
6
|
import { FetchError } from "@fedify/vocab-runtime";
|
|
7
7
|
//#region src/federation/metrics.ts
|
|
@@ -2,10 +2,10 @@ import { Temporal } from "temporal-polyfill";
|
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
import { t as __exportAll } from "./rolldown-runtime-BC-Eo5Mj.js";
|
|
4
4
|
import { r as getDefaultActivityTransformers } from "./transformers-DAtXl_Kc.js";
|
|
5
|
-
import { A as formatAcceptSignature, D as recordOutboxEnqueue, E as recordOutboxActivity, F as version, O as recordWebFingerHandle, P as name, S as recordCollectionTotalItems, T as recordInboxActivity, a as verifyRequestDetailed, b as recordCollectionPageItems, d as validateCryptoKey, f as getDurationMs, g as isAbortError, h as instrumentDocumentLoader, i as verifyRequest, k as registerQueueDepthGauge, m as getRemoteHost, n as parseRfc9421SignatureInput, o as exportJwk, p as getFederationMetrics, t as doubleKnock, u as importJwk, v as recordCircuitBreakerStateChange, w as recordFanoutRecipients, x as recordCollectionRequest, y as recordCollectionDispatchDuration } from "./http-
|
|
6
|
-
import { S as verifyCompactJsonLd, T as wrapContextLoaderForJsonLd, _ as hasSignature, b as isInvalidUrlTypeError, c as doesActorOwnKey, d as assertSafeJsonLd, g as getNormalizationContextLoader, h as detachSignature, i as verifyObject, l as getKeyOwner, n as hasProofLike, p as compactJsonLd, r as signObject, s as normalizeOutgoingActivityJsonLd, u as InvalidContextReferenceError, v as hasSignatureLike, x as signJsonLd, y as isClearlyMalformedContextReference } from "./proof-
|
|
5
|
+
import { A as formatAcceptSignature, D as recordOutboxEnqueue, E as recordOutboxActivity, F as version, O as recordWebFingerHandle, P as name, S as recordCollectionTotalItems, T as recordInboxActivity, a as verifyRequestDetailed, b as recordCollectionPageItems, d as validateCryptoKey, f as getDurationMs, g as isAbortError, h as instrumentDocumentLoader, i as verifyRequest, k as registerQueueDepthGauge, m as getRemoteHost, n as parseRfc9421SignatureInput, o as exportJwk, p as getFederationMetrics, t as doubleKnock, u as importJwk, v as recordCircuitBreakerStateChange, w as recordFanoutRecipients, x as recordCollectionRequest, y as recordCollectionDispatchDuration } from "./http-Bh37_81O.js";
|
|
6
|
+
import { S as verifyCompactJsonLd, T as wrapContextLoaderForJsonLd, _ as hasSignature, b as isInvalidUrlTypeError, c as doesActorOwnKey, d as assertSafeJsonLd, g as getNormalizationContextLoader, h as detachSignature, i as verifyObject, l as getKeyOwner, n as hasProofLike, p as compactJsonLd, r as signObject, s as normalizeOutgoingActivityJsonLd, u as InvalidContextReferenceError, v as hasSignatureLike, x as signJsonLd, y as isClearlyMalformedContextReference } from "./proof-3rlJfM0Z.js";
|
|
7
7
|
import { n as getNodeInfo, t as nodeInfoToJson } from "./types-Dtyf8lVj.js";
|
|
8
|
-
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-
|
|
8
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "./kv-cache-DjFxdXjk.js";
|
|
9
9
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
10
10
|
import { Router, RouterError, assertPath } from "@fedify/uri-template";
|
|
11
11
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
@@ -1460,12 +1460,14 @@ var KvKeyCache = class {
|
|
|
1460
1460
|
prefix;
|
|
1461
1461
|
options;
|
|
1462
1462
|
unavailableKeyTtl;
|
|
1463
|
+
keyTtl;
|
|
1463
1464
|
nullKeys;
|
|
1464
1465
|
constructor(kv, prefix, options = {}) {
|
|
1465
1466
|
this.kv = kv;
|
|
1466
1467
|
this.prefix = prefix;
|
|
1467
1468
|
this.options = options;
|
|
1468
1469
|
this.unavailableKeyTtl = options.unavailableKeyTtl ?? Temporal.Duration.from({ minutes: 10 });
|
|
1470
|
+
this.keyTtl = options.keyTtl ?? Temporal.Duration.from({ days: 30 });
|
|
1469
1471
|
this.nullKeys = /* @__PURE__ */ new Map();
|
|
1470
1472
|
}
|
|
1471
1473
|
#getFetchErrorKey(keyId) {
|
|
@@ -1506,7 +1508,7 @@ var KvKeyCache = class {
|
|
|
1506
1508
|
}
|
|
1507
1509
|
this.nullKeys.delete(keyId.href);
|
|
1508
1510
|
const serialized = await key.toJsonLd(this.options);
|
|
1509
|
-
await this.kv.set([...this.prefix, keyId.href], serialized);
|
|
1511
|
+
await this.kv.set([...this.prefix, keyId.href], serialized, { ttl: this.keyTtl });
|
|
1510
1512
|
}
|
|
1511
1513
|
async getFetchError(keyId) {
|
|
1512
1514
|
const cached = await this.kv.get(this.#getFetchErrorKey(keyId));
|
|
@@ -2462,7 +2464,7 @@ async function handleInbox(request, options) {
|
|
|
2462
2464
|
* @returns A promise that resolves to an HTTP response.
|
|
2463
2465
|
*/
|
|
2464
2466
|
async function handleInboxInternal(request, parameters, span) {
|
|
2465
|
-
const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, queue, actorDispatcher, inboxListeners, inboxErrorHandler, unverifiedActivityHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, inboxChallengePolicy, meterProvider, tracerProvider } = parameters;
|
|
2467
|
+
const { recipient, context: ctx, inboxContextFactory, kv, kvPrefixes, publicKeyTtl, queue, actorDispatcher, inboxListeners, inboxErrorHandler, unverifiedActivityHandler, onNotFound, signatureTimeWindow, skipSignatureVerification, inboxChallengePolicy, meterProvider, tracerProvider } = parameters;
|
|
2466
2468
|
const logger = getLogger([
|
|
2467
2469
|
"fedify",
|
|
2468
2470
|
"federation",
|
|
@@ -2533,7 +2535,12 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
2533
2535
|
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
2534
2536
|
});
|
|
2535
2537
|
}
|
|
2536
|
-
const keyCache = new KvKeyCache(kv, kvPrefixes.publicKey,
|
|
2538
|
+
const keyCache = new KvKeyCache(kv, kvPrefixes.publicKey, {
|
|
2539
|
+
documentLoader: ctx.documentLoader,
|
|
2540
|
+
contextLoader: ctx.contextLoader,
|
|
2541
|
+
tracerProvider,
|
|
2542
|
+
keyTtl: publicKeyTtl
|
|
2543
|
+
});
|
|
2537
2544
|
const jsonWithoutSig = detachSignature(json);
|
|
2538
2545
|
const hasLdSignature = hasSignature(json);
|
|
2539
2546
|
const canAttemptAlternateAuthAfterLdSignatureFailure = skipSignatureVerification || hasHttpSignatureHeaders(request) || hasObjectIntegrityProof(jsonWithoutSig);
|
|
@@ -4667,6 +4674,8 @@ function createFederation(options) {
|
|
|
4667
4674
|
var FederationImpl = class extends FederationBuilderImpl {
|
|
4668
4675
|
kv;
|
|
4669
4676
|
kvPrefixes;
|
|
4677
|
+
publicKeyTtl;
|
|
4678
|
+
httpMessageSignaturesSpecTtl;
|
|
4670
4679
|
inboxQueue;
|
|
4671
4680
|
outboxQueue;
|
|
4672
4681
|
fanoutQueue;
|
|
@@ -4732,6 +4741,8 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4732
4741
|
taskDeduplication: ["_fedify", "taskDeduplication"],
|
|
4733
4742
|
...options.kvPrefixes ?? {}
|
|
4734
4743
|
};
|
|
4744
|
+
this.publicKeyTtl = Temporal.Duration.from(options.publicKeyTtl ?? { days: 30 });
|
|
4745
|
+
this.httpMessageSignaturesSpecTtl = Temporal.Duration.from(options.httpMessageSignaturesSpecTtl ?? { days: 90 });
|
|
4735
4746
|
if (options.queue == null) {
|
|
4736
4747
|
this.inboxQueue = void 0;
|
|
4737
4748
|
this.outboxQueue = void 0;
|
|
@@ -4834,7 +4845,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
4834
4845
|
this.authenticatedDocumentLoaderFactory = (identity, factoryOpts) => instrumentDocumentLoader(userAuthFactory != null ? userAuthFactory(identity, factoryOpts) : getAuthenticatedDocumentLoader(identity, {
|
|
4835
4846
|
allowPrivateAddress: factoryOpts?.allowPrivateAddress ?? allowPrivateAddress,
|
|
4836
4847
|
userAgent: factoryOpts?.userAgent ?? userAgent,
|
|
4837
|
-
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, options.firstKnock),
|
|
4848
|
+
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, options.firstKnock, { specTtl: this.httpMessageSignaturesSpecTtl }),
|
|
4838
4849
|
tracerProvider: this.tracerProvider
|
|
4839
4850
|
}), {
|
|
4840
4851
|
meterProvider: this._meterProvider,
|
|
@@ -5209,7 +5220,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5209
5220
|
inbox,
|
|
5210
5221
|
sharedInbox: message.sharedInbox,
|
|
5211
5222
|
headers: new Headers(message.headers),
|
|
5212
|
-
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock),
|
|
5223
|
+
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock, { specTtl: this.httpMessageSignaturesSpecTtl }),
|
|
5213
5224
|
meterProvider: this.meterProvider,
|
|
5214
5225
|
tracerProvider: this.tracerProvider
|
|
5215
5226
|
});
|
|
@@ -5830,7 +5841,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
5830
5841
|
inbox: new URL(inbox),
|
|
5831
5842
|
sharedInbox: inboxes[inbox].sharedInbox,
|
|
5832
5843
|
headers: collectionSync == null ? void 0 : new Headers({ "Collection-Synchronization": await buildCollectionSynchronizationHeader(collectionSync, inboxes[inbox].actorIds) }),
|
|
5833
|
-
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock),
|
|
5844
|
+
specDeterminer: new KvSpecDeterminer(this.kv, this.kvPrefixes.httpMessageSignaturesSpec, this.firstKnock, { specTtl: this.httpMessageSignaturesSpecTtl }),
|
|
5834
5845
|
meterProvider: this.meterProvider,
|
|
5835
5846
|
tracerProvider: this.tracerProvider
|
|
5836
5847
|
}));
|
|
@@ -6143,6 +6154,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
6143
6154
|
inboxContextFactory,
|
|
6144
6155
|
kv: this.kv,
|
|
6145
6156
|
kvPrefixes: this.kvPrefixes,
|
|
6157
|
+
publicKeyTtl: this.publicKeyTtl,
|
|
6146
6158
|
queue: this.inboxQueue,
|
|
6147
6159
|
actorDispatcher: this.actorCallbacks?.dispatcher,
|
|
6148
6160
|
inboxListeners: this.inboxListeners,
|
|
@@ -6884,7 +6896,12 @@ var ContextImpl = class ContextImpl {
|
|
|
6884
6896
|
]);
|
|
6885
6897
|
const contextLoader = options.contextLoader ?? this.contextLoader;
|
|
6886
6898
|
const json = await activity.toJsonLd({ contextLoader });
|
|
6887
|
-
const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey,
|
|
6899
|
+
const keyCache = new KvKeyCache(this.federation.kv, this.federation.kvPrefixes.publicKey, {
|
|
6900
|
+
documentLoader: this.documentLoader,
|
|
6901
|
+
contextLoader: this.contextLoader,
|
|
6902
|
+
tracerProvider: this.tracerProvider,
|
|
6903
|
+
keyTtl: this.federation.publicKeyTtl
|
|
6904
|
+
});
|
|
6888
6905
|
if (await verifyObject(Activity, json, {
|
|
6889
6906
|
contextLoader,
|
|
6890
6907
|
documentLoader: options.documentLoader ?? this.documentLoader,
|
|
@@ -7159,7 +7176,7 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
|
|
|
7159
7176
|
sharedInbox: inboxes[inbox].sharedInbox,
|
|
7160
7177
|
meterProvider: ctx.meterProvider,
|
|
7161
7178
|
tracerProvider: ctx.tracerProvider,
|
|
7162
|
-
specDeterminer: new KvSpecDeterminer(ctx.federation.kv, ctx.federation.kvPrefixes.httpMessageSignaturesSpec, ctx.federation.firstKnock)
|
|
7179
|
+
specDeterminer: new KvSpecDeterminer(ctx.federation.kv, ctx.federation.kvPrefixes.httpMessageSignaturesSpec, ctx.federation.firstKnock, { specTtl: ctx.federation.httpMessageSignaturesSpecTtl })
|
|
7163
7180
|
}));
|
|
7164
7181
|
await Promise.all(promises);
|
|
7165
7182
|
return true;
|
|
@@ -7330,16 +7347,18 @@ var KvSpecDeterminer = class {
|
|
|
7330
7347
|
kv;
|
|
7331
7348
|
prefix;
|
|
7332
7349
|
defaultSpec;
|
|
7333
|
-
|
|
7350
|
+
specTtl;
|
|
7351
|
+
constructor(kv, prefix, defaultSpec = "rfc9421", options = {}) {
|
|
7334
7352
|
this.kv = kv;
|
|
7335
7353
|
this.prefix = prefix;
|
|
7336
7354
|
this.defaultSpec = defaultSpec;
|
|
7355
|
+
this.specTtl = options.specTtl ?? Temporal.Duration.from({ days: 90 });
|
|
7337
7356
|
}
|
|
7338
7357
|
async determineSpec(origin) {
|
|
7339
7358
|
return await this.kv.get([...this.prefix, origin]) ?? this.defaultSpec;
|
|
7340
7359
|
}
|
|
7341
7360
|
async rememberSpec(origin, spec) {
|
|
7342
|
-
await this.kv.set([...this.prefix, origin], spec);
|
|
7361
|
+
await this.kv.set([...this.prefix, origin], spec, { ttl: this.specTtl });
|
|
7343
7362
|
}
|
|
7344
7363
|
};
|
|
7345
7364
|
function notFound(_request) {
|