@helia/verified-fetch 2.3.1 → 2.5.0

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.
Files changed (119) hide show
  1. package/README.md +200 -0
  2. package/dist/index.min.js +357 -35
  3. package/dist/src/index.d.ts +220 -0
  4. package/dist/src/index.d.ts.map +1 -1
  5. package/dist/src/index.js +200 -0
  6. package/dist/src/index.js.map +1 -1
  7. package/dist/src/plugins/errors.d.ts +25 -0
  8. package/dist/src/plugins/errors.d.ts.map +1 -0
  9. package/dist/src/plugins/errors.js +33 -0
  10. package/dist/src/plugins/errors.js.map +1 -0
  11. package/dist/src/plugins/index.d.ts +8 -0
  12. package/dist/src/plugins/index.d.ts.map +1 -0
  13. package/dist/src/plugins/index.js +7 -0
  14. package/dist/src/plugins/index.js.map +1 -0
  15. package/dist/src/plugins/plugin-base.d.ts +19 -0
  16. package/dist/src/plugins/plugin-base.d.ts.map +1 -0
  17. package/dist/src/plugins/plugin-base.js +26 -0
  18. package/dist/src/plugins/plugin-base.js.map +1 -0
  19. package/dist/src/plugins/plugin-handle-car.d.ts +11 -0
  20. package/dist/src/plugins/plugin-handle-car.d.ts.map +1 -0
  21. package/dist/src/plugins/plugin-handle-car.js +28 -0
  22. package/dist/src/plugins/plugin-handle-car.js.map +1 -0
  23. package/dist/src/plugins/plugin-handle-dag-cbor.d.ts +11 -0
  24. package/dist/src/plugins/plugin-handle-dag-cbor.d.ts.map +1 -0
  25. package/dist/src/plugins/plugin-handle-dag-cbor.js +73 -0
  26. package/dist/src/plugins/plugin-handle-dag-cbor.js.map +1 -0
  27. package/dist/src/plugins/plugin-handle-dag-pb.d.ts +15 -0
  28. package/dist/src/plugins/plugin-handle-dag-pb.d.ts.map +1 -0
  29. package/dist/src/plugins/plugin-handle-dag-pb.js +152 -0
  30. package/dist/src/plugins/plugin-handle-dag-pb.js.map +1 -0
  31. package/dist/src/plugins/plugin-handle-dag-walk.d.ts +16 -0
  32. package/dist/src/plugins/plugin-handle-dag-walk.d.ts.map +1 -0
  33. package/dist/src/plugins/plugin-handle-dag-walk.js +45 -0
  34. package/dist/src/plugins/plugin-handle-dag-walk.js.map +1 -0
  35. package/dist/src/plugins/plugin-handle-dir-index-html.d.ts +9 -0
  36. package/dist/src/plugins/plugin-handle-dir-index-html.d.ts.map +1 -0
  37. package/dist/src/plugins/plugin-handle-dir-index-html.js +37 -0
  38. package/dist/src/plugins/plugin-handle-dir-index-html.js.map +1 -0
  39. package/dist/src/plugins/plugin-handle-ipns-record.d.ts +12 -0
  40. package/dist/src/plugins/plugin-handle-ipns-record.d.ts.map +1 -0
  41. package/dist/src/plugins/plugin-handle-ipns-record.js +62 -0
  42. package/dist/src/plugins/plugin-handle-ipns-record.js.map +1 -0
  43. package/dist/src/plugins/plugin-handle-json.d.ts +11 -0
  44. package/dist/src/plugins/plugin-handle-json.d.ts.map +1 -0
  45. package/dist/src/plugins/plugin-handle-json.js +51 -0
  46. package/dist/src/plugins/plugin-handle-json.js.map +1 -0
  47. package/dist/src/plugins/plugin-handle-raw.d.ts +8 -0
  48. package/dist/src/plugins/plugin-handle-raw.d.ts.map +1 -0
  49. package/dist/src/plugins/plugin-handle-raw.js +80 -0
  50. package/dist/src/plugins/plugin-handle-raw.js.map +1 -0
  51. package/dist/src/plugins/plugin-handle-tar.d.ts +12 -0
  52. package/dist/src/plugins/plugin-handle-tar.d.ts.map +1 -0
  53. package/dist/src/plugins/plugin-handle-tar.js +36 -0
  54. package/dist/src/plugins/plugin-handle-tar.js.map +1 -0
  55. package/dist/src/plugins/plugins.d.ts +5 -0
  56. package/dist/src/plugins/plugins.d.ts.map +1 -0
  57. package/dist/src/plugins/plugins.js +5 -0
  58. package/dist/src/plugins/plugins.js.map +1 -0
  59. package/dist/src/plugins/types.d.ts +68 -0
  60. package/dist/src/plugins/types.d.ts.map +1 -0
  61. package/dist/src/plugins/types.js +2 -0
  62. package/dist/src/plugins/types.js.map +1 -0
  63. package/dist/src/types.d.ts +0 -23
  64. package/dist/src/types.d.ts.map +1 -1
  65. package/dist/src/types.js +1 -2
  66. package/dist/src/types.js.map +1 -1
  67. package/dist/src/utils/dir-index-html.d.ts +16 -0
  68. package/dist/src/utils/dir-index-html.d.ts.map +1 -0
  69. package/dist/src/utils/dir-index-html.js +387 -0
  70. package/dist/src/utils/dir-index-html.js.map +1 -0
  71. package/dist/src/utils/get-e-tag.d.ts +1 -1
  72. package/dist/src/utils/get-e-tag.d.ts.map +1 -1
  73. package/dist/src/utils/get-e-tag.js +18 -3
  74. package/dist/src/utils/get-e-tag.js.map +1 -1
  75. package/dist/src/utils/parse-resource.d.ts +2 -1
  76. package/dist/src/utils/parse-resource.d.ts.map +1 -1
  77. package/dist/src/utils/parse-resource.js +4 -3
  78. package/dist/src/utils/parse-resource.js.map +1 -1
  79. package/dist/src/utils/parse-url-string.d.ts +8 -3
  80. package/dist/src/utils/parse-url-string.d.ts.map +1 -1
  81. package/dist/src/utils/parse-url-string.js +30 -4
  82. package/dist/src/utils/parse-url-string.js.map +1 -1
  83. package/dist/src/utils/server-timing.d.ts +13 -0
  84. package/dist/src/utils/server-timing.d.ts.map +1 -0
  85. package/dist/src/utils/server-timing.js +19 -0
  86. package/dist/src/utils/server-timing.js.map +1 -0
  87. package/dist/src/utils/walk-path.d.ts +3 -2
  88. package/dist/src/utils/walk-path.d.ts.map +1 -1
  89. package/dist/src/utils/walk-path.js +1 -1
  90. package/dist/src/utils/walk-path.js.map +1 -1
  91. package/dist/src/verified-fetch.d.ts +11 -20
  92. package/dist/src/verified-fetch.d.ts.map +1 -1
  93. package/dist/src/verified-fetch.js +174 -367
  94. package/dist/src/verified-fetch.js.map +1 -1
  95. package/dist/typedoc-urls.json +32 -24
  96. package/package.json +6 -2
  97. package/src/index.ts +223 -0
  98. package/src/plugins/errors.ts +37 -0
  99. package/src/plugins/index.ts +8 -0
  100. package/src/plugins/plugin-base.ts +30 -0
  101. package/src/plugins/plugin-handle-car.ts +32 -0
  102. package/src/plugins/plugin-handle-dag-cbor.ts +84 -0
  103. package/src/plugins/plugin-handle-dag-pb.ts +168 -0
  104. package/src/plugins/plugin-handle-dag-walk.ts +53 -0
  105. package/src/plugins/plugin-handle-dir-index-html.ts +44 -0
  106. package/src/plugins/plugin-handle-ipns-record.ts +69 -0
  107. package/src/plugins/plugin-handle-json.ts +57 -0
  108. package/src/plugins/plugin-handle-raw.ts +92 -0
  109. package/src/plugins/plugin-handle-tar.ts +44 -0
  110. package/src/plugins/plugins.ts +4 -0
  111. package/src/plugins/types.ts +73 -0
  112. package/src/types.ts +0 -29
  113. package/src/utils/dir-index-html.ts +445 -0
  114. package/src/utils/get-e-tag.ts +20 -3
  115. package/src/utils/parse-resource.ts +5 -4
  116. package/src/utils/parse-url-string.ts +38 -7
  117. package/src/utils/server-timing.ts +37 -0
  118. package/src/utils/walk-path.ts +3 -3
  119. package/src/verified-fetch.ts +198 -403
@@ -0,0 +1,387 @@
1
+ // see https://github.com/ipfs/boxo/blob/09b0013e1c3e09468009b02dfc9b2b9041199d5d/gateway/assets/templates.go#L19C1-L25C2
2
+ function iconFromExt(name) {
3
+ // not implemented yet
4
+ // TODO: optimize icons: https://github.com/ipfs-shipyard/ipfs-css/issues/71
5
+ return 'ipfs-_blank';
6
+ }
7
+ function itemShortHashCell(item, dirData) {
8
+ const href = dirData.globalData.dnsLink ? `https://inbrowser.dev/ipfs/${item.hash}` : `${dirData.globalData.gatewayURL}/ipfs/${item.hash}?filename=${item.name}`;
9
+ return `<a class="ipfs-hash" translate="no" href="${href}">${item.shortHash}</a>`;
10
+ }
11
+ function dirListingTitle(dirData) {
12
+ if (dirData.path != null) {
13
+ const href = `${dirData.globalData.gatewayURL}/${dirData.path}`;
14
+ return `Index of <a href="${href}">${dirData.name}</a>`;
15
+ }
16
+ return `Index of ${dirData.name} ${dirData.path}`;
17
+ }
18
+ function getAllDirListingRows(dirData) {
19
+ return dirData.listing.map((item) => `<div class="type-icon">
20
+ <div class="${iconFromExt(item.name)}">&nbsp;</div>
21
+ </div>
22
+ <div>
23
+ <a href="${item.path}">${item.name}</a>
24
+ </div>
25
+ <div class="nowrap">
26
+ ${itemShortHashCell(item, dirData)}
27
+ </div>
28
+ <div class="nowrap" title="Cumulative size of IPFS DAG (data + metadata)">${item.size}</div>`).join(' ');
29
+ }
30
+ function getItemPath(item) {
31
+ const itemPathParts = item.path.split('/');
32
+ return itemPathParts.pop() ?? item.path;
33
+ }
34
+ /**
35
+ * todo: https://github.com/ipfs/boxo/blob/09b0013e1c3e09468009b02dfc9b2b9041199d5d/gateway/handler_unixfs_dir.go#L200-L208
36
+ *
37
+ * @see https://github.com/ipfs/boxo/blob/09b0013e1c3e09468009b02dfc9b2b9041199d5d/gateway/assets/directory.html
38
+ * @see https://github.com/ipfs/boxo/pull/298
39
+ * @see https://github.com/ipfs/kubo/pull/8555
40
+ */
41
+ export const dirIndexHtml = (dir, items, { gatewayURL, dnsLink, log }) => {
42
+ log('loading directory html for %s', dir.path);
43
+ const dirData = {
44
+ globalData: {
45
+ gatewayURL,
46
+ dnsLink: dnsLink ?? false
47
+ },
48
+ listing: items.map((item) => {
49
+ return {
50
+ size: item.size.toString(),
51
+ name: item.name,
52
+ path: getItemPath(item),
53
+ hash: item.cid.toString(),
54
+ shortHash: item.cid.toString().slice(0, 8)
55
+ };
56
+ }),
57
+ name: dir.name,
58
+ size: dir.size.toString(),
59
+ path: dir.path,
60
+ breadcrumbs: [],
61
+ backLink: '',
62
+ hash: dir.cid.toString()
63
+ };
64
+ return `
65
+ <!DOCTYPE html>
66
+ <!--{{ $root := . }}-->
67
+ <html lang="en">
68
+ <head>
69
+ <meta charset="utf-8" />
70
+ <meta name="description" content="A directory of content-addressed files hosted on IPFS.">
71
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
72
+ <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlo89/56ZQ/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUjDu1lo89/6mhTP+zrVP/nplD/5+aRK8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHNiIS6Wjz3/ubFY/761W/+vp1D/urRZ/8vDZf/GvmH/nplD/1BNIm8AAAAAAAAAAAAAAAAAAAAAAAAAAJaPPf+knEj/vrVb/761W/++tVv/r6dQ/7q0Wf/Lw2X/y8Nl/8vDZf+tpk7/nplD/wAAAAAAAAAAAAAAAJaPPf+2rVX/vrVb/761W/++tVv/vrVb/6+nUP+6tFn/y8Nl/8vDZf/Lw2X/y8Nl/8G6Xv+emUP/AAAAAAAAAACWjz3/vrVb/761W/++tVv/vrVb/761W/+vp1D/urRZ/8vDZf/Lw2X/y8Nl/8vDZf/Lw2X/nplD/wAAAAAAAAAAlo89/761W/++tVv/vrVb/761W/++tVv/r6dQ/7q0Wf/Lw2X/y8Nl/8vDZf/Lw2X/y8Nl/56ZQ/8AAAAAAAAAAJaPPf++tVv/vrVb/761W/++tVv/vbRa/5aPPf+emUP/y8Nl/8vDZf/Lw2X/y8Nl/8vDZf+emUP/AAAAAAAAAACWjz3/vrVb/761W/++tVv/vrVb/5qTQP+inkb/op5G/6KdRv/Lw2X/y8Nl/8vDZf/Lw2X/nplD/wAAAAAAAAAAlo89/761W/++tVv/sqlS/56ZQ//LxWb/0Mlp/9DJaf/Kw2X/oJtE/7+3XP/Lw2X/y8Nl/56ZQ/8AAAAAAAAAAJaPPf+9tFr/mJE+/7GsUv/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+xrFL/nplD/8vDZf+emUP/AAAAAAAAAACWjz3/op5G/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+inkb/nplD/wAAAAAAAAAAAAAAAKKeRv+3slb/0cpq/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+1sFX/op5G/wAAAAAAAAAAAAAAAAAAAAAAAAAAop5GUKKeRv/Nxmf/0cpq/9HKav/Rymr/0cpq/83GZ/+inkb/op5GSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAop5G16KeRv/LxWb/y8Vm/6KeRv+inkaPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAop5G/6KeRtcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/n8AAPgfAADwDwAAwAMAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAwAMAAPAPAAD4HwAA/n8AAA==" />
73
+ <title>${dirData.path}</title>
74
+ <style>${style}</style>
75
+ </head>
76
+ <body>
77
+ <!--
78
+ # Some JSON content for debugging:
79
+
80
+ ## dirData
81
+ ${JSON.stringify(dirData, null, 2)}
82
+ -->
83
+ <header id="header">
84
+ <div class="ipfs-logo">&nbsp;</div>
85
+ <!--
86
+ <nav>
87
+ <a href="https://ipfs.tech" target="_blank" rel="noopener noreferrer">About<span class="dn-mobile"> IPFS</span></a>
88
+ <a href="https://docs.ipfs.tech/install/" target="_blank" rel="noopener noreferrer">Install<span class="dn-mobile"> IPFS</span></a>
89
+ </nav>
90
+ -->
91
+ </header>
92
+ <main id="main">
93
+ <header class="flex flex-wrap">
94
+ <div>
95
+ <strong>${dirListingTitle(dirData)}</strong>
96
+ ${dirData.hash == null
97
+ ? ''
98
+ : `<div class="ipfs-hash" translate="no">
99
+ ${dirData.hash}
100
+ </div>`}
101
+ </div>
102
+ ${dirData.size == null
103
+ ? ''
104
+ : `<div class="nowrap flex-shrink ml-auto">
105
+ <strong title="Cumulative size of IPFS DAG (data + metadata)">&nbsp;${dirData.size}</strong>
106
+ </div>`}
107
+ </header>
108
+ <section>
109
+ <div class="grid dir">
110
+ <!--{{ if .BackLink }}
111
+ <div class="type-icon">
112
+ <div class="ipfs-_blank">&nbsp;</div>
113
+ </div>
114
+ <div>
115
+ <a href="{{.BackLink | urlEscape}}">..</a>
116
+ </div>
117
+ <div></div>
118
+ <div></div>
119
+ </tr>
120
+ {{ end }}-->
121
+ ${getAllDirListingRows(dirData)}
122
+ </div>
123
+ </section>
124
+ </main>
125
+ </body>
126
+ </html>
127
+ `;
128
+ };
129
+ const style = `
130
+
131
+ .ipfs-_blank {
132
+ background-image: url("data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 100'%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='36' y1='1' x2='36' y2='99' gradientTransform='matrix(1 0 0 -1 0 100)'%3E%3Cstop offset='0' stop-color='%23c8d4db'/%3E%3Cstop offset='.139' stop-color='%23d8e1e6'/%3E%3Cstop offset='.359' stop-color='%23ebf0f3'/%3E%3Cstop offset='.617' stop-color='%23f9fafb'/%3E%3Cstop offset='1' stop-color='%23fff'/%3E%3C/linearGradient%3E%3Cpath d='M45 1l27 26.7V99H0V1h45z' fill='url(%23a)'/%3E%3Cpath d='M45 1l27 26.7V99H0V1h45z' fill-opacity='0' stroke='%237191a1' stroke-width='2'/%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='45.068' y1='72.204' x2='58.568' y2='85.705' gradientTransform='matrix(1 0 0 -1 0 100)'%3E%3Cstop offset='0' stop-color='%23fff'/%3E%3Cstop offset='.35' stop-color='%23fafbfb'/%3E%3Cstop offset='.532' stop-color='%23edf1f4'/%3E%3Cstop offset='.675' stop-color='%23dde5e9'/%3E%3Cstop offset='.799' stop-color='%23c7d3da'/%3E%3Cstop offset='.908' stop-color='%23adbdc7'/%3E%3Cstop offset='1' stop-color='%2392a5b0'/%3E%3C/linearGradient%3E%3Cpath d='M45 1l27 26.7H45V1z' fill='url(%23b)'/%3E%3Cpath d='M45 1l27 26.7H45V1z' fill-opacity='0' stroke='%237191a1' stroke-width='2' stroke-linejoin='bevel'/%3E%3C/svg%3E");
133
+ background-repeat: no-repeat;
134
+ background-size: contain
135
+ }
136
+
137
+ :root {
138
+ --sans-serif: "Plex",system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;
139
+ --monospace: Consolas, monaco, monospace;
140
+ --navy: #073a53;
141
+ --teal: #6bc4ce;
142
+ --turquoise: #47AFB4;
143
+ --steel-gray: #3f5667;
144
+ --dark-white: #d9dbe2;
145
+ --light-white: #edf0f4;
146
+ --near-white: #f7f8fa;
147
+ --radius: 4px;
148
+ }
149
+
150
+ body {
151
+ color: #34373f;
152
+ font-family: var(--sans-serif);
153
+ line-height: 1.43;
154
+ margin: 0;
155
+ word-break: break-all;
156
+ -webkit-text-size-adjust: 100%;
157
+ -ms-text-size-adjust: 100%;
158
+ -webkit-tap-highlight-color: transparent;
159
+ }
160
+
161
+ pre, code {
162
+ font-family: var(--monospace);
163
+ }
164
+
165
+ a {
166
+ color: #117eb3;
167
+ text-decoration: none;
168
+ }
169
+
170
+ a:hover {
171
+ color: #00b0e9;
172
+ text-decoration: underline;
173
+ }
174
+
175
+ a:active,a:visited {
176
+ color: #00b0e9;
177
+ }
178
+
179
+ .flex {
180
+ display: flex;
181
+ }
182
+
183
+ .flex-wrap {
184
+ flex-flow: wrap;
185
+ }
186
+
187
+ .flex-shrink {
188
+ flex-shrink: 1;
189
+ }
190
+
191
+ .ml-auto {
192
+ margin-left: auto;
193
+ }
194
+
195
+ .nowrap {
196
+ white-space: nowrap
197
+ }
198
+
199
+ .ipfs-hash {
200
+ color: #7f8491;
201
+ font-family: var(--monospace);
202
+ }
203
+
204
+ #header {
205
+ align-items: center;
206
+ background: var(--navy);
207
+ border-bottom: 4px solid var(--teal);
208
+ color: #fff;
209
+ display: flex;
210
+ font-weight: 500;
211
+ justify-content: space-between;
212
+ padding: 0 1em;
213
+ }
214
+
215
+ #header a {
216
+ color: var(--teal);
217
+ }
218
+
219
+ #header a:active {
220
+ color: #9ad4db;
221
+ }
222
+
223
+ #header a:hover {
224
+ color: #fff;
225
+ }
226
+
227
+ #header .ipfs-logo {
228
+ height: 2.25em;
229
+ margin: .7em .7em .7em 0;
230
+ width: 7.15em
231
+ }
232
+
233
+ #header nav {
234
+ align-items: center;
235
+ display: flex;
236
+ margin: .65em 0;
237
+ }
238
+
239
+ #header nav a {
240
+ margin: 0 .6em;
241
+ }
242
+
243
+ #header nav a:last-child {
244
+ margin: 0 0 0 .6em;
245
+ }
246
+
247
+ #header nav svg {
248
+ fill: var(--teal);
249
+ height: 1.8em;
250
+ margin-top: .125em;
251
+ }
252
+
253
+ #header nav svg:hover {
254
+ fill: #fff;
255
+ }
256
+
257
+ main {
258
+ border: 1px solid var(--dark-white);
259
+ border-radius: var(--radius);
260
+ overflow: hidden;
261
+ margin: 1em;
262
+ font-size: .875em;
263
+ }
264
+
265
+ main header,main .container {
266
+ padding-left: 1em;
267
+ padding-right: 1em;
268
+ }
269
+
270
+ main header {
271
+ padding-top: .7em;
272
+ padding-bottom: .7em;
273
+ background-color: var(--light-white);
274
+ }
275
+
276
+ main header,main section:not(:last-child) {
277
+ border-bottom: 1px solid var(--dark-white);
278
+ }
279
+
280
+ main section header {
281
+ background-color: var(--near-white);
282
+ }
283
+
284
+ .grid {
285
+ display: grid;
286
+ overflow-x: auto;
287
+ }
288
+
289
+ .grid .grid {
290
+ overflow-x: visible;
291
+ }
292
+
293
+ .grid > div {
294
+ padding: .7em;
295
+ border-bottom: 1px solid var(--dark-white);
296
+ }
297
+
298
+ .grid.dir {
299
+ grid-template-columns: min-content 1fr min-content min-content;
300
+ }
301
+
302
+ .grid.dir > div:nth-of-type(4n+1) {
303
+ padding-left: 1em;
304
+ }
305
+
306
+ .grid.dir > div:nth-of-type(4n+4) {
307
+ padding-right: 1em;
308
+ }
309
+
310
+ .grid.dir > div:nth-last-child(-n+4) {
311
+ border-bottom: 0;
312
+ }
313
+
314
+ .grid.dir > div:nth-of-type(8n+5),.grid.dir > div:nth-of-type(8n+6),.grid.dir > div:nth-of-type(8n+7),.grid.dir > div:nth-of-type(8n+8) {
315
+ background-color: var(--near-white);
316
+ }
317
+
318
+ .grid.dag {
319
+ grid-template-columns: max-content 1fr;
320
+ }
321
+
322
+ .grid.dag pre {
323
+ margin: 0;
324
+ }
325
+
326
+ .grid.dag .grid {
327
+ padding: 0;
328
+ }
329
+
330
+ .grid.dag > div:nth-last-child(-n+2) {
331
+ border-bottom: 0;
332
+ }
333
+
334
+ .grid.dag > div {
335
+ background: white
336
+ }
337
+
338
+ .grid.dag > div:nth-child(4n),.grid.dag > div:nth-child(4n+3) {
339
+ background-color: var(--near-white);
340
+ }
341
+
342
+ section > .grid.dag > div:nth-of-type(2n+1) {
343
+ padding-left: 1em;
344
+ }
345
+
346
+ .type-icon,.type-icon > * {
347
+ width: 1.15em
348
+ }
349
+
350
+ .terminal {
351
+ background: var(--steel-gray);
352
+ color: white;
353
+ padding: .7em;
354
+ border-radius: var(--radius);
355
+ word-wrap: break-word;
356
+ white-space: break-spaces;
357
+ }
358
+
359
+ @media print {
360
+ #header {
361
+ display: none;
362
+ }
363
+
364
+ #main header,.ipfs-hash,body {
365
+ color: #000;
366
+ }
367
+
368
+ #main,#main header {
369
+ border-color: #000;
370
+ }
371
+
372
+ a,a:visited {
373
+ color: #000;
374
+ text-decoration: underline;
375
+ }
376
+
377
+ a[href]:after {
378
+ content: " (" attr(href) ")"
379
+ }
380
+ }
381
+
382
+ @media only screen and (max-width: 500px) {
383
+ .dn-mobile {
384
+ display: none;
385
+ }
386
+ }`;
387
+ //# sourceMappingURL=dir-index-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dir-index-html.js","sourceRoot":"","sources":["../../../src/utils/dir-index-html.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,7 @@ interface GetETagArg {
17
17
  /**
18
18
  * etag
19
19
  * you need to wrap cid with ""
20
- * we use strong Etags for immutable responses and weak one (prefixed with W/ ) for mutable/generated ones (ipns and generated HTML).
20
+ * we use strong Etags for immutable responses and weak one (prefixed with W/ ) for mutable/generated ones (ipns, car, tar, and generated HTML).
21
21
  * block and car responses should have different etag than deserialized one, so you can add some prefix like we do in existing gateway
22
22
  *
23
23
  * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
@@ -1 +1 @@
1
- {"version":3,"file":"get-e-tag.d.ts","sourceRoot":"","sources":["../../../src/utils/get-e-tag.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAE3C,UAAU,UAAU;IAClB,GAAG,EAAE,GAAG,CAAA;IACR,SAAS,CAAC,EAAE,sBAAsB,CAAA;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,UAAU,GAAG,MAAM,CAQ3F"}
1
+ {"version":3,"file":"get-e-tag.d.ts","sourceRoot":"","sources":["../../../src/utils/get-e-tag.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAE3C,UAAU,UAAU;IAClB,GAAG,EAAE,GAAG,CAAA;IACR,SAAS,CAAC,EAAE,sBAAsB,CAAA;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,UAAU,GAAG,MAAM,CAQ3F"}
@@ -1,15 +1,30 @@
1
+ const getPrefix = ({ weak, reqFormat }) => {
2
+ if (reqFormat === 'tar' || reqFormat === 'car' || reqFormat === 'ipns-record' || weak === true) {
3
+ return 'W/';
4
+ }
5
+ return '';
6
+ };
7
+ const getFormatSuffix = ({ reqFormat }) => {
8
+ if (reqFormat == null) {
9
+ return '';
10
+ }
11
+ if (reqFormat === 'tar') {
12
+ return '.x-tar';
13
+ }
14
+ return `.${reqFormat}`;
15
+ };
1
16
  /**
2
17
  * etag
3
18
  * you need to wrap cid with ""
4
- * we use strong Etags for immutable responses and weak one (prefixed with W/ ) for mutable/generated ones (ipns and generated HTML).
19
+ * we use strong Etags for immutable responses and weak one (prefixed with W/ ) for mutable/generated ones (ipns, car, tar, and generated HTML).
5
20
  * block and car responses should have different etag than deserialized one, so you can add some prefix like we do in existing gateway
6
21
  *
7
22
  * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
8
23
  * @see https://specs.ipfs.tech/http-gateways/path-gateway/#etag-response-header
9
24
  */
10
25
  export function getETag({ cid, reqFormat, weak, rangeStart, rangeEnd }) {
11
- const prefix = weak === true ? 'W/' : '';
12
- let suffix = reqFormat == null ? '' : `.${reqFormat}`;
26
+ const prefix = getPrefix({ weak, reqFormat });
27
+ let suffix = getFormatSuffix({ reqFormat });
13
28
  if (rangeStart != null || rangeEnd != null) {
14
29
  suffix += `.${rangeStart ?? '0'}-${rangeEnd ?? 'N'}`;
15
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"get-e-tag.js","sourceRoot":"","sources":["../../../src/utils/get-e-tag.ts"],"names":[],"mappings":"AAkBA;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CAAE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAc;IACjF,MAAM,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;IACxC,IAAI,MAAM,GAAG,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAA;IACrD,IAAI,UAAU,IAAI,IAAI,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC3C,MAAM,IAAI,IAAI,UAAU,IAAI,GAAG,IAAI,QAAQ,IAAI,GAAG,EAAE,CAAA;IACtD,CAAC;IAED,OAAO,GAAG,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,GAAG,MAAM,GAAG,CAAA;AAChD,CAAC"}
1
+ {"version":3,"file":"get-e-tag.js","sourceRoot":"","sources":["../../../src/utils/get-e-tag.ts"],"names":[],"mappings":"AAiBA,MAAM,SAAS,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAuB,EAAU,EAAE;IACrE,IAAI,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,aAAa,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAC/F,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;AAED,MAAM,eAAe,GAAG,CAAC,EAAE,SAAS,EAAuB,EAAU,EAAE;IACrE,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QACtB,OAAO,EAAE,CAAA;IACX,CAAC;IACD,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;QACxB,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,OAAO,IAAI,SAAS,EAAE,CAAA;AACxB,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CAAE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAc;IACjF,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;IAC7C,IAAI,MAAM,GAAG,eAAe,CAAC,EAAE,SAAS,EAAE,CAAC,CAAA;IAC3C,IAAI,UAAU,IAAI,IAAI,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC3C,MAAM,IAAI,IAAI,UAAU,IAAI,GAAG,IAAI,QAAQ,IAAI,GAAG,EAAE,CAAA;IACtD,CAAC;IAED,OAAO,GAAG,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,GAAG,MAAM,GAAG,CAAA;AAChD,CAAC"}
@@ -7,11 +7,12 @@ export interface ParseResourceComponents {
7
7
  logger: ComponentLogger;
8
8
  }
9
9
  export interface ParseResourceOptions extends ParseUrlStringOptions {
10
+ withServerTiming?: boolean;
10
11
  }
11
12
  /**
12
13
  * Handles the different use cases for the `resource` argument.
13
14
  * The resource can represent an IPFS path, IPNS path, or CID.
14
15
  * If the resource represents an IPNS path, we need to resolve it to a CID.
15
16
  */
16
- export declare function parseResource(resource: Resource, { ipns, logger }: ParseResourceComponents, options?: ParseResourceOptions): Promise<ParsedUrlStringResults>;
17
+ export declare function parseResource(resource: Resource, { ipns, logger }: ParseResourceComponents, { withServerTiming, ...options }?: ParseResourceOptions): Promise<ParsedUrlStringResults>;
17
18
  //# sourceMappingURL=parse-resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse-resource.d.ts","sourceRoot":"","sources":["../../../src/utils/parse-resource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC1F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;CAElE;AACD;;;;GAIG;AACH,wBAAsB,aAAa,CAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAoBnK"}
1
+ {"version":3,"file":"parse-resource.d.ts","sourceRoot":"","sources":["../../../src/utils/parse-resource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC1F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;IACjE,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AACD;;;;GAIG;AACH,wBAAsB,aAAa,CAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,uBAAuB,EAAE,EAAE,gBAAwB,EAAE,GAAG,OAAO,EAAE,GAAE,oBAAkD,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAqBjO"}
@@ -5,9 +5,9 @@ import { parseUrlString } from './parse-url-string.js';
5
5
  * The resource can represent an IPFS path, IPNS path, or CID.
6
6
  * If the resource represents an IPNS path, we need to resolve it to a CID.
7
7
  */
8
- export async function parseResource(resource, { ipns, logger }, options) {
8
+ export async function parseResource(resource, { ipns, logger }, { withServerTiming = false, ...options } = { withServerTiming: false }) {
9
9
  if (typeof resource === 'string') {
10
- return parseUrlString({ urlString: resource, ipns, logger }, options);
10
+ return parseUrlString({ urlString: resource, ipns, logger, withServerTiming }, options);
11
11
  }
12
12
  const cid = CID.asCID(resource);
13
13
  if (cid != null) {
@@ -18,7 +18,8 @@ export async function parseResource(resource, { ipns, logger }, options) {
18
18
  path: '',
19
19
  query: {},
20
20
  ipfsPath: `/ipfs/${cid.toString()}`,
21
- ttl: 29030400 // 1 year for ipfs content
21
+ ttl: 29030400, // 1 year for ipfs content
22
+ serverTimings: []
22
23
  };
23
24
  }
24
25
  throw new TypeError(`Invalid resource. Cannot determine CID from resource: ${resource}`);
@@ -1 +1 @@
1
- {"version":3,"file":"parse-resource.js","sourceRoot":"","sources":["../../../src/utils/parse-resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AActD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAE,QAAkB,EAAE,EAAE,IAAI,EAAE,MAAM,EAA2B,EAAE,OAA8B;IAChI,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,cAAc,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,CAAA;IACvE,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;IAE/B,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,gBAAgB;QAChB,OAAO;YACL,GAAG;YACH,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,EAAE;YACT,QAAQ,EAAE,SAAS,GAAG,CAAC,QAAQ,EAAE,EAAE;YACnC,GAAG,EAAE,QAAQ,CAAC,0BAA0B;SACR,CAAA;IACpC,CAAC;IAED,MAAM,IAAI,SAAS,CAAC,yDAAyD,QAAQ,EAAE,CAAC,CAAA;AAC1F,CAAC"}
1
+ {"version":3,"file":"parse-resource.js","sourceRoot":"","sources":["../../../src/utils/parse-resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AActD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAE,QAAkB,EAAE,EAAE,IAAI,EAAE,MAAM,EAA2B,EAAE,EAAE,gBAAgB,GAAG,KAAK,EAAE,GAAG,OAAO,KAA2B,EAAE,gBAAgB,EAAE,KAAK,EAAE;IAC9L,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,cAAc,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,OAAO,CAAC,CAAA;IACzF,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;IAE/B,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,gBAAgB;QAChB,OAAO;YACL,GAAG;YACH,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,EAAE;YACT,QAAQ,EAAE,SAAS,GAAG,CAAC,QAAQ,EAAE,EAAE;YACnC,GAAG,EAAE,QAAQ,EAAE,0BAA0B;YACzC,aAAa,EAAE,EAAE;SACe,CAAA;IACpC,CAAC;IAED,MAAM,IAAI,SAAS,CAAC,yDAAyD,QAAQ,EAAE,CAAC,CAAA;AAC1F,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { type ServerTimingResult } from './server-timing.js';
1
2
  import type { RequestFormatShorthand } from '../types.js';
2
3
  import type { IPNS, IPNSRoutingEvents, ResolveDNSLinkProgressEvents, ResolveProgressEvents, ResolveResult } from '@helia/ipns';
3
4
  import type { AbortOptions, ComponentLogger } from '@libp2p/interface';
@@ -6,6 +7,7 @@ export interface ParseUrlStringInput {
6
7
  urlString: string;
7
8
  ipns: IPNS;
8
9
  logger: ComponentLogger;
10
+ withServerTiming?: boolean;
9
11
  }
10
12
  export interface ParseUrlStringOptions extends ProgressOptions<ResolveProgressEvents | IPNSRoutingEvents | ResolveDNSLinkProgressEvents>, AbortOptions {
11
13
  }
@@ -14,7 +16,7 @@ export interface ParsedUrlQuery extends Record<string, string | unknown> {
14
16
  download?: boolean;
15
17
  filename?: string;
16
18
  }
17
- interface ParsedUrlStringResultsBase extends ResolveResult {
19
+ export interface ParsedUrlStringResults extends ResolveResult {
18
20
  protocol: 'ipfs' | 'ipns';
19
21
  query: ParsedUrlQuery;
20
22
  /**
@@ -30,8 +32,11 @@ interface ParsedUrlStringResultsBase extends ResolveResult {
30
32
  * seconds as a number
31
33
  */
32
34
  ttl?: number;
35
+ /**
36
+ * serverTiming items
37
+ */
38
+ serverTimings: Array<ServerTimingResult<any>>;
33
39
  }
34
- export type ParsedUrlStringResults = ParsedUrlStringResultsBase;
35
40
  interface MatchUrlGroups {
36
41
  protocol: 'ipfs' | 'ipns';
37
42
  cidOrPeerIdOrDnsLink: string;
@@ -48,6 +53,6 @@ export declare function matchURLString(urlString: string): MatchUrlGroups;
48
53
  *
49
54
  * @todo we need to break out each step of this function (cid parsing, ipns resolving, dnslink resolving) into separate functions and then remove the eslint-disable comment
50
55
  */
51
- export declare function parseUrlString({ urlString, ipns, logger }: ParseUrlStringInput, options?: ParseUrlStringOptions): Promise<ParsedUrlStringResults>;
56
+ export declare function parseUrlString({ urlString, ipns, logger, withServerTiming }: ParseUrlStringInput, options?: ParseUrlStringOptions): Promise<ParsedUrlStringResults>;
52
57
  export {};
53
58
  //# sourceMappingURL=parse-url-string.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse-url-string.d.ts","sourceRoot":"","sources":["../../../src/utils/parse-url-string.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,KAAK,EAAwB,IAAI,EAAqB,iBAAiB,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACvK,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAU,MAAM,mBAAmB,CAAA;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAItD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,eAAe,CAAA;CACxB;AACD,MAAM,WAAW,qBAAsB,SAAQ,eAAe,CAAC,qBAAqB,GAAG,iBAAiB,GAAG,4BAA4B,CAAC,EAAE,YAAY;CAErJ;AAED,MAAM,WAAW,cAAe,SAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACtE,MAAM,CAAC,EAAE,sBAAsB,CAAA;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,UAAU,0BAA2B,SAAQ,aAAa;IACxD,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,KAAK,EAAE,cAAc,CAAA;IAErB;;;;;;;OAOG;IACH,QAAQ,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,MAAM,sBAAsB,GAAG,0BAA0B,CAAA;AAO/D,UAAU,cAAc;IACtB,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAgBD,wBAAgB,cAAc,CAAE,SAAS,EAAE,MAAM,GAAG,cAAc,CAUjE;AAsDD;;;;;;;;GAQG;AAEH,wBAAsB,cAAc,CAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAwHxJ"}
1
+ {"version":3,"file":"parse-url-string.d.ts","sourceRoot":"","sources":["../../../src/utils/parse-url-string.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAE1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,KAAK,EAAwB,IAAI,EAAqB,iBAAiB,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACvK,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAU,MAAM,mBAAmB,CAAA;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAItD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,eAAe,CAAA;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AACD,MAAM,WAAW,qBAAsB,SAAQ,eAAe,CAAC,qBAAqB,GAAG,iBAAiB,GAAG,4BAA4B,CAAC,EAAE,YAAY;CAErJ;AAED,MAAM,WAAW,cAAe,SAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACtE,MAAM,CAAC,EAAE,sBAAsB,CAAA;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC3D,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,KAAK,EAAE,cAAc,CAAA;IAErB;;;;;;;OAOG;IACH,QAAQ,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ;;OAEG;IACH,aAAa,EAAE,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAA;CAC9C;AAOD,UAAU,cAAc;IACtB,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAgBD,wBAAgB,cAAc,CAAE,SAAS,EAAE,MAAM,GAAG,cAAc,CAUjE;AAsDD;;;;;;;;GAQG;AAEH,wBAAsB,cAAc,CAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAwB,EAAE,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAkJlL"}
@@ -1,5 +1,6 @@
1
1
  import { CID } from 'multiformats/cid';
2
2
  import { getPeerIdFromString } from './get-peer-id-from-string.js';
3
+ import { serverTiming } from './server-timing.js';
3
4
  import { TLRU } from './tlru.js';
4
5
  const ipnsCache = new TLRU(1000);
5
6
  const URL_REGEX = /^(?<protocol>ip[fn]s):\/\/(?<cidOrPeerIdOrDnsLink>[^/?]+)\/?(?<path>[^?]*)\??(?<queryString>.*)$/;
@@ -86,13 +87,14 @@ function dnsLinkLabelDecoder(linkLabel) {
86
87
  * @todo we need to break out each step of this function (cid parsing, ipns resolving, dnslink resolving) into separate functions and then remove the eslint-disable comment
87
88
  */
88
89
  // eslint-disable-next-line complexity
89
- export async function parseUrlString({ urlString, ipns, logger }, options) {
90
+ export async function parseUrlString({ urlString, ipns, logger, withServerTiming = false }, options) {
90
91
  const log = logger.forComponent('helia:verified-fetch:parse-url-string');
91
92
  const { protocol, cidOrPeerIdOrDnsLink, path: urlPath, queryString } = matchURLString(urlString);
92
93
  let cid;
93
94
  let resolvedPath;
94
95
  const errors = [];
95
96
  let resolveResult;
97
+ const serverTimings = [];
96
98
  if (protocol === 'ipfs') {
97
99
  try {
98
100
  cid = CID.parse(cidOrPeerIdOrDnsLink);
@@ -122,7 +124,18 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
122
124
  if (peerId.publicKey == null) {
123
125
  throw new TypeError('cidOrPeerIdOrDnsLink contains no public key');
124
126
  }
125
- resolveResult = await ipns.resolve(peerId.publicKey, options);
127
+ if (withServerTiming) {
128
+ const resolveResultWithServerTiming = await serverTiming('ipns.resolve', `Resolve IPNS name ${cidOrPeerIdOrDnsLink}`, ipns.resolve.bind(null, peerId.publicKey, options));
129
+ serverTimings.push(resolveResultWithServerTiming);
130
+ // eslint-disable-next-line max-depth
131
+ if (resolveResultWithServerTiming.error != null) {
132
+ throw resolveResultWithServerTiming.error;
133
+ }
134
+ resolveResult = resolveResultWithServerTiming.result;
135
+ }
136
+ else {
137
+ resolveResult = await ipns.resolve(peerId.publicKey, options);
138
+ }
126
139
  cid = resolveResult?.cid;
127
140
  resolvedPath = resolveResult?.path;
128
141
  log.trace('resolved %s to %c', cidOrPeerIdOrDnsLink, cid);
@@ -147,7 +160,19 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
147
160
  }
148
161
  log.trace('Attempting to resolve DNSLink for %s', decodedDnsLinkLabel);
149
162
  try {
150
- resolveResult = await ipns.resolveDNSLink(decodedDnsLinkLabel, options);
163
+ // eslint-disable-next-line max-depth
164
+ if (withServerTiming) {
165
+ const resolveResultWithServerTiming = await serverTiming('ipns.resolveDNSLink', `Resolve DNSLink ${decodedDnsLinkLabel}`, ipns.resolveDNSLink.bind(ipns, decodedDnsLinkLabel, options));
166
+ serverTimings.push(resolveResultWithServerTiming);
167
+ // eslint-disable-next-line max-depth
168
+ if (resolveResultWithServerTiming.error != null) {
169
+ throw resolveResultWithServerTiming.error;
170
+ }
171
+ resolveResult = resolveResultWithServerTiming.result;
172
+ }
173
+ else {
174
+ resolveResult = await ipns.resolveDNSLink(decodedDnsLinkLabel, options);
175
+ }
151
176
  cid = resolveResult?.cid;
152
177
  resolvedPath = resolveResult?.path;
153
178
  log.trace('resolved %s to %c', decodedDnsLinkLabel, cid);
@@ -195,7 +220,8 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
195
220
  path: joinPaths(resolvedPath, urlPath ?? ''),
196
221
  query,
197
222
  ttl,
198
- ipfsPath: `/${protocol}/${cidOrPeerIdOrDnsLink}${urlPath != null && urlPath !== '' ? `/${urlPath}` : ''}`
223
+ ipfsPath: `/${protocol}/${cidOrPeerIdOrDnsLink}${urlPath != null && urlPath !== '' ? `/${urlPath}` : ''}`,
224
+ serverTimings
199
225
  };
200
226
  }
201
227
  /**