@fedify/vocab-runtime 2.4.0-dev.2228 → 2.4.0-dev.2240
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/deno.json +2 -2
- package/dist/internal/jsonld-cache.cjs +1 -1
- package/dist/internal/jsonld-cache.js +1 -1
- package/dist/internal/portable-dereference.cjs +6 -18
- package/dist/internal/portable-dereference.js +4 -16
- package/dist/mod.cjs +5 -2
- package/dist/mod.d.cts +107 -4
- package/dist/mod.d.ts +107 -4
- package/dist/mod.js +3 -3
- package/dist/tests/{body-BmNV5g5S.mjs → body-C00dWiYW.mjs} +1 -1
- package/dist/tests/{body-BQZL1aJ1.cjs → body-DHk-vT0I.cjs} +1 -1
- package/dist/tests/body.test.cjs +1 -1
- package/dist/tests/body.test.mjs +1 -1
- package/dist/tests/decimal.test.cjs +3 -3
- package/dist/tests/decimal.test.mjs +3 -3
- package/dist/tests/{docloader-ButlYQxr.mjs → docloader-Bi982uOa.mjs} +3 -3
- package/dist/tests/{docloader-BnuGCXLg.cjs → docloader-gX-8knd3.cjs} +3 -3
- package/dist/tests/docloader.test.cjs +59 -65
- package/dist/tests/docloader.test.mjs +38 -44
- package/dist/tests/internal/portable-dereference.test.cjs +30 -157
- package/dist/tests/internal/portable-dereference.test.mjs +13 -140
- package/dist/tests/{jsonld-cache-C7mkqjiE.mjs → jsonld-cache-CKfgtxPB.mjs} +1 -1
- package/dist/tests/{jsonld-cache-CXA76Xi6.cjs → jsonld-cache-DzxT9IXH.cjs} +1 -1
- package/dist/tests/jsonld-cache.test.cjs +2 -2
- package/dist/tests/jsonld-cache.test.mjs +2 -2
- package/dist/tests/multibase/multibase.test.cjs +7 -7
- package/dist/tests/multibase/multibase.test.mjs +5 -5
- package/dist/tests/portable-dereference-C_cwGjz6.mjs +132 -0
- package/dist/tests/portable-dereference-CyFYTBnr.cjs +149 -0
- package/dist/tests/{portable-media-CFrGpz-3.cjs → portable-media-B39cvJGK.cjs} +3 -3
- package/dist/tests/{portable-media-xFDDMte7.mjs → portable-media-l0ET9Pq8.mjs} +3 -3
- package/dist/tests/portable-media.test.cjs +1 -1
- package/dist/tests/portable-media.test.mjs +1 -1
- package/dist/tests/portable-workers.test.cjs +36 -0
- package/dist/tests/portable-workers.test.d.cts +2 -0
- package/dist/tests/portable-workers.test.d.mts +2 -0
- package/dist/tests/portable-workers.test.mjs +35 -0
- package/dist/tests/{request-2GDEEJng.mjs → request-BRPiDcmG.mjs} +1 -1
- package/dist/tests/{request-Cme6ShRu.cjs → request-fo2l2yJS.cjs} +1 -1
- package/dist/tests/request.test.cjs +1 -1
- package/dist/tests/request.test.mjs +1 -1
- package/dist/tests/{url-R9TTZ67B.mjs → url-CWC-NI3a.mjs} +224 -8
- package/dist/tests/{url-B6WlNhra.cjs → url-DsMBGqCc.cjs} +253 -7
- package/dist/tests/url.test.cjs +192 -1
- package/dist/tests/url.test.mjs +192 -1
- package/dist/{url-CHAbe3hE.cjs → url-BJMXv2kE.cjs} +253 -7
- package/dist/{url-BfguNa6K.js → url-CZm2-7ZO.js} +224 -8
- package/package.json +6 -3
- package/scripts/test-bun.mjs +17 -0
- package/src/docloader.test.ts +82 -74
- package/src/internal/portable-dereference.test.ts +14 -1
- package/src/internal/portable-dereference.ts +5 -19
- package/src/mod.ts +3 -0
- package/src/multibase/multibase.test.ts +5 -5
- package/src/portable-workers.test.ts +81 -0
- package/src/url.test.ts +385 -0
- package/src/url.ts +347 -13
package/dist/tests/url.test.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as
|
|
1
|
+
import { C as withoutGatewayHints, S as withGatewayHints, _ as parseIri, a as expandIPv6Address, b as validateLookupAddresses, c as getFe34Origin, d as haveSameIriOrigin, f as isGatewayUrl, g as parseGatewayUrl, i as canonicalizePortableUri, l as getGatewayHints, m as isValidPublicIPv6Address, n as UrlError, o as formatIri, p as isValidPublicIPv4Address, r as arePortableUrisEqual, s as fromCompatibleEf61Id, u as haveSameFe34Origin, v as parseJsonLdId, x as validatePublicUrl, y as toCompatibleEf61Id } from "./url-CWC-NI3a.mjs";
|
|
2
2
|
import { test } from "node:test";
|
|
3
3
|
import { deepStrictEqual, ok, rejects, strictEqual, throws } from "node:assert";
|
|
4
4
|
//#region src/url.test.ts
|
|
@@ -11,6 +11,39 @@ test("parseIri() accepts portable ActivityPub URI schemes", () => {
|
|
|
11
11
|
"AP+EF61://did:key:z6Mkabc/actor"
|
|
12
12
|
]) deepStrictEqual(parseIri(iri), new URL("ap+ef61://did%3Akey%3Az6Mkabc/actor"));
|
|
13
13
|
});
|
|
14
|
+
test("portable URI parsing refuses dot segments before URL normalization", () => {
|
|
15
|
+
const base = "ap://did:key:z6Mkabc";
|
|
16
|
+
for (const segment of [
|
|
17
|
+
".",
|
|
18
|
+
"..",
|
|
19
|
+
"%2e",
|
|
20
|
+
".%2E",
|
|
21
|
+
"%2e.",
|
|
22
|
+
"%2E%2e"
|
|
23
|
+
]) for (const path of [
|
|
24
|
+
`/${segment}`,
|
|
25
|
+
`/a/${segment}/b`,
|
|
26
|
+
`/a/${segment}`
|
|
27
|
+
]) {
|
|
28
|
+
const iri = base + path;
|
|
29
|
+
throws(() => parseIri(iri), TypeError, iri);
|
|
30
|
+
throws(() => parseJsonLdId(iri), TypeError, iri);
|
|
31
|
+
throws(() => formatIri(iri), TypeError, iri);
|
|
32
|
+
}
|
|
33
|
+
for (const iri of [
|
|
34
|
+
`${base}/a/.\t./b`,
|
|
35
|
+
`${base}/a/..\n/b`,
|
|
36
|
+
` ${base}/a/../b`,
|
|
37
|
+
`${base}/a/.. `
|
|
38
|
+
]) throws(() => parseIri(iri), TypeError, iri);
|
|
39
|
+
for (const path of [
|
|
40
|
+
"/a/.../b",
|
|
41
|
+
"/a/.x/b",
|
|
42
|
+
"/a/x.y/b",
|
|
43
|
+
"/a/%252e/b"
|
|
44
|
+
]) deepStrictEqual(formatIri(parseIri(base + path)), `ap+ef61://did:key:z6Mkabc${path}`);
|
|
45
|
+
throws(() => parseIri("child", `${base}/a/../b`), TypeError);
|
|
46
|
+
});
|
|
14
47
|
test("parseIri() normalizes DID scheme and method casing", () => {
|
|
15
48
|
for (const iri of [
|
|
16
49
|
"ap://DID:key:z6Mkabc/actor",
|
|
@@ -44,6 +77,20 @@ test("parseIri() resolves relative IRIs against portable string bases", () => {
|
|
|
44
77
|
deepStrictEqual(parseIri("attachments/1", "ap://did:key:z6Mkabc/objects/1"), new URL("ap+ef61://did%3Akey%3Az6Mkabc/objects/attachments/1"));
|
|
45
78
|
throws(() => parseIri("//example.com/outbox", "ap://did:key:z6Mkabc/objects/1"), TypeError);
|
|
46
79
|
});
|
|
80
|
+
test("parseIri() rejects lossy compatible ID string bases", () => {
|
|
81
|
+
const base = "https://server.example/.well-known/apgateway/did:key:z6MkAlice";
|
|
82
|
+
for (const segment of [
|
|
83
|
+
".",
|
|
84
|
+
"..",
|
|
85
|
+
"%2e",
|
|
86
|
+
"%2e%2e"
|
|
87
|
+
]) {
|
|
88
|
+
const rawBase = `${base}/a/${segment}/b`;
|
|
89
|
+
throws(() => parseIri("child", rawBase), TypeError, rawBase);
|
|
90
|
+
throws(() => parseJsonLdId("child", rawBase), TypeError, rawBase);
|
|
91
|
+
}
|
|
92
|
+
deepStrictEqual(parseIri("child", "https://server.example/a/../b"), new URL("https://server.example/child"));
|
|
93
|
+
});
|
|
47
94
|
test("parseIri() resolves relative IRIs against at:// string bases", () => {
|
|
48
95
|
deepStrictEqual(parseIri("/record", "at://did:plc:example/collection/item"), new URL("at://did%3Aplc%3Aexample/record"));
|
|
49
96
|
deepStrictEqual(parseIri("reply", "at://did:plc:example/collection/item"), new URL("at://did%3Aplc%3Aexample/collection/reply"));
|
|
@@ -316,6 +363,32 @@ test("fromCompatibleEf61Id() rejects malformed compatible identifiers", () => {
|
|
|
316
363
|
"https://user@server.example/.well-known/apgateway/did:key:z6MkAlice/a"
|
|
317
364
|
]) throws(() => fromCompatibleEf61Id(input), TypeError, input);
|
|
318
365
|
});
|
|
366
|
+
test("fromCompatibleEf61Id() refuses raw paths changed by URL parsing", () => {
|
|
367
|
+
const base = "https://server.example/.well-known/apgateway/did:key:z6MkAlice";
|
|
368
|
+
for (const path of [
|
|
369
|
+
"/a/../b",
|
|
370
|
+
"/a/%2e%2E/b",
|
|
371
|
+
"/a/. ./b",
|
|
372
|
+
"/a/.. "
|
|
373
|
+
]) {
|
|
374
|
+
throws(() => fromCompatibleEf61Id(base + path), TypeError, path);
|
|
375
|
+
throws(() => parseIri(base + path), TypeError, path);
|
|
376
|
+
throws(() => formatIri(base + path), TypeError, path);
|
|
377
|
+
}
|
|
378
|
+
for (const input of [
|
|
379
|
+
"https:/server.example/.well-known/apgateway/did:key:z6MkAlice/a/../b",
|
|
380
|
+
"https:server.example/.well-known/apgateway/did:key:z6MkAlice/a/../b",
|
|
381
|
+
"https:\\\\server.example\\.well-known\\apgateway\\did:key:z6MkAlice\\a\\..\\b",
|
|
382
|
+
` ${base}/../../other`
|
|
383
|
+
]) {
|
|
384
|
+
throws(() => parseIri(input), TypeError, input);
|
|
385
|
+
throws(() => formatIri(input), TypeError, input);
|
|
386
|
+
}
|
|
387
|
+
throws(() => fromCompatibleEf61Id(` ${base}/actor`), TypeError);
|
|
388
|
+
throws(() => fromCompatibleEf61Id(`https://server.example/foo/../.well-known/apgateway/did:key:z6MkAlice/actor`), TypeError);
|
|
389
|
+
deepStrictEqual(fromCompatibleEf61Id(`${base}/a/%252e/b`)?.pathname, "/a/%252e/b");
|
|
390
|
+
deepStrictEqual(fromCompatibleEf61Id("https://server.example/.WELL-KNOWN/apgateway/did:key:z6MkAlice/actor"), null);
|
|
391
|
+
});
|
|
319
392
|
test("toCompatibleEf61Id() converts portable URIs", () => {
|
|
320
393
|
const cases = [
|
|
321
394
|
[
|
|
@@ -620,5 +693,123 @@ test("expandIPv6Address()", () => {
|
|
|
620
693
|
deepStrictEqual(expandIPv6Address("2001:db8::1"), "2001:0db8:0000:0000:0000:0000:0000:0001");
|
|
621
694
|
deepStrictEqual(expandIPv6Address("64:ff9b::8.8.8.8"), "0064:ff9b:0000:0000:0000:0000:0808:0808");
|
|
622
695
|
});
|
|
696
|
+
test("withGatewayHints() adds @gateway location hints", () => {
|
|
697
|
+
const expected = "ap+ef61://did:key:z6Mkabc/actor?@gateway=https%3A%2F%2Fserver1.example&@gateway=https%3A%2F%2Fserver2.example";
|
|
698
|
+
for (const id of [
|
|
699
|
+
"ap://did:key:z6Mkabc/actor",
|
|
700
|
+
"ap+ef61://did:key:z6Mkabc/actor",
|
|
701
|
+
"ap://did%3Akey%3Az6Mkabc/actor",
|
|
702
|
+
parseIri("ap://did:key:z6Mkabc/actor"),
|
|
703
|
+
new URL("ap://did%3Akey%3Az6Mkabc/actor")
|
|
704
|
+
]) {
|
|
705
|
+
const hinted = withGatewayHints(id, ["https://server1.example", new URL("https://server2.example/")]);
|
|
706
|
+
ok(hinted instanceof URL);
|
|
707
|
+
strictEqual(hinted.href, "ap+ef61://did%3Akey%3Az6Mkabc/actor?@gateway=https%3A%2F%2Fserver1.example&@gateway=https%3A%2F%2Fserver2.example");
|
|
708
|
+
strictEqual(formatIri(hinted), expected);
|
|
709
|
+
deepStrictEqual(parseIri(formatIri(hinted)), hinted);
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
test("withGatewayHints() encodes and deduplicates gateway origins", () => {
|
|
713
|
+
function* gateways() {
|
|
714
|
+
yield "https://A.example:443";
|
|
715
|
+
yield "https://a.example/";
|
|
716
|
+
yield new URL("https://a.example");
|
|
717
|
+
yield "https://b.example:8443";
|
|
718
|
+
yield "http://c.example:80/";
|
|
719
|
+
yield "https://例え.jp";
|
|
720
|
+
}
|
|
721
|
+
strictEqual(formatIri(withGatewayHints("ap://did:key:z6Mkabc/actor", gateways())), "ap+ef61://did:key:z6Mkabc/actor?@gateway=https%3A%2F%2Fa.example&@gateway=https%3A%2F%2Fb.example%3A8443&@gateway=http%3A%2F%2Fc.example&@gateway=https%3A%2F%2Fxn--r8jz45g.jp");
|
|
722
|
+
strictEqual(formatIri(withGatewayHints("ap://did:key:z6Mkabc/actor", /* @__PURE__ */ new Set(["https://b.example", "https://a.example"]))), "ap+ef61://did:key:z6Mkabc/actor?@gateway=https%3A%2F%2Fb.example&@gateway=https%3A%2F%2Fa.example");
|
|
723
|
+
const many = Array.from({ length: 7 }, (_, i) => `https://server${i}.example`);
|
|
724
|
+
deepStrictEqual(getGatewayHints(withGatewayHints("ap://did:key:z6Mkabc/actor", many)).map((url) => url.origin), many);
|
|
725
|
+
});
|
|
726
|
+
test("withGatewayHints() keeps other query parameters and fragments", () => {
|
|
727
|
+
strictEqual(formatIri(withGatewayHints("ap://did:key:z6Mkabc/collection?page=3&maxItems=20&q=a+b%20c%2b", ["https://server.example"])), "ap+ef61://did:key:z6Mkabc/collection?page=3&maxItems=20&q=a+b%20c%2B&@gateway=https%3A%2F%2Fserver.example");
|
|
728
|
+
strictEqual(formatIri(withGatewayHints("ap://did:key:z6Mkabc/actor?x=%26%3D#main-key", ["https://server.example"])), "ap+ef61://did:key:z6Mkabc/actor?x=%26%3D&@gateway=https%3A%2F%2Fserver.example#main-key");
|
|
729
|
+
strictEqual(withGatewayHints("ap://did:key:z6Mkabc/actor#", ["https://s.example"]).href, "ap+ef61://did%3Akey%3Az6Mkabc/actor?@gateway=https%3A%2F%2Fs.example#");
|
|
730
|
+
});
|
|
731
|
+
test("withGatewayHints() replaces existing location hints", () => {
|
|
732
|
+
strictEqual(formatIri(withGatewayHints("ap://did:key:z6Mkabc/collection?@gateway=https%3A%2F%2Fold.example&page=2&%40gateway=https%3A%2F%2Fold2.example&@gateway&gateways=https%3A%2F%2Flegacy.example&%2540gateway=kept", ["https://new.example"])), "ap+ef61://did:key:z6Mkabc/collection?page=2&%2540gateway=kept&@gateway=https%3A%2F%2Fnew.example");
|
|
733
|
+
for (const char of [
|
|
734
|
+
" ",
|
|
735
|
+
"\n",
|
|
736
|
+
"\r"
|
|
737
|
+
]) deepStrictEqual(getGatewayHints(withGatewayHints(`ap://did:key:z6Mkabc/actor?@gate${char}way=https%3A%2F%2Fevil.example`, ["https://new.example"])).map((url) => url.href), ["https://new.example/"]);
|
|
738
|
+
});
|
|
739
|
+
test("withGatewayHints() with no gateways removes location hints", () => {
|
|
740
|
+
for (const [input, expected] of [
|
|
741
|
+
["ap://did:key:z6Mkabc/actor?@gateway=https%3A%2F%2Fa.example", "ap+ef61://did%3Akey%3Az6Mkabc/actor"],
|
|
742
|
+
["ap://did:key:z6Mkabc/actor?&@gateway=https%3A%2F%2Fa.example&&p=1&", "ap+ef61://did%3Akey%3Az6Mkabc/actor?p=1"],
|
|
743
|
+
["ap://did:key:z6Mkabc/actor?", "ap+ef61://did%3Akey%3Az6Mkabc/actor"],
|
|
744
|
+
["ap://did:key:z6Mkabc/actor?gateways=https%3A%2F%2Fa.example#k", "ap+ef61://did%3Akey%3Az6Mkabc/actor#k"]
|
|
745
|
+
]) {
|
|
746
|
+
strictEqual(withGatewayHints(input, []).href, expected, input);
|
|
747
|
+
strictEqual(withoutGatewayHints(input).href, expected, input);
|
|
748
|
+
}
|
|
749
|
+
const input = parseIri("ap://did:key:z6Mkabc/actor?@gateway=https%3A%2F%2Fa.example");
|
|
750
|
+
const href = input.href;
|
|
751
|
+
withoutGatewayHints(input);
|
|
752
|
+
strictEqual(input.href, href);
|
|
753
|
+
});
|
|
754
|
+
test("withGatewayHints() rejects non-portable IDs", () => {
|
|
755
|
+
for (const id of [
|
|
756
|
+
"https://server.example/.well-known/apgateway/did:key:z6Mkabc/actor",
|
|
757
|
+
"https://example.com/actor",
|
|
758
|
+
"did:key:z6Mkabc#z6Mkabc",
|
|
759
|
+
"ap://did:key:z6Mkabc",
|
|
760
|
+
"ap://example.com/actor",
|
|
761
|
+
"ap://did:key:z6Mkabc/actor%zz",
|
|
762
|
+
new URL("https://example.com/actor"),
|
|
763
|
+
new URL("ap://did%3Akey%3Az6Mkabc:8080/actor"),
|
|
764
|
+
new URL("ap://user@did%3Akey%3Az6Mkabc/actor")
|
|
765
|
+
]) {
|
|
766
|
+
throws(() => withGatewayHints(id, ["https://server.example"]), TypeError, String(id));
|
|
767
|
+
throws(() => withoutGatewayHints(id), TypeError, String(id));
|
|
768
|
+
throws(() => getGatewayHints(id), TypeError, String(id));
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
test("withGatewayHints() rejects paths that URLs cannot represent", () => {
|
|
772
|
+
for (const id of [
|
|
773
|
+
"ap://did:key:z6Mkabc/a/../actor",
|
|
774
|
+
"ap://did:key:z6Mkabc/a/./actor",
|
|
775
|
+
"ap://did:key:z6Mkabc/a/%2e%2e/actor",
|
|
776
|
+
"ap://did:key:z6Mkabc/a/%2E/actor"
|
|
777
|
+
]) {
|
|
778
|
+
throws(() => withGatewayHints(id, ["https://server.example"]), TypeError, id);
|
|
779
|
+
throws(() => withoutGatewayHints(id), TypeError, id);
|
|
780
|
+
}
|
|
781
|
+
strictEqual(withoutGatewayHints("ap://did:key:z6Mkabc/a b").href, "ap+ef61://did%3Akey%3Az6Mkabc/a%09b");
|
|
782
|
+
});
|
|
783
|
+
test("withGatewayHints() rejects invalid gateways", () => {
|
|
784
|
+
for (const gateway of [
|
|
785
|
+
"https://server.example/path",
|
|
786
|
+
"https://server.example/?",
|
|
787
|
+
"https://server.example/#",
|
|
788
|
+
"https://server.example/?q=1",
|
|
789
|
+
"https://user:pass@server.example",
|
|
790
|
+
"ftp://server.example",
|
|
791
|
+
"ap://did:key:z6Mkabc/actor",
|
|
792
|
+
"server.example",
|
|
793
|
+
new URL("https://server.example/path")
|
|
794
|
+
]) throws(() => withGatewayHints("ap://did:key:z6Mkabc/actor", [gateway]), TypeError, String(gateway));
|
|
795
|
+
throws(() => withGatewayHints("ap://did:key:z6Mkabc/actor", "https://server.example"), TypeError);
|
|
796
|
+
});
|
|
797
|
+
test("getGatewayHints() reads @gateway location hints", () => {
|
|
798
|
+
deepStrictEqual(getGatewayHints("ap://did:key:z6Mkabc/actor?@gateway=https%3A%2F%2Fa.example&@gateway=invalid&%40gateway=https%3A%2F%2Fb.example%2F&@gateway=https%3A%2F%2Fa.example%2F&@gateway=https%3A%2F%2Fc.example%2Fpath&gateways=https%3A%2F%2Flegacy.example&page=1#k").map((url) => url.href), ["https://a.example/", "https://b.example/"]);
|
|
799
|
+
deepStrictEqual(getGatewayHints("ap://did:key:z6Mkabc/actor"), []);
|
|
800
|
+
const questioned = "ap://did:key:z6Mkabc/actor??@gateway=https%3A%2F%2Fa.example";
|
|
801
|
+
deepStrictEqual(getGatewayHints(questioned), []);
|
|
802
|
+
strictEqual(withoutGatewayHints(questioned).href, "ap+ef61://did%3Akey%3Az6Mkabc/actor??@gateway=https%3A%2F%2Fa.example");
|
|
803
|
+
deepStrictEqual(getGatewayHints(withGatewayHints(questioned, ["https://b.example"])).map((url) => url.href), ["https://b.example/"]);
|
|
804
|
+
deepStrictEqual(getGatewayHints("ap://did:key:z6Mkabc/actor?@gate%09way=https%3A%2F%2Fa.example"), []);
|
|
805
|
+
deepStrictEqual(getGatewayHints("ap://did:key:z6Mkabc/actor?@gate way=https%3A%2F%2Fa.example"), []);
|
|
806
|
+
});
|
|
807
|
+
test("withGatewayHints() round-trips with other portable ID helpers", () => {
|
|
808
|
+
const hinted = withGatewayHints("ap://did:key:z6Mkabc/objects/1#frag", ["https://server1.example", "https://server2.example"]);
|
|
809
|
+
strictEqual(canonicalizePortableUri(formatIri(hinted)), "ap+ef61://did:key:z6Mkabc/objects/1#frag");
|
|
810
|
+
ok(arePortableUrisEqual(formatIri(hinted), "ap://did:key:z6Mkabc/objects/1#frag"));
|
|
811
|
+
strictEqual(toCompatibleEf61Id(hinted, "https://server1.example").href, "https://server1.example/.well-known/apgateway/did:key:z6Mkabc/objects/1#frag");
|
|
812
|
+
strictEqual(formatIri(withoutGatewayHints(hinted)), "ap+ef61://did:key:z6Mkabc/objects/1#frag");
|
|
813
|
+
});
|
|
623
814
|
//#endregion
|
|
624
815
|
export {};
|
|
@@ -22,6 +22,26 @@ const INVALID_PERCENT_ENCODING_PATTERN = /%(?![0-9A-Fa-f]{2})/;
|
|
|
22
22
|
const PERCENT_ENCODING_PATTERN = /%[0-9A-Fa-f]{2}/g;
|
|
23
23
|
const DID_SCHEME_PATTERN = /^did:/i;
|
|
24
24
|
const DID_PATTERN = /^did:[a-z0-9]+:[-A-Za-z0-9._%]+(?::[-A-Za-z0-9._%]+)*$/i;
|
|
25
|
+
const DOT_SEGMENT_PATTERN = /(?:^|\/)(?:\.|%2e){1,2}(?=\/|$)/i;
|
|
26
|
+
function prepareUrlInput(iri) {
|
|
27
|
+
let prepared = iri.replace(/[\t\n\r]/g, "");
|
|
28
|
+
while (prepared.length > 0 && prepared.charCodeAt(0) <= 32) prepared = prepared.slice(1);
|
|
29
|
+
while (prepared.length > 0 && prepared.charCodeAt(prepared.length - 1) <= 32) prepared = prepared.slice(0, -1);
|
|
30
|
+
return prepared;
|
|
31
|
+
}
|
|
32
|
+
function assertPortablePathCanBeParsed(iri) {
|
|
33
|
+
const match = prepareUrlInput(iri).match(PORTABLE_IRI_PATTERN);
|
|
34
|
+
if (match != null && DOT_SEGMENT_PATTERN.test(match[3])) throw new TypeError("Portable ActivityPub IRI paths with dot segments cannot be represented as URLs.");
|
|
35
|
+
}
|
|
36
|
+
function assertCompatiblePathCanBeParsed(raw, parsed) {
|
|
37
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return;
|
|
38
|
+
const match = prepareUrlInput(raw).match(/^https?:[\/\\]*[^/?#\\]*([^?#]*)/i);
|
|
39
|
+
if (match == null) return;
|
|
40
|
+
const rawPath = match[1].replace(/\\/g, "/");
|
|
41
|
+
const compatiblePath = parsed.pathname.startsWith(COMPATIBLE_ID_PATH_PREFIX) && COMPATIBLE_ID_DID_PATTERN.test(parsed.pathname.slice(COMPATIBLE_ID_PATH_PREFIX.length));
|
|
42
|
+
const rawCompatiblePath = rawPath.startsWith(COMPATIBLE_ID_PATH_PREFIX) && COMPATIBLE_ID_DID_PATTERN.test(rawPath.slice(COMPATIBLE_ID_PATH_PREFIX.length));
|
|
43
|
+
if ((compatiblePath || rawCompatiblePath) && DOT_SEGMENT_PATTERN.test(rawPath)) throw new TypeError("FEP-ef61 compatible identifier paths with dot segments cannot be represented as URLs.");
|
|
44
|
+
}
|
|
25
45
|
/**
|
|
26
46
|
* Parses a JSON-LD `@id` value as an IRI.
|
|
27
47
|
*/
|
|
@@ -35,22 +55,40 @@ function parseJsonLdId(id, base) {
|
|
|
35
55
|
}
|
|
36
56
|
/**
|
|
37
57
|
* Parses an IRI as a URL, including FEP-ef61 portable ActivityPub IRIs.
|
|
58
|
+
* Portable URI and FEP-ef61 compatible identifier strings whose path contains
|
|
59
|
+
* a `.` or `..` segment, including percent-encoded spellings, throw a
|
|
60
|
+
* `TypeError`: JavaScript `URL` would otherwise identify a different object.
|
|
61
|
+
* This also applies to compatible identifier strings used as relative bases.
|
|
62
|
+
* A `URL` argument may already have lost such segments before this function
|
|
63
|
+
* receives it.
|
|
38
64
|
*/
|
|
39
65
|
function parseIri(iri, base) {
|
|
40
66
|
if (iri instanceof URL) return normalizePortableUrl(iri) ?? new URL(iri.href);
|
|
67
|
+
assertPortablePathCanBeParsed(iri);
|
|
41
68
|
const portable = parsePortableIri(iri);
|
|
42
69
|
if (portable != null) return portable;
|
|
43
70
|
base = normalizeBaseIri(base);
|
|
44
71
|
if (!URL.canParse(iri, base) && iri.startsWith("at://")) return parseAtUri(iri);
|
|
45
72
|
const parsed = new URL(iri, base);
|
|
73
|
+
assertCompatiblePathCanBeParsed(iri, parsed);
|
|
46
74
|
return normalizePortableUrl(parsed) ?? parsed;
|
|
47
75
|
}
|
|
48
76
|
/**
|
|
49
77
|
* Formats a URL as an IRI, including FEP-ef61 portable ActivityPub IRIs.
|
|
78
|
+
* Portable URI and FEP-ef61 compatible identifier strings with dot segments
|
|
79
|
+
* throw a `TypeError` because their paths cannot be represented by JavaScript
|
|
80
|
+
* `URL` without normalization.
|
|
50
81
|
*/
|
|
51
82
|
function formatIri(iri) {
|
|
83
|
+
if (typeof iri === "string") assertPortablePathCanBeParsed(iri);
|
|
52
84
|
const parsed = parsePortableIri(iri instanceof URL ? iri.href : iri);
|
|
53
|
-
if (parsed == null)
|
|
85
|
+
if (parsed == null) {
|
|
86
|
+
if (iri instanceof URL) return iri.href;
|
|
87
|
+
if (!URL.canParse(iri)) return iri;
|
|
88
|
+
const url = new URL(iri);
|
|
89
|
+
assertCompatiblePathCanBeParsed(iri, url);
|
|
90
|
+
return url.href;
|
|
91
|
+
}
|
|
54
92
|
return `ap+ef61://${decodePortableAuthority(parsed.host)}${parsed.pathname}${parsed.search}${parsed.hash}`;
|
|
55
93
|
}
|
|
56
94
|
/**
|
|
@@ -170,11 +208,15 @@ function parsePortableIri(iri) {
|
|
|
170
208
|
}
|
|
171
209
|
function normalizePortableUrl(iri) {
|
|
172
210
|
if (iri.protocol !== "ap:" && iri.protocol !== "ap+ef61:") return null;
|
|
173
|
-
|
|
211
|
+
const raw = `ap+ef61://${iri.host}${iri.pathname}${iri.search}${iri.hash}`;
|
|
212
|
+
assertPortablePathCanBeParsed(raw);
|
|
213
|
+
return parsePortableIri(raw);
|
|
174
214
|
}
|
|
175
215
|
function normalizeBaseIri(base) {
|
|
176
216
|
if (base == null) return void 0;
|
|
177
217
|
if (base instanceof URL) return normalizePortableUrl(base) ?? base;
|
|
218
|
+
assertPortablePathCanBeParsed(base);
|
|
219
|
+
if (URL.canParse(base)) assertCompatiblePathCanBeParsed(base, new URL(base));
|
|
178
220
|
return parsePortableIri(base) ?? (base.startsWith("at://") && !URL.canParse(".", base) ? parseAtUri(base) : base);
|
|
179
221
|
}
|
|
180
222
|
function decodePortableAuthority(authority) {
|
|
@@ -241,6 +283,7 @@ function parseGatewayUrl(url) {
|
|
|
241
283
|
}
|
|
242
284
|
const COMPATIBLE_ID_PATH_PREFIX = "/.well-known/apgateway/";
|
|
243
285
|
const COMPATIBLE_ID_DID_PATTERN = /^did(?::|%3A)/i;
|
|
286
|
+
const RAW_COMPATIBLE_ID_PREFIX_PATTERN = /^(?:[hH][tT][tT][pP][sS]?):\/\/[^/?#]*\/\.well-known\/apgateway\/(?=[dD][iI][dD](?::|%3[aA]))/;
|
|
244
287
|
const LOCATION_HINT_PARAMETERS = /* @__PURE__ */ new Set(["@gateway", "gateways"]);
|
|
245
288
|
/**
|
|
246
289
|
* Converts an [FEP-ef61] compatible identifier into a portable ActivityPub
|
|
@@ -276,8 +319,9 @@ const LOCATION_HINT_PARAMETERS = /* @__PURE__ */ new Set(["@gateway", "gateways"
|
|
|
276
319
|
* malformed, e.g., it has an invalid DID, no object path,
|
|
277
320
|
* invalid percent-encoding, credentials, or location
|
|
278
321
|
* hints (`@gateway` query parameters, or the legacy
|
|
279
|
-
* `gateways` parameter),
|
|
280
|
-
*
|
|
322
|
+
* `gateways` parameter), or its raw string path would
|
|
323
|
+
* change during URL parsing. Already-parsed `URL`
|
|
324
|
+
* arguments cannot reveal segments lost by their parser.
|
|
281
325
|
* @since 2.4.0
|
|
282
326
|
*/
|
|
283
327
|
function fromCompatibleEf61Id(input) {
|
|
@@ -285,18 +329,29 @@ function fromCompatibleEf61Id(input) {
|
|
|
285
329
|
}
|
|
286
330
|
function convertCompatibleEf61Id(input) {
|
|
287
331
|
let url;
|
|
332
|
+
const rawPrefix = typeof input === "string" ? input.match(RAW_COMPATIBLE_ID_PREFIX_PATTERN) : null;
|
|
288
333
|
if (input instanceof URL) url = input;
|
|
289
334
|
else if (typeof input === "string" && URL.canParse(input)) url = new URL(input);
|
|
290
335
|
else return null;
|
|
291
336
|
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
292
|
-
if (
|
|
337
|
+
if (typeof input === "string" && rawPrefix == null) {
|
|
338
|
+
if (url.pathname.startsWith(COMPATIBLE_ID_PATH_PREFIX) && COMPATIBLE_ID_DID_PATTERN.test(url.pathname.slice(23))) throw new TypeError("Invalid FEP-ef61 compatible identifier.");
|
|
339
|
+
}
|
|
340
|
+
if (!url.pathname.startsWith(COMPATIBLE_ID_PATH_PREFIX)) {
|
|
341
|
+
if (rawPrefix != null) throw new TypeError("Invalid FEP-ef61 compatible identifier.");
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
293
344
|
const tail = url.pathname.slice(23);
|
|
294
|
-
if (!COMPATIBLE_ID_DID_PATTERN.test(tail))
|
|
345
|
+
if (!COMPATIBLE_ID_DID_PATTERN.test(tail)) {
|
|
346
|
+
if (rawPrefix != null) throw new TypeError("Invalid FEP-ef61 compatible identifier.");
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
295
349
|
if (url.username !== "" || url.password !== "") throw new TypeError("Invalid FEP-ef61 compatible identifier: credentials are not allowed.");
|
|
296
350
|
const iri = "ap+ef61://" + url.href.slice(url.origin.length + 23);
|
|
297
351
|
try {
|
|
298
352
|
const parsed = parsePortableIri(iri);
|
|
299
353
|
if (parsed == null) throw new TypeError("Not a portable IRI.");
|
|
354
|
+
if (typeof input === "string" && rawPrefix != null && canonicalizePortableUri("ap://" + input.slice(rawPrefix[0].length)) !== canonicalizePortableUri(iri)) throw new TypeError("URL parsing changed the portable identifier.");
|
|
300
355
|
canonicalizePortableUri(iri);
|
|
301
356
|
if ((url.search === "" ? [] : normalizePortableComponent(url.search.slice(1)).split("&")).some(isLocationHint)) throw new TypeError("Location hints are not allowed.");
|
|
302
357
|
return {
|
|
@@ -336,7 +391,8 @@ function convertCompatibleEf61Id(input) {
|
|
|
336
391
|
* @returns The compatible identifier.
|
|
337
392
|
* @throws {TypeError} If the portable ID is not a valid `ap:` or `ap+ef61:`
|
|
338
393
|
* URI, if its path has `.` or `..` segments (which
|
|
339
|
-
* HTTP(S) URLs cannot represent
|
|
394
|
+
* HTTP(S) URLs cannot represent without changing the
|
|
395
|
+
* identified object), or if the gateway is
|
|
340
396
|
* not an HTTP(S) origin with no credentials, path, query,
|
|
341
397
|
* or fragment.
|
|
342
398
|
* @since 2.4.0
|
|
@@ -386,6 +442,166 @@ function isLocationHint(pair) {
|
|
|
386
442
|
}
|
|
387
443
|
}
|
|
388
444
|
/**
|
|
445
|
+
* The name of the FEP-ef61 location hint query parameter.
|
|
446
|
+
* @internal
|
|
447
|
+
*/
|
|
448
|
+
const GATEWAY_HINT_PARAMETER = "@gateway";
|
|
449
|
+
/**
|
|
450
|
+
* Parses an FEP-ef61 gateway, which has to be an HTTP(S) origin with no
|
|
451
|
+
* credentials, path, query, or fragment.
|
|
452
|
+
* @returns The gateway, or `null` if it is not a valid gateway.
|
|
453
|
+
* @internal
|
|
454
|
+
*/
|
|
455
|
+
function parseGatewayOrigin(gateway) {
|
|
456
|
+
let url;
|
|
457
|
+
if (gateway instanceof URL) url = new URL(gateway.href);
|
|
458
|
+
else if (typeof gateway === "string" && URL.canParse(gateway)) url = new URL(gateway);
|
|
459
|
+
else return null;
|
|
460
|
+
return isGatewayUrl(url) ? url : null;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Returns a copy of an [FEP-ef61] portable ActivityPub URI with `@gateway`
|
|
464
|
+
* location hints for the given gateways, which tell consumers where they can
|
|
465
|
+
* retrieve the object. Put hints on *references* to portable actors, e.g.,
|
|
466
|
+
* in `actor`, `attributedTo`, `to`, or `cc`, when constructing an object, as
|
|
467
|
+
* FEP-ef61 recommends:
|
|
468
|
+
*
|
|
469
|
+
* ~~~~ typescript
|
|
470
|
+
* withGatewayHints("ap://did:key:z6Mk.../actor", [
|
|
471
|
+
* "https://server1.example",
|
|
472
|
+
* "https://server2.example",
|
|
473
|
+
* ]);
|
|
474
|
+
* // ap+ef61://did:key:z6Mk.../actor?@gateway=https%3A%2F%2Fserver1.example&@gateway=https%3A%2F%2Fserver2.example
|
|
475
|
+
* ~~~~
|
|
476
|
+
*
|
|
477
|
+
* Do not put hints on an object's own `id`. Hints do not change the
|
|
478
|
+
* identity of a portable URI, since FEP-ef61 drops the query when comparing
|
|
479
|
+
* portable URIs, but implementations that do not canonicalize portable URIs
|
|
480
|
+
* would take a hinted ID for another object. Add hints before signing the
|
|
481
|
+
* object, since its Object Integrity Proof covers its references too.
|
|
482
|
+
*
|
|
483
|
+
* The hints that the URI already has, including the legacy `gateways`
|
|
484
|
+
* parameter, are replaced. Each gateway becomes a `@gateway` query
|
|
485
|
+
* parameter whose value is its URI-encoded origin, e.g.,
|
|
486
|
+
* `@gateway=https%3A%2F%2Fserver1.example`, in the given order after the
|
|
487
|
+
* other query parameters. Duplicate gateways are dropped, and an empty list
|
|
488
|
+
* removes the hints as {@link withoutGatewayHints} does. The other query
|
|
489
|
+
* parameters, their order, and the fragment are kept, but percent-encoding
|
|
490
|
+
* is normalized the same way as {@link canonicalizePortableUri} does it.
|
|
491
|
+
*
|
|
492
|
+
* Fedify follows at most five hints when dereferencing a portable URI
|
|
493
|
+
* (three for the key ID of an HTTP Signature), so list the preferred
|
|
494
|
+
* gateways first; there is no limit on the number of hints added here.
|
|
495
|
+
*
|
|
496
|
+
* [FEP-ef61]: https://w3id.org/fep/ef61
|
|
497
|
+
*
|
|
498
|
+
* @param portableId The `ap:` or `ap+ef61:` URI. Pass the raw string rather
|
|
499
|
+
* than a `URL` if its path may have `.` or `..` segments,
|
|
500
|
+
* because the `URL` class resolves them.
|
|
501
|
+
* @param gateways The gateways, e.g., the `gateways` of the actor that the
|
|
502
|
+
* URI refers to. Each has to be an HTTP(S) origin with no
|
|
503
|
+
* credentials, path, query, or fragment.
|
|
504
|
+
* @returns The portable URI with the hints, in the same internal `URL` form
|
|
505
|
+
* as {@link parseIri} returns. Use {@link formatIri} to get its
|
|
506
|
+
* canonical string.
|
|
507
|
+
* @throws {TypeError} If the portable ID is not a valid `ap:` or `ap+ef61:`
|
|
508
|
+
* URI, e.g., it is a compatible identifier, which must
|
|
509
|
+
* not have location hints; if its path has `.` or `..`
|
|
510
|
+
* segments, which the `URL` class cannot represent; or
|
|
511
|
+
* if a gateway is invalid.
|
|
512
|
+
* @since 2.4.0
|
|
513
|
+
*/
|
|
514
|
+
function withGatewayHints(portableId, gateways) {
|
|
515
|
+
const parts = splitPortableIri(portableId);
|
|
516
|
+
if (typeof gateways === "string") throw new TypeError("The gateways must be an iterable of gateways, not a string.");
|
|
517
|
+
const hints = [];
|
|
518
|
+
const seen = /* @__PURE__ */ new Set();
|
|
519
|
+
for (const gateway of gateways) {
|
|
520
|
+
const url = parseGatewayOrigin(gateway);
|
|
521
|
+
if (url == null) throw new TypeError("FEP-ef61 gateways must be HTTP(S) origins with no credentials, path, query, or fragment: " + String(gateway));
|
|
522
|
+
if (seen.has(url.href)) continue;
|
|
523
|
+
seen.add(url.href);
|
|
524
|
+
hints.push(url);
|
|
525
|
+
}
|
|
526
|
+
return replaceGatewayHints(parts, hints);
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Returns a copy of an [FEP-ef61] portable ActivityPub URI without its
|
|
530
|
+
* location hints, i.e., `@gateway` query parameters and the legacy
|
|
531
|
+
* `gateways` parameter. The other query parameters, their order, and the
|
|
532
|
+
* fragment are kept, but percent-encoding is normalized the same way as
|
|
533
|
+
* {@link canonicalizePortableUri} does it.
|
|
534
|
+
*
|
|
535
|
+
* [FEP-ef61]: https://w3id.org/fep/ef61
|
|
536
|
+
*
|
|
537
|
+
* @param portableId The `ap:` or `ap+ef61:` URI. Pass the raw string rather
|
|
538
|
+
* than a `URL` if its path may have `.` or `..` segments,
|
|
539
|
+
* because the `URL` class resolves them.
|
|
540
|
+
* @returns The portable URI without the hints, in the same internal `URL`
|
|
541
|
+
* form as {@link parseIri} returns.
|
|
542
|
+
* @throws {TypeError} If the portable ID is not a valid `ap:` or `ap+ef61:`
|
|
543
|
+
* URI, or if its path has `.` or `..` segments, which
|
|
544
|
+
* the `URL` class cannot represent.
|
|
545
|
+
* @since 2.4.0
|
|
546
|
+
*/
|
|
547
|
+
function withoutGatewayHints(portableId) {
|
|
548
|
+
return replaceGatewayHints(splitPortableIri(portableId), []);
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Gets the gateways in the `@gateway` location hints of an [FEP-ef61]
|
|
552
|
+
* portable ActivityPub URI, in order. Hints that are not valid gateways,
|
|
553
|
+
* i.e., HTTP(S) origins with no credentials, path, query, or fragment, are
|
|
554
|
+
* skipped, and so are duplicates. The legacy `gateways` parameter is not
|
|
555
|
+
* read.
|
|
556
|
+
*
|
|
557
|
+
* Unlike Fedify's dereferencing, which follows at most five hints, this
|
|
558
|
+
* returns all of them.
|
|
559
|
+
*
|
|
560
|
+
* [FEP-ef61]: https://w3id.org/fep/ef61
|
|
561
|
+
*
|
|
562
|
+
* @param portableId The `ap:` or `ap+ef61:` URI.
|
|
563
|
+
* @returns The gateways, e.g., `https://server1.example/`.
|
|
564
|
+
* @throws {TypeError} If the portable ID is not a valid `ap:` or `ap+ef61:`
|
|
565
|
+
* URI.
|
|
566
|
+
* @since 2.4.0
|
|
567
|
+
*/
|
|
568
|
+
function getGatewayHints(portableId) {
|
|
569
|
+
const { query } = splitPortableIri(portableId);
|
|
570
|
+
return query == null ? [] : parseGatewayHints(query);
|
|
571
|
+
}
|
|
572
|
+
function splitPortableIri(portableId) {
|
|
573
|
+
const raw = getRawPortableIri(portableId);
|
|
574
|
+
const match = raw.match(PORTABLE_IRI_PATTERN);
|
|
575
|
+
const parsed = parsePortableIri(raw);
|
|
576
|
+
if (match == null || parsed == null) throw new TypeError("Invalid portable ActivityPub IRI.");
|
|
577
|
+
return {
|
|
578
|
+
raw,
|
|
579
|
+
parsed,
|
|
580
|
+
path: normalizePortableComponent(match[3]),
|
|
581
|
+
query: match[4] == null ? null : normalizePortableComponent(match[4].slice(1)),
|
|
582
|
+
fragment: match[5] == null ? "" : normalizePortableComponent(match[5])
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
function parseGatewayHints(query) {
|
|
586
|
+
const hints = [];
|
|
587
|
+
const seen = /* @__PURE__ */ new Set();
|
|
588
|
+
for (const hint of new URLSearchParams(`?${query}`).getAll(GATEWAY_HINT_PARAMETER)) {
|
|
589
|
+
const url = parseGatewayOrigin(hint);
|
|
590
|
+
if (url == null || seen.has(url.href)) continue;
|
|
591
|
+
seen.add(url.href);
|
|
592
|
+
hints.push(url);
|
|
593
|
+
}
|
|
594
|
+
return hints;
|
|
595
|
+
}
|
|
596
|
+
function replaceGatewayHints(parts, hints) {
|
|
597
|
+
const pairs = parts.query == null ? [] : parts.query.split("&").filter((pair) => pair !== "" && !isLocationHint(pair));
|
|
598
|
+
for (const hint of hints) pairs.push(`${GATEWAY_HINT_PARAMETER}=${encodeURIComponent(hint.origin)}`);
|
|
599
|
+
const query = pairs.length < 1 ? "" : `?${pairs.join("&")}`;
|
|
600
|
+
const result = parsePortableIri(`ap+ef61://${parts.parsed.host}${parts.path}${query}${parts.fragment}`);
|
|
601
|
+
if (result == null || canonicalizePortableUri(result.href) !== canonicalizePortableUri(parts.raw) || parseGatewayHints(result.search.slice(1)).map((url) => url.href).join(" ") !== hints.map((url) => url.href).join(" ")) throw new TypeError("The portable ActivityPub IRI cannot be represented as a URL without changing the object it refers to.");
|
|
602
|
+
return result;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
389
605
|
* Validates a URL to prevent SSRF attacks.
|
|
390
606
|
*/
|
|
391
607
|
async function validatePublicUrl(url) {
|
|
@@ -581,6 +797,12 @@ function matchesIPv6Prefix(address, prefixWords, prefixLength) {
|
|
|
581
797
|
return true;
|
|
582
798
|
}
|
|
583
799
|
//#endregion
|
|
800
|
+
Object.defineProperty(exports, "GATEWAY_HINT_PARAMETER", {
|
|
801
|
+
enumerable: true,
|
|
802
|
+
get: function() {
|
|
803
|
+
return GATEWAY_HINT_PARAMETER;
|
|
804
|
+
}
|
|
805
|
+
});
|
|
584
806
|
Object.defineProperty(exports, "UrlError", {
|
|
585
807
|
enumerable: true,
|
|
586
808
|
get: function() {
|
|
@@ -623,6 +845,12 @@ Object.defineProperty(exports, "getFe34Origin", {
|
|
|
623
845
|
return getFe34Origin;
|
|
624
846
|
}
|
|
625
847
|
});
|
|
848
|
+
Object.defineProperty(exports, "getGatewayHints", {
|
|
849
|
+
enumerable: true,
|
|
850
|
+
get: function() {
|
|
851
|
+
return getGatewayHints;
|
|
852
|
+
}
|
|
853
|
+
});
|
|
626
854
|
Object.defineProperty(exports, "haveSameFe34Origin", {
|
|
627
855
|
enumerable: true,
|
|
628
856
|
get: function() {
|
|
@@ -653,6 +881,12 @@ Object.defineProperty(exports, "isValidPublicIPv6Address", {
|
|
|
653
881
|
return isValidPublicIPv6Address;
|
|
654
882
|
}
|
|
655
883
|
});
|
|
884
|
+
Object.defineProperty(exports, "parseGatewayOrigin", {
|
|
885
|
+
enumerable: true,
|
|
886
|
+
get: function() {
|
|
887
|
+
return parseGatewayOrigin;
|
|
888
|
+
}
|
|
889
|
+
});
|
|
656
890
|
Object.defineProperty(exports, "parseGatewayUrl", {
|
|
657
891
|
enumerable: true,
|
|
658
892
|
get: function() {
|
|
@@ -683,3 +917,15 @@ Object.defineProperty(exports, "validatePublicUrl", {
|
|
|
683
917
|
return validatePublicUrl;
|
|
684
918
|
}
|
|
685
919
|
});
|
|
920
|
+
Object.defineProperty(exports, "withGatewayHints", {
|
|
921
|
+
enumerable: true,
|
|
922
|
+
get: function() {
|
|
923
|
+
return withGatewayHints;
|
|
924
|
+
}
|
|
925
|
+
});
|
|
926
|
+
Object.defineProperty(exports, "withoutGatewayHints", {
|
|
927
|
+
enumerable: true,
|
|
928
|
+
get: function() {
|
|
929
|
+
return withoutGatewayHints;
|
|
930
|
+
}
|
|
931
|
+
});
|