@helia/verified-fetch 2.6.3 → 2.6.4

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.
@@ -1,6 +1,9 @@
1
1
  import type { Logger } from '@libp2p/interface';
2
2
  import type { UnixFSEntry } from 'ipfs-unixfs-exporter';
3
3
  export interface DirIndexHtmlOptions {
4
+ /**
5
+ * The URL of the requested resource
6
+ */
4
7
  gatewayURL: string;
5
8
  dnsLink?: boolean;
6
9
  log: Logger;
@@ -1 +1 @@
1
- {"version":3,"file":"dir-index-html.d.ts","sourceRoot":"","sources":["../../../src/utils/dir-index-html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAwCvD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;CACZ;AAyED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,QAAS,WAAW,SAAS,WAAW,EAAE,gCAAgC,mBAAmB,KAAG,MAwFxH,CAAA"}
1
+ {"version":3,"file":"dir-index-html.d.ts","sourceRoot":"","sources":["../../../src/utils/dir-index-html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAyCvD,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;CACZ;AAoGD;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,QAAS,WAAW,SAAS,WAAW,EAAE,gCAAgC,mBAAmB,KAAG,MAyFxH,CAAA"}
@@ -5,29 +5,51 @@ function iconFromExt(name) {
5
5
  return 'ipfs-_blank';
6
6
  }
7
7
  /**
8
- * If they click on the short hash, it should link to the host + /ipfs/ + hash + ?filename={filename}
8
+ * If they click on the short hash, it should link to the host-without-subdomain + /ipfs/ + hash + ?filename={filename}
9
9
  */
10
10
  function itemShortHashCell(item, dirData) {
11
- let href;
12
- try {
13
- const currentUrl = new URL(dirData.globalData.gatewayURL);
14
- const currentHost = dirData.globalData.dnsLink ? 'inbrowser.dev' : currentUrl.host;
15
- let newHost = currentHost;
16
- if (currentHost.includes('.ipfs.')) {
17
- newHost = currentHost.split('.ipfs.')[1];
18
- }
19
- else if (currentHost.includes('.ipns.')) {
20
- newHost = currentHost.split('.ipns.')[1];
11
+ const host = dirData.globalData.gatewayURLWithoutSubdomain.host;
12
+ const protocol = dirData.globalData.gatewayURLWithoutSubdomain.protocol;
13
+ return `<a class="ipfs-hash" translate="no" href="${protocol}//${host}/ipfs/${item.hash}?filename=${item.name}">${item.shortHash}</a>`;
14
+ }
15
+ /**
16
+ * Returns a new host with the subdomain removed if it includes "ipfs" or "ipns".
17
+ *
18
+ * @example
19
+ * subdomain.ipfs.dweb.link -> dweb.link
20
+ * abc.ipns.localhost -> localhost
21
+ * bafyfoo.ipfs.localhost:3441 -> localhost:3441
22
+ * bafyfoo.ipfs.foo.localhost:3441 -> foo.localhost:3441
23
+ */
24
+ function removeIpfsOrIpnsSubdomain(host) {
25
+ const segments = host.split('.');
26
+ const keepSegments = [];
27
+ // Walk from the right to the left
28
+ for (let i = segments.length - 1; i >= 0; i--) {
29
+ const seg = segments[i];
30
+ // If we hit "ipfs" or "ipns", stop (ignore everything to the left)
31
+ if (seg === 'ipfs' || seg === 'ipns') {
32
+ break;
21
33
  }
22
- href = `${currentUrl.protocol}//${newHost}/ipfs/${item.hash}?filename=${item.name}`;
23
- // return `<a class="ipfs-hash" translate="no" href="${href}">${item.shortHash}</a>`
34
+ keepSegments.push(seg);
35
+ }
36
+ // Reverse because we collected from right to left
37
+ keepSegments.reverse();
38
+ // If keepSegments is empty, it means "ipfs" or "ipns" was at the TLD level
39
+ // but typically that means the next domain is empty; just return empty string
40
+ return keepSegments.join('.');
41
+ }
42
+ function getGatewayURLWithoutSubdomain(gatewayURL) {
43
+ let currentUrl;
44
+ try {
45
+ currentUrl = new URL(gatewayURL);
24
46
  }
25
47
  catch {
26
- // resource is not a URL.
27
- // TODO: handle unknown gatewayURLs in a more standardized way? if someone calls verified fetch and gatewayURL is not a valid URL, are ipfs:// links okay, or should we error in this plugin?
28
- href = `ipfs://${item.hash}`;
48
+ // If the gatewayURL is invalid (ipfs:// or ipns:// or just a CID), use inbrowser.link as a fallback
49
+ currentUrl = new URL('https://inbrowser.link');
29
50
  }
30
- return `<a class="ipfs-hash" translate="no" href="${href}">${item.shortHash}</a>`;
51
+ currentUrl.host = removeIpfsOrIpnsSubdomain(currentUrl.host);
52
+ return currentUrl;
31
53
  }
32
54
  function dirListingTitle(dirData) {
33
55
  if (dirData.path != null) {
@@ -74,6 +96,7 @@ export const dirIndexHtml = (dir, items, { gatewayURL, dnsLink, log }) => {
74
96
  const dirData = {
75
97
  globalData: {
76
98
  gatewayURL,
99
+ gatewayURLWithoutSubdomain: getGatewayURLWithoutSubdomain(gatewayURL),
77
100
  dnsLink: dnsLink ?? false
78
101
  },
79
102
  listing: items.map((item) => {
@@ -1 +1 @@
1
- {"version":3,"file":"dir-index-html.js","sourceRoot":"","sources":["../../../src/utils/dir-index-html.ts"],"names":[],"mappings":"AA+CA,yHAAyH;AACzH,SAAS,WAAW,CAAE,IAAY;IAChC,sBAAsB;IACtB,4EAA4E;IAC5E,OAAO,aAAa,CAAA;AACtB,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAE,IAAmB,EAAE,OAA8B;IAC7E,IAAI,IAAY,CAAA;IAChB,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAA;QACzD,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAA;QAClF,IAAI,OAAO,GAAG,WAAW,CAAA;QACzB,IAAI,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnC,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;QAC1C,CAAC;aAAM,IAAI,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1C,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;QAC1C,CAAC;QAED,IAAI,GAAG,GAAG,UAAU,CAAC,QAAQ,KAAK,OAAO,SAAS,IAAI,CAAC,IAAI,aAAa,IAAI,CAAC,IAAI,EAAE,CAAA;QAEnF,oFAAoF;IACtF,CAAC;IAAC,MAAM,CAAC;QACP,yBAAyB;QACzB,6LAA6L;QAC7L,IAAI,GAAG,UAAU,IAAI,CAAC,IAAI,EAAE,CAAA;IAC9B,CAAC;IACD,OAAO,6CAA6C,IAAI,KAAK,IAAI,CAAC,SAAS,MAAM,CAAA;AACnF,CAAC;AAED,SAAS,eAAe,CAAE,OAA8B;IACtD,IAAI,OAAO,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,EAAE,CAAA;QAC/D,OAAO,qBAAqB,IAAI,KAAK,OAAO,CAAC,IAAI,MAAM,CAAA;IACzD,CAAC;IACD,OAAO,YAAY,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,CAAA;AACnD,CAAC;AAED,SAAS,oBAAoB,CAAE,OAA8B;IAC3D,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;oBACnB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;;;iBAGzB,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI;;;QAGhC,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC;;gFAEwC,IAAI,CAAC,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC5G,CAAC;AAED,SAAS,WAAW,CAAE,IAAiB;IACrC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAE1C,OAAO,aAAa,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,IAAI,CAAA;AACzC,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CAAE,IAAY;IACjC,OAAO,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AAC7E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAgB,EAAE,KAAoB,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAuB,EAAU,EAAE;IAChI,GAAG,CAAC,+BAA+B,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;IAE9C,MAAM,OAAO,GAA0B;QACrC,UAAU,EAAE;YACV,UAAU;YACV,OAAO,EAAE,OAAO,IAAI,KAAK;SAC1B;QACD,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAC1B,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;gBAC1B,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC;gBACvB,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE;gBACzB,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;aACrB,CAAA;QAC3B,CAAC,CAAC;QACF,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE;QACzB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,WAAW,EAAE,EAAE;QACf,QAAQ,EAAE,EAAE;QACZ,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE;KACzB,CAAA;IAED,OAAO;;;;;;;aAOI,OAAO,CAAC,IAAI;aACZ,KAAK;;;;;;;MAOZ,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;;;;;;;;;;;;;;oBAclB,eAAe,CAAC,OAAO,CAAC;YAChC,OAAO,CAAC,IAAI,IAAI,IAAI;QACpB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;kBACI,OAAO,CAAC,IAAI;qBAEpB;;UAEA,OAAO,CAAC,IAAI,IAAI,IAAI;QACpB,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;oFACwE,OAAO,CAAC,IAAI;mBAExF;;;;;;;;;;;;;;;YAeI,oBAAoB,CAAC,OAAO,CAAC;;;;;QAKjC,CAAA;AACR,CAAC,CAAA;AAED,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAiQR,CAAA"}
1
+ {"version":3,"file":"dir-index-html.js","sourceRoot":"","sources":["../../../src/utils/dir-index-html.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helia/verified-fetch",
3
- "version": "2.6.3",
3
+ "version": "2.6.4",
4
4
  "description": "A fetch-like API for obtaining verified & trustless IPFS content on the web",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "homepage": "https://github.com/ipfs/helia-verified-fetch/tree/main/packages/verified-fetch#readme",
@@ -11,6 +11,7 @@ import type { UnixFSEntry } from 'ipfs-unixfs-exporter'
11
11
  interface GlobalData {
12
12
  // Menu []MenuItem
13
13
  gatewayURL: string
14
+ gatewayURLWithoutSubdomain: URL
14
15
  dnsLink: boolean
15
16
  // root: UnixFSEntry
16
17
  }
@@ -40,6 +41,9 @@ interface Breadcrumb {
40
41
  }
41
42
 
42
43
  export interface DirIndexHtmlOptions {
44
+ /**
45
+ * The URL of the requested resource
46
+ */
43
47
  gatewayURL: string
44
48
  dnsLink?: boolean
45
49
  log: Logger
@@ -53,29 +57,56 @@ function iconFromExt (name: string): string {
53
57
  }
54
58
 
55
59
  /**
56
- * If they click on the short hash, it should link to the host + /ipfs/ + hash + ?filename={filename}
60
+ * If they click on the short hash, it should link to the host-without-subdomain + /ipfs/ + hash + ?filename={filename}
57
61
  */
58
62
  function itemShortHashCell (item: DirectoryItem, dirData: DirectoryTemplateData): string {
59
- let href: string
60
- try {
61
- const currentUrl = new URL(dirData.globalData.gatewayURL)
62
- const currentHost = dirData.globalData.dnsLink ? 'inbrowser.dev' : currentUrl.host
63
- let newHost = currentHost
64
- if (currentHost.includes('.ipfs.')) {
65
- newHost = currentHost.split('.ipfs.')[1]
66
- } else if (currentHost.includes('.ipns.')) {
67
- newHost = currentHost.split('.ipns.')[1]
68
- }
63
+ const host = dirData.globalData.gatewayURLWithoutSubdomain.host
64
+ const protocol = dirData.globalData.gatewayURLWithoutSubdomain.protocol
65
+
66
+ return `<a class="ipfs-hash" translate="no" href="${protocol}//${host}/ipfs/${item.hash}?filename=${item.name}">${item.shortHash}</a>`
67
+ }
68
+
69
+ /**
70
+ * Returns a new host with the subdomain removed if it includes "ipfs" or "ipns".
71
+ *
72
+ * @example
73
+ * subdomain.ipfs.dweb.link -> dweb.link
74
+ * abc.ipns.localhost -> localhost
75
+ * bafyfoo.ipfs.localhost:3441 -> localhost:3441
76
+ * bafyfoo.ipfs.foo.localhost:3441 -> foo.localhost:3441
77
+ */
78
+ function removeIpfsOrIpnsSubdomain (host: string): string {
79
+ const segments = host.split('.')
80
+ const keepSegments: string[] = []
81
+
82
+ // Walk from the right to the left
83
+ for (let i = segments.length - 1; i >= 0; i--) {
84
+ const seg = segments[i]
85
+ // If we hit "ipfs" or "ipns", stop (ignore everything to the left)
86
+ if (seg === 'ipfs' || seg === 'ipns') {
87
+ break
88
+ }
89
+ keepSegments.push(seg)
90
+ }
69
91
 
70
- href = `${currentUrl.protocol}//${newHost}/ipfs/${item.hash}?filename=${item.name}`
92
+ // Reverse because we collected from right to left
93
+ keepSegments.reverse()
71
94
 
72
- // return `<a class="ipfs-hash" translate="no" href="${href}">${item.shortHash}</a>`
95
+ // If keepSegments is empty, it means "ipfs" or "ipns" was at the TLD level
96
+ // but typically that means the next domain is empty; just return empty string
97
+ return keepSegments.join('.')
98
+ }
99
+
100
+ function getGatewayURLWithoutSubdomain (gatewayURL: string): URL {
101
+ let currentUrl: URL
102
+ try {
103
+ currentUrl = new URL(gatewayURL)
73
104
  } catch {
74
- // resource is not a URL.
75
- // TODO: handle unknown gatewayURLs in a more standardized way? if someone calls verified fetch and gatewayURL is not a valid URL, are ipfs:// links okay, or should we error in this plugin?
76
- href = `ipfs://${item.hash}`
105
+ // If the gatewayURL is invalid (ipfs:// or ipns:// or just a CID), use inbrowser.link as a fallback
106
+ currentUrl = new URL('https://inbrowser.link')
77
107
  }
78
- return `<a class="ipfs-hash" translate="no" href="${href}">${item.shortHash}</a>`
108
+ currentUrl.host = removeIpfsOrIpnsSubdomain(currentUrl.host)
109
+ return currentUrl
79
110
  }
80
111
 
81
112
  function dirListingTitle (dirData: DirectoryTemplateData): string {
@@ -129,6 +160,7 @@ export const dirIndexHtml = (dir: UnixFSEntry, items: UnixFSEntry[], { gatewayUR
129
160
  const dirData: DirectoryTemplateData = {
130
161
  globalData: {
131
162
  gatewayURL,
163
+ gatewayURLWithoutSubdomain: getGatewayURLWithoutSubdomain(gatewayURL),
132
164
  dnsLink: dnsLink ?? false
133
165
  },
134
166
  listing: items.map((item) => {