@helia/verified-fetch 2.4.0 → 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 (104) hide show
  1. package/README.md +192 -0
  2. package/dist/index.min.js +357 -32
  3. package/dist/src/index.d.ts +198 -0
  4. package/dist/src/index.d.ts.map +1 -1
  5. package/dist/src/index.js +192 -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 -27
  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/walk-path.d.ts +3 -2
  76. package/dist/src/utils/walk-path.d.ts.map +1 -1
  77. package/dist/src/utils/walk-path.js +1 -1
  78. package/dist/src/utils/walk-path.js.map +1 -1
  79. package/dist/src/verified-fetch.d.ts +6 -24
  80. package/dist/src/verified-fetch.d.ts.map +1 -1
  81. package/dist/src/verified-fetch.js +164 -387
  82. package/dist/src/verified-fetch.js.map +1 -1
  83. package/dist/typedoc-urls.json +32 -24
  84. package/package.json +6 -2
  85. package/src/index.ts +199 -0
  86. package/src/plugins/errors.ts +37 -0
  87. package/src/plugins/index.ts +8 -0
  88. package/src/plugins/plugin-base.ts +30 -0
  89. package/src/plugins/plugin-handle-car.ts +32 -0
  90. package/src/plugins/plugin-handle-dag-cbor.ts +84 -0
  91. package/src/plugins/plugin-handle-dag-pb.ts +168 -0
  92. package/src/plugins/plugin-handle-dag-walk.ts +53 -0
  93. package/src/plugins/plugin-handle-dir-index-html.ts +44 -0
  94. package/src/plugins/plugin-handle-ipns-record.ts +69 -0
  95. package/src/plugins/plugin-handle-json.ts +57 -0
  96. package/src/plugins/plugin-handle-raw.ts +92 -0
  97. package/src/plugins/plugin-handle-tar.ts +44 -0
  98. package/src/plugins/plugins.ts +4 -0
  99. package/src/plugins/types.ts +73 -0
  100. package/src/types.ts +0 -34
  101. package/src/utils/dir-index-html.ts +445 -0
  102. package/src/utils/get-e-tag.ts +20 -3
  103. package/src/utils/walk-path.ts +3 -3
  104. package/src/verified-fetch.ts +187 -430
@@ -0,0 +1,28 @@
1
+ import { car } from '@helia/car';
2
+ import toBrowserReadableStream from 'it-to-browser-readablestream';
3
+ import { okResponse } from '../utils/responses.js';
4
+ import { BasePlugin } from './plugin-base.js';
5
+ /**
6
+ * Accepts a `CID` and returns a `Response` with a body stream that is a CAR
7
+ * of the `DAG` referenced by the `CID`.
8
+ */
9
+ export class CarPlugin extends BasePlugin {
10
+ canHandle(context) {
11
+ this.log('checking if we can handle %c with accept %s', context.cid, context.accept);
12
+ return context.accept?.startsWith('application/vnd.ipld.car') === true || context.query.format === 'car'; // application/vnd.ipld.car
13
+ }
14
+ async handle(context) {
15
+ const { options } = context;
16
+ const { getBlockstore, helia } = this.pluginOptions;
17
+ context.reqFormat = 'car';
18
+ context.query.download = true;
19
+ context.query.filename = context.query.filename ?? `${context.cid.toString()}.car`;
20
+ const blockstore = getBlockstore(context.cid, context.resource, options?.session ?? true, options);
21
+ const c = car({ blockstore, getCodec: helia.getCodec });
22
+ const stream = toBrowserReadableStream(c.stream(context.cid, options));
23
+ const response = okResponse(context.resource, stream);
24
+ response.headers.set('content-type', 'application/vnd.ipld.car; version=1');
25
+ return response;
26
+ }
27
+ }
28
+ //# sourceMappingURL=plugin-handle-car.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-car.js","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-car.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAA;AAChC,OAAO,uBAAuB,MAAM,8BAA8B,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7C;;;GAGG;AACH,MAAM,OAAO,SAAU,SAAQ,UAAU;IACvC,SAAS,CAAE,OAAsB;QAC/B,IAAI,CAAC,GAAG,CAAC,6CAA6C,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;QACpF,OAAO,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,0BAA0B,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,KAAK,CAAA,CAAC,2BAA2B;IACtI,CAAC;IAED,KAAK,CAAC,MAAM,CAAE,OAAsB;QAClC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;QAC3B,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,aAAa,CAAA;QACnD,OAAO,CAAC,SAAS,GAAG,KAAK,CAAA;QACzB,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAA;QAC7B,OAAO,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAA;QAClF,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,OAAO,CAAC,CAAA;QAClG,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,uBAAuB,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;QAEtE,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QACrD,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,qCAAqC,CAAC,CAAA;QAE3E,OAAO,QAAQ,CAAA;IACjB,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ import { BasePlugin } from './plugin-base.js';
2
+ import type { PluginContext } from './types.js';
3
+ /**
4
+ * Handles `dag-cbor` content, including requests with Accept: `application/vnd.ipld.dag-json` and `application/json`.
5
+ */
6
+ export declare class DagCborPlugin extends BasePlugin {
7
+ readonly codes: 113[];
8
+ canHandle({ cid, accept, pathDetails }: PluginContext): boolean;
9
+ handle(context: PluginContext): Promise<Response>;
10
+ }
11
+ //# sourceMappingURL=plugin-handle-dag-cbor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-dag-cbor.d.ts","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-dag-cbor.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAG/C;;GAEG;AACH,qBAAa,aAAc,SAAQ,UAAU;IAC3C,QAAQ,CAAC,KAAK,QAAqB;IAEnC,SAAS,CAAE,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,aAAa,GAAG,OAAO;IAe1D,MAAM,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC;CAoDzD"}
@@ -0,0 +1,73 @@
1
+ import * as ipldDagCbor from '@ipld/dag-cbor';
2
+ import * as ipldDagJson from '@ipld/dag-json';
3
+ import { dagCborToSafeJSON } from '../utils/dag-cbor-to-safe-json.js';
4
+ import { setIpfsRoots } from '../utils/response-headers.js';
5
+ import { notAcceptableResponse, okResponse } from '../utils/responses.js';
6
+ import { isObjectNode } from '../utils/walk-path.js';
7
+ import { BasePlugin } from './plugin-base.js';
8
+ /**
9
+ * Handles `dag-cbor` content, including requests with Accept: `application/vnd.ipld.dag-json` and `application/json`.
10
+ */
11
+ export class DagCborPlugin extends BasePlugin {
12
+ codes = [ipldDagCbor.code];
13
+ canHandle({ cid, accept, pathDetails }) {
14
+ this.log('checking if we can handle %c with accept %s', cid, accept);
15
+ if (pathDetails == null) {
16
+ return false;
17
+ }
18
+ if (!isObjectNode(pathDetails.terminalElement)) {
19
+ return false;
20
+ }
21
+ if (cid.code !== ipldDagCbor.code) {
22
+ return false;
23
+ }
24
+ return isObjectNode(pathDetails.terminalElement);
25
+ }
26
+ async handle(context) {
27
+ const { cid, path, resource, accept, pathDetails } = context;
28
+ this.log.trace('fetching %c/%s', cid, path);
29
+ if (pathDetails == null) {
30
+ throw new Error('pathDetails is null');
31
+ }
32
+ const ipfsRoots = pathDetails.ipfsRoots;
33
+ const terminalElement = pathDetails.terminalElement; // checked in canHandle fn.
34
+ const block = terminalElement.node;
35
+ let body;
36
+ if (accept === 'application/octet-stream' || accept === 'application/vnd.ipld.dag-cbor' || accept === 'application/cbor') {
37
+ // skip decoding
38
+ body = block;
39
+ }
40
+ else if (accept === 'application/vnd.ipld.dag-json') {
41
+ try {
42
+ // if vnd.ipld.dag-json has been specified, convert to the format - note
43
+ // that this supports more data types than regular JSON, the content-type
44
+ // response header is set so the user knows to process it differently
45
+ const obj = ipldDagCbor.decode(block);
46
+ body = ipldDagJson.encode(obj);
47
+ }
48
+ catch (err) {
49
+ this.log.error('could not transform %c to application/vnd.ipld.dag-json', err);
50
+ return notAcceptableResponse(resource);
51
+ }
52
+ }
53
+ else {
54
+ try {
55
+ body = dagCborToSafeJSON(block);
56
+ }
57
+ catch (err) {
58
+ if (accept === 'application/json') {
59
+ this.log('could not decode DAG-CBOR as JSON-safe, but the client sent "Accept: application/json"', err);
60
+ return notAcceptableResponse(resource);
61
+ }
62
+ this.log('could not decode DAG-CBOR as JSON-safe, falling back to `application/octet-stream`', err);
63
+ body = block;
64
+ }
65
+ }
66
+ const response = okResponse(resource, body);
67
+ const responseContentType = accept ?? (body instanceof Uint8Array ? 'application/octet-stream' : 'application/json');
68
+ response.headers.set('content-type', responseContentType);
69
+ setIpfsRoots(response, ipfsRoots);
70
+ return response;
71
+ }
72
+ }
73
+ //# sourceMappingURL=plugin-handle-dag-cbor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-dag-cbor.js","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-dag-cbor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { BasePlugin } from './plugin-base.js';
2
+ import type { PluginContext } from './types.js';
3
+ /**
4
+ * Handles UnixFS and dag-pb content.
5
+ */
6
+ export declare class DagPbPlugin extends BasePlugin {
7
+ readonly codes: 112[];
8
+ canHandle({ cid, accept, pathDetails }: PluginContext): boolean;
9
+ /**
10
+ * @see https://specs.ipfs.tech/http-gateways/path-gateway/#use-in-directory-url-normalization
11
+ */
12
+ getRedirectUrl(context: PluginContext): string | null;
13
+ handle(context: PluginContext): Promise<Response | null>;
14
+ }
15
+ //# sourceMappingURL=plugin-handle-dag-pb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-dag-pb.d.ts","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-dag-pb.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAG/C;;GAEG;AACH,qBAAa,WAAY,SAAQ,UAAU;IACzC,QAAQ,CAAC,KAAK,QAAc;IAC5B,SAAS,CAAE,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,aAAa,GAAG,OAAO;IAShE;;OAEG;IACH,cAAc,CAAE,OAAO,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI;IAiBhD,MAAM,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;CAwHhE"}
@@ -0,0 +1,152 @@
1
+ import { unixfs } from '@helia/unixfs';
2
+ import { code as dagPbCode } from '@ipld/dag-pb';
3
+ import { exporter } from 'ipfs-unixfs-exporter';
4
+ import { CustomProgressEvent } from 'progress-events';
5
+ import { ByteRangeContext } from '../utils/byte-range-context.js';
6
+ import { getStreamFromAsyncIterable } from '../utils/get-stream-from-async-iterable.js';
7
+ import { setIpfsRoots } from '../utils/response-headers.js';
8
+ import { badGatewayResponse, badRangeResponse, movedPermanentlyResponse, notSupportedResponse, okRangeResponse } from '../utils/responses.js';
9
+ import { setContentType } from '../utils/set-content-type.js';
10
+ import { BasePlugin } from './plugin-base.js';
11
+ /**
12
+ * Handles UnixFS and dag-pb content.
13
+ */
14
+ export class DagPbPlugin extends BasePlugin {
15
+ codes = [dagPbCode];
16
+ canHandle({ cid, accept, pathDetails }) {
17
+ this.log('checking if we can handle %c with accept %s', cid, accept);
18
+ if (pathDetails == null) {
19
+ return false;
20
+ }
21
+ return cid.code === dagPbCode;
22
+ }
23
+ /**
24
+ * @see https://specs.ipfs.tech/http-gateways/path-gateway/#use-in-directory-url-normalization
25
+ */
26
+ getRedirectUrl(context) {
27
+ const { resource, path } = context;
28
+ const redirectCheckNeeded = path === '' ? !resource.toString().endsWith('/') : !path.endsWith('/');
29
+ if (redirectCheckNeeded) {
30
+ try {
31
+ const url = new URL(resource.toString());
32
+ // make sure we append slash to end of the path
33
+ url.pathname = `${url.pathname}/`;
34
+ return url.toString();
35
+ }
36
+ catch (err) {
37
+ // resource is likely a CID
38
+ return `${resource.toString()}/`;
39
+ }
40
+ }
41
+ return null;
42
+ }
43
+ async handle(context) {
44
+ const { cid, options, withServerTiming = false, pathDetails } = context;
45
+ const { handleServerTiming, contentTypeParser, helia, getBlockstore } = this.pluginOptions;
46
+ const log = this.log;
47
+ let resource = context.resource;
48
+ let path = context.path;
49
+ let redirected = false;
50
+ const byteRangeContext = new ByteRangeContext(this.pluginOptions.logger, options?.headers);
51
+ if (pathDetails == null) {
52
+ throw new TypeError('Path details are required');
53
+ }
54
+ const ipfsRoots = pathDetails.ipfsRoots;
55
+ const terminalElement = pathDetails.terminalElement;
56
+ let resolvedCID = terminalElement.cid;
57
+ if (terminalElement?.type === 'directory') {
58
+ const dirCid = terminalElement.cid;
59
+ const redirectUrl = this.getRedirectUrl(context);
60
+ if (redirectUrl != null) {
61
+ log.trace('directory url normalization spec requires redirect...');
62
+ if (options?.redirect === 'error') {
63
+ log('could not redirect to %s as redirect option was set to "error"', redirectUrl);
64
+ throw new TypeError('Failed to fetch');
65
+ }
66
+ else if (options?.redirect === 'manual') {
67
+ log('returning 301 permanent redirect to %s', redirectUrl);
68
+ return movedPermanentlyResponse(resource, redirectUrl);
69
+ }
70
+ log('following redirect to %s', redirectUrl);
71
+ // fall-through simulates following the redirect?
72
+ resource = redirectUrl;
73
+ redirected = true;
74
+ }
75
+ const rootFilePath = 'index.html';
76
+ try {
77
+ log.trace('found directory at %c/%s, looking for index.html', cid, path);
78
+ const entry = await handleServerTiming('exporter-dir', '', async () => exporter(`/ipfs/${dirCid}/${rootFilePath}`, helia.blockstore, {
79
+ signal: options?.signal,
80
+ onProgress: options?.onProgress
81
+ }), withServerTiming);
82
+ log.trace('found root file at %c/%s with cid %c', dirCid, rootFilePath, entry.cid);
83
+ path = rootFilePath;
84
+ resolvedCID = entry.cid;
85
+ }
86
+ catch (err) {
87
+ this.log.error('error loading path %c/%s', dirCid, rootFilePath, err);
88
+ options?.signal?.throwIfAborted();
89
+ context.isDirectory = true;
90
+ context.directoryEntries = [];
91
+ this.log.trace('attempting to get directory entries because index.html was not found');
92
+ const fs = unixfs({ ...helia, blockstore: getBlockstore(context.cid, context.resource, options?.session ?? true, options) });
93
+ try {
94
+ for await (const dirItem of fs.ls(dirCid, { signal: options?.signal, onProgress: options?.onProgress })) {
95
+ context.directoryEntries.push(dirItem);
96
+ }
97
+ // dir-index-html plugin or dir-index-json (future idea?) plugin should handle this
98
+ return null;
99
+ }
100
+ catch (e) {
101
+ log.error('error listing directory %c', dirCid, e);
102
+ return notSupportedResponse('Unable to get directory contents');
103
+ }
104
+ }
105
+ finally {
106
+ options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:end', { cid: dirCid, path: rootFilePath }));
107
+ }
108
+ }
109
+ // we have a validRangeRequest & terminalElement is a file, we know the size and should set it
110
+ if (byteRangeContext.isRangeRequest && byteRangeContext.isValidRangeRequest && terminalElement.type === 'file') {
111
+ byteRangeContext.setFileSize(terminalElement.unixfs.fileSize());
112
+ log.trace('fileSize for rangeRequest %d', byteRangeContext.getFileSize());
113
+ }
114
+ const offset = byteRangeContext.offset;
115
+ const length = byteRangeContext.length;
116
+ log.trace('calling exporter for %c/%s with offset=%o & length=%o', resolvedCID, path, offset, length);
117
+ try {
118
+ const entry = await handleServerTiming('exporter-file', '', async () => exporter(resolvedCID, helia.blockstore, {
119
+ signal: options?.signal,
120
+ onProgress: options?.onProgress
121
+ }), withServerTiming);
122
+ const asyncIter = entry.content({
123
+ signal: options?.signal,
124
+ onProgress: options?.onProgress,
125
+ offset,
126
+ length
127
+ });
128
+ log('got async iterator for %c/%s', cid, path);
129
+ const { stream, firstChunk } = await handleServerTiming('stream-and-chunk', '', async () => getStreamFromAsyncIterable(asyncIter, path ?? '', this.pluginOptions.logger, {
130
+ onProgress: options?.onProgress,
131
+ signal: options?.signal
132
+ }), withServerTiming);
133
+ byteRangeContext.setBody(stream);
134
+ // if not a valid range request, okRangeRequest will call okResponse
135
+ const response = okRangeResponse(resource, byteRangeContext.getBody(), { byteRangeContext, log }, {
136
+ redirected
137
+ });
138
+ await handleServerTiming('set-content-type', '', async () => setContentType({ bytes: firstChunk, path, response, contentTypeParser, log }), withServerTiming);
139
+ setIpfsRoots(response, ipfsRoots);
140
+ return response;
141
+ }
142
+ catch (err) {
143
+ options?.signal?.throwIfAborted();
144
+ log.error('error streaming %c/%s', cid, path, err);
145
+ if (byteRangeContext.isRangeRequest && err.code === 'ERR_INVALID_PARAMS') {
146
+ return badRangeResponse(resource);
147
+ }
148
+ return badGatewayResponse(resource.toString(), 'Unable to stream content');
149
+ }
150
+ }
151
+ }
152
+ //# sourceMappingURL=plugin-handle-dag-pb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-dag-pb.js","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-dag-pb.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { BasePlugin } from './plugin-base.js';
2
+ import type { PluginContext } from './types.js';
3
+ /**
4
+ * This plugin should almost always run first because it's going to handle path walking if needed, and will only say it can handle
5
+ * the request if path walking is possible (path is not empty, terminalCid is unknown, and the path has not been walked yet).
6
+ *
7
+ * Once this plugin has run, the PluginContext will be updated and then this plugin will return false for canHandle, so it won't run again.
8
+ */
9
+ export declare class DagWalkPlugin extends BasePlugin {
10
+ /**
11
+ * Return false if the path has already been walked, otherwise return true if the CID is encoded with a codec that supports pathing.
12
+ */
13
+ canHandle(context: PluginContext): boolean;
14
+ handle(context: PluginContext): Promise<Response | null>;
15
+ }
16
+ //# sourceMappingURL=plugin-handle-dag-walk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-dag-walk.d.ts","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-dag-walk.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C;;;;;GAKG;AACH,qBAAa,aAAc,SAAQ,UAAU;IAC3C;;OAEG;IACH,SAAS,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO;IAWrC,MAAM,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;CAyBhE"}
@@ -0,0 +1,45 @@
1
+ import { code as dagCborCode } from '@ipld/dag-cbor';
2
+ import { code as dagPbCode } from '@ipld/dag-pb';
3
+ import { handlePathWalking } from '../utils/walk-path.js';
4
+ import { BasePlugin } from './plugin-base.js';
5
+ /**
6
+ * This plugin should almost always run first because it's going to handle path walking if needed, and will only say it can handle
7
+ * the request if path walking is possible (path is not empty, terminalCid is unknown, and the path has not been walked yet).
8
+ *
9
+ * Once this plugin has run, the PluginContext will be updated and then this plugin will return false for canHandle, so it won't run again.
10
+ */
11
+ export class DagWalkPlugin extends BasePlugin {
12
+ /**
13
+ * Return false if the path has already been walked, otherwise return true if the CID is encoded with a codec that supports pathing.
14
+ */
15
+ canHandle(context) {
16
+ this.log('checking if we can handle %c with accept %s', context.cid, context.accept);
17
+ const { pathDetails, cid } = context;
18
+ if (pathDetails != null) {
19
+ // path has already been walked
20
+ return false;
21
+ }
22
+ return (cid.code === dagPbCode || cid.code === dagCborCode);
23
+ }
24
+ async handle(context) {
25
+ const { cid, resource, options, withServerTiming = false } = context;
26
+ const { getBlockstore, handleServerTiming } = this.pluginOptions;
27
+ const blockstore = getBlockstore(cid, resource, options?.session ?? true, options);
28
+ // TODO: migrate handlePathWalking into this plugin
29
+ const pathDetails = await handleServerTiming('path-walking', '', async () => handlePathWalking({ ...context, blockstore, log: this.log }), withServerTiming);
30
+ context.modified++;
31
+ if (pathDetails instanceof Response) {
32
+ this.log.trace('path walking failed');
33
+ if (pathDetails.status === 404) {
34
+ // invalid or incorrect path.. we walked the path but nothing is there
35
+ // send the 404 response
36
+ return pathDetails;
37
+ }
38
+ // some error walking the path
39
+ return null;
40
+ }
41
+ context.pathDetails = pathDetails;
42
+ return null;
43
+ }
44
+ }
45
+ //# sourceMappingURL=plugin-handle-dag-walk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-dag-walk.js","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-dag-walk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7C;;;;;GAKG;AACH,MAAM,OAAO,aAAc,SAAQ,UAAU;IAC3C;;OAEG;IACH,SAAS,CAAE,OAAsB;QAC/B,IAAI,CAAC,GAAG,CAAC,6CAA6C,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;QACpF,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,OAAO,CAAA;QACpC,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;YACxB,+BAA+B;YAC/B,OAAO,KAAK,CAAA;QACd,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAAA;IAC7D,CAAC;IAED,KAAK,CAAC,MAAM,CAAE,OAAsB;QAClC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,gBAAgB,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;QACpE,MAAM,EAAE,aAAa,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC,aAAa,CAAA;QAChE,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,OAAO,CAAC,CAAA;QAClF,mDAAmD;QACnD,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,cAAc,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE,CAAC,iBAAiB,CAAC,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,gBAAgB,CAAC,CAAA;QAE5J,OAAO,CAAC,QAAQ,EAAE,CAAA;QAClB,IAAI,WAAW,YAAY,QAAQ,EAAE,CAAC;YACpC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAA;YAErC,IAAI,WAAW,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC/B,sEAAsE;gBACtE,wBAAwB;gBACxB,OAAO,WAAW,CAAA;YACpB,CAAC;YAED,8BAA8B;YAC9B,OAAO,IAAI,CAAA;QACb,CAAC;QAED,OAAO,CAAC,WAAW,GAAG,WAAW,CAAA;QAEjC,OAAO,IAAI,CAAA;IACb,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import { BasePlugin } from './plugin-base.js';
2
+ import type { PluginContext, VerifiedFetchPluginFactory } from './types.js';
3
+ export declare class DirIndexHtmlPlugin extends BasePlugin {
4
+ readonly codes: 112[];
5
+ canHandle(context: PluginContext): boolean;
6
+ handle(context: PluginContext): Promise<Response>;
7
+ }
8
+ export declare const dirIndexHtmlPluginFactory: VerifiedFetchPluginFactory;
9
+ //# sourceMappingURL=plugin-handle-dir-index-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-dir-index-html.d.ts","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-dir-index-html.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAA;AAE3E,qBAAa,kBAAmB,SAAQ,UAAU;IAChD,QAAQ,CAAC,KAAK,QAAc;IAC5B,SAAS,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO;IAgBrC,MAAM,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC;CAiBzD;AAED,eAAO,MAAM,yBAAyB,EAAE,0BAAmE,CAAA"}
@@ -0,0 +1,37 @@
1
+ import { code as dagPbCode } from '@ipld/dag-pb';
2
+ import { dirIndexHtml } from '../utils/dir-index-html.js';
3
+ import { okResponse } from '../utils/responses.js';
4
+ import { BasePlugin } from './plugin-base.js';
5
+ export class DirIndexHtmlPlugin extends BasePlugin {
6
+ codes = [dagPbCode];
7
+ canHandle(context) {
8
+ const { cid, pathDetails, directoryEntries } = context;
9
+ if (pathDetails == null) {
10
+ return false;
11
+ }
12
+ if (pathDetails.terminalElement?.type !== 'directory') {
13
+ return false;
14
+ }
15
+ if (directoryEntries?.length === 0) {
16
+ return false;
17
+ }
18
+ return cid.code === dagPbCode;
19
+ }
20
+ async handle(context) {
21
+ const { resource, pathDetails, directoryEntries } = context;
22
+ if (pathDetails?.terminalElement == null) {
23
+ throw new Error('Path details are required');
24
+ }
25
+ if (directoryEntries == null || directoryEntries?.length === 0) {
26
+ throw new Error('Directory entries are required');
27
+ }
28
+ const terminalElement = pathDetails.terminalElement;
29
+ const gatewayURL = resource;
30
+ const htmlResponse = dirIndexHtml(terminalElement, directoryEntries, { gatewayURL, log: this.log });
31
+ const response = okResponse(resource, htmlResponse);
32
+ response.headers.set('content-type', 'text/html');
33
+ return response;
34
+ }
35
+ }
36
+ export const dirIndexHtmlPluginFactory = (opts) => new DirIndexHtmlPlugin(opts);
37
+ //# sourceMappingURL=plugin-handle-dir-index-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-dir-index-html.js","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-dir-index-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7C,MAAM,OAAO,kBAAmB,SAAQ,UAAU;IACvC,KAAK,GAAG,CAAC,SAAS,CAAC,CAAA;IAC5B,SAAS,CAAE,OAAsB;QAC/B,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAA;QACtD,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;YACxB,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,WAAW,CAAC,eAAe,EAAE,IAAI,KAAK,WAAW,EAAE,CAAC;YACtD,OAAO,KAAK,CAAA;QACd,CAAC;QAED,IAAI,gBAAgB,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,OAAO,KAAK,CAAA;QACd,CAAC;QAED,OAAO,GAAG,CAAC,IAAI,KAAK,SAAS,CAAA;IAC/B,CAAC;IAED,KAAK,CAAC,MAAM,CAAE,OAAsB;QAClC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAA;QAE3D,IAAI,WAAW,EAAE,eAAe,IAAI,IAAI,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;QAC9C,CAAC;QACD,IAAI,gBAAgB,IAAI,IAAI,IAAI,gBAAgB,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;QACnD,CAAC;QACD,MAAM,eAAe,GAAG,WAAW,CAAC,eAAe,CAAA;QAEnD,MAAM,UAAU,GAAG,QAAQ,CAAA;QAC3B,MAAM,YAAY,GAAG,YAAY,CAAC,eAAe,EAAE,gBAAgB,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;QACnG,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;QACnD,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;QACjD,OAAO,QAAQ,CAAA;IACjB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,yBAAyB,GAA+B,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAA"}
@@ -0,0 +1,12 @@
1
+ import { BasePlugin } from './plugin-base.js';
2
+ import type { PluginContext } from './types.js';
3
+ /**
4
+ * Accepts an `ipns://...`, `https?://<ipnsname>.ipns.<domain>`, or `https?://<domain>/ipns/...` URL as a string and
5
+ * returns a `Response` containing a raw IPNS record.
6
+ */
7
+ export declare class IpnsRecordPlugin extends BasePlugin {
8
+ readonly codes: never[];
9
+ canHandle({ cid, accept, query }: PluginContext): boolean;
10
+ handle(context: PluginContext): Promise<Response>;
11
+ }
12
+ //# sourceMappingURL=plugin-handle-ipns-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-ipns-record.d.ts","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-ipns-record.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAG/C;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,UAAU;IAC9C,QAAQ,CAAC,KAAK,UAAK;IACnB,SAAS,CAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,aAAa,GAAG,OAAO;IAMpD,MAAM,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC;CA4CzD"}
@@ -0,0 +1,62 @@
1
+ import { Record as DHTRecord } from '@libp2p/kad-dht';
2
+ import { Key } from 'interface-datastore';
3
+ import { concat as uint8ArrayConcat } from 'uint8arrays/concat';
4
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
5
+ import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
6
+ import { getPeerIdFromString } from '../utils/get-peer-id-from-string.js';
7
+ import { badRequestResponse, okResponse } from '../utils/responses.js';
8
+ import { PluginFatalError } from './errors.js';
9
+ import { BasePlugin } from './plugin-base.js';
10
+ /**
11
+ * Accepts an `ipns://...`, `https?://<ipnsname>.ipns.<domain>`, or `https?://<domain>/ipns/...` URL as a string and
12
+ * returns a `Response` containing a raw IPNS record.
13
+ */
14
+ export class IpnsRecordPlugin extends BasePlugin {
15
+ codes = [];
16
+ canHandle({ cid, accept, query }) {
17
+ this.log('checking if we can handle %c with accept %s', cid, accept);
18
+ return accept === 'application/vnd.ipfs.ipns-record' || query.format === 'ipns-record';
19
+ }
20
+ async handle(context) {
21
+ const { resource, path, options } = context;
22
+ const { helia } = this.pluginOptions;
23
+ context.reqFormat = 'ipns-record';
24
+ if (path !== '' || !(resource.startsWith('ipns://') || resource.includes('.ipns.') || resource.includes('/ipns/'))) {
25
+ this.log.error('invalid request for IPNS name "%s" and path "%s"', resource, path);
26
+ throw new PluginFatalError('ERR_INVALID_IPNS_NAME', 'Invalid IPNS name', { response: badRequestResponse(resource, 'Invalid IPNS name') });
27
+ }
28
+ let peerId;
29
+ try {
30
+ let peerIdString;
31
+ if (resource.startsWith('ipns://')) {
32
+ peerIdString = resource.replace('ipns://', '');
33
+ }
34
+ else if (resource.includes('/ipns/')) {
35
+ peerIdString = resource.split('/ipns/')[1].split('/')[0].split('?')[0];
36
+ }
37
+ else {
38
+ peerIdString = resource.split('.ipns.')[0].split('://')[1];
39
+ }
40
+ this.log.trace('trying to parse peer id from "%s"', peerIdString);
41
+ peerId = getPeerIdFromString(peerIdString);
42
+ }
43
+ catch (err) {
44
+ this.log.error('could not parse peer id from IPNS url %s', resource, err);
45
+ throw new PluginFatalError('ERR_NO_PEER_ID_FOUND', 'could not parse peer id from url', { response: badRequestResponse(resource, err) });
46
+ }
47
+ // since this call happens after parseResource, we've already resolved the
48
+ // IPNS name so a local copy should be in the helia datastore, so we can
49
+ // just read it out..
50
+ const routingKey = uint8ArrayConcat([
51
+ uint8ArrayFromString('/ipns/'),
52
+ peerId.toMultihash().bytes
53
+ ]);
54
+ const datastoreKey = new Key('/dht/record/' + uint8ArrayToString(routingKey, 'base32'), false);
55
+ const buf = await helia.datastore.get(datastoreKey, options);
56
+ const record = DHTRecord.deserialize(buf);
57
+ const response = okResponse(resource, record.value);
58
+ response.headers.set('content-type', 'application/vnd.ipfs.ipns-record');
59
+ return response;
60
+ }
61
+ }
62
+ //# sourceMappingURL=plugin-handle-ipns-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-ipns-record.js","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-ipns-record.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAA;AACzC,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC/D,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAC5E,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAI7C;;;GAGG;AACH,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IACrC,KAAK,GAAG,EAAE,CAAA;IACnB,SAAS,CAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAiB;QAC9C,IAAI,CAAC,GAAG,CAAC,6CAA6C,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;QAEpE,OAAO,MAAM,KAAK,kCAAkC,IAAI,KAAK,CAAC,MAAM,KAAK,aAAa,CAAA;IACxF,CAAC;IAED,KAAK,CAAC,MAAM,CAAE,OAAsB;QAClC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;QAC3C,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,aAAa,CAAA;QACpC,OAAO,CAAC,SAAS,GAAG,aAAa,CAAA;QACjC,IAAI,IAAI,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;YACnH,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,kDAAkD,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;YAClF,MAAM,IAAI,gBAAgB,CAAC,uBAAuB,EAAE,mBAAmB,EAAE,EAAE,QAAQ,EAAE,kBAAkB,CAAC,QAAQ,EAAE,mBAAmB,CAAC,EAAE,CAAC,CAAA;QAC3I,CAAC;QACD,IAAI,MAAc,CAAA;QAElB,IAAI,CAAC;YACH,IAAI,YAAoB,CAAA;YACxB,IAAI,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACnC,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;YAChD,CAAC;iBAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACvC,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;YACxE,CAAC;iBAAM,CAAC;gBACN,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;YAC5D,CAAC;YAED,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,mCAAmC,EAAE,YAAY,CAAC,CAAA;YACjE,MAAM,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAA;QAC5C,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,0CAA0C,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAA;YAEzE,MAAM,IAAI,gBAAgB,CAAC,sBAAsB,EAAE,kCAAkC,EAAE,EAAE,QAAQ,EAAE,kBAAkB,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;QACzI,CAAC;QAED,0EAA0E;QAC1E,wEAAwE;QACxE,qBAAqB;QACrB,MAAM,UAAU,GAAG,gBAAgB,CAAC;YAClC,oBAAoB,CAAC,QAAQ,CAAC;YAC9B,MAAM,CAAC,WAAW,EAAE,CAAC,KAAK;SAC3B,CAAC,CAAA;QACF,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,cAAc,GAAG,kBAAkB,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAA;QAC9F,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;QAC5D,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;QAEzC,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;QACnD,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,kCAAkC,CAAC,CAAA;QAExE,OAAO,QAAQ,CAAA;IACjB,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ import { BasePlugin } from './plugin-base.js';
2
+ import type { PluginContext } from './types.js';
3
+ /**
4
+ * Handles `dag-json` content, including requests with Accept: `application/vnd.ipld.dag-cbor` and `application/cbor`.
5
+ */
6
+ export declare class JsonPlugin extends BasePlugin {
7
+ readonly codes: number[];
8
+ canHandle({ cid, accept }: PluginContext): boolean;
9
+ handle(context: PluginContext): Promise<Response>;
10
+ }
11
+ //# sourceMappingURL=plugin-handle-json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-json.d.ts","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-json.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C;;GAEG;AACH,qBAAa,UAAW,SAAQ,UAAU;IACxC,QAAQ,CAAC,KAAK,WAA+B;IAC7C,SAAS,CAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,aAAa,GAAG,OAAO;IAY7C,MAAM,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC;CAgCzD"}
@@ -0,0 +1,51 @@
1
+ import * as ipldDagCbor from '@ipld/dag-cbor';
2
+ import * as ipldDagJson from '@ipld/dag-json';
3
+ import { code as jsonCode } from 'multiformats/codecs/json';
4
+ import { notAcceptableResponse, okResponse } from '../utils/responses.js';
5
+ import { BasePlugin } from './plugin-base.js';
6
+ /**
7
+ * Handles `dag-json` content, including requests with Accept: `application/vnd.ipld.dag-cbor` and `application/cbor`.
8
+ */
9
+ export class JsonPlugin extends BasePlugin {
10
+ codes = [ipldDagJson.code, jsonCode];
11
+ canHandle({ cid, accept }) {
12
+ this.log('checking if we can handle %c with accept %s', cid, accept);
13
+ if (accept === 'application/vnd.ipld.dag-json' && cid.code !== ipldDagCbor.code) {
14
+ // we can handle application/vnd.ipld.dag-json, but if the CID codec is ipldDagCbor, DagCborPlugin should handle it
15
+ // TODO: remove the need for deny-listing cases in plugins
16
+ return true;
17
+ }
18
+ return ipldDagJson.code === cid.code || jsonCode === cid.code;
19
+ }
20
+ async handle(context) {
21
+ const { path, resource, cid, accept, options } = context;
22
+ const { getBlockstore } = this.pluginOptions;
23
+ const session = options?.session ?? true;
24
+ this.log.trace('fetching %c/%s', cid, path);
25
+ const terminalCid = context.pathDetails?.terminalElement.cid ?? context.cid;
26
+ const blockstore = getBlockstore(terminalCid, resource, session, options);
27
+ const block = await blockstore.get(terminalCid, options);
28
+ let body;
29
+ if (accept === 'application/vnd.ipld.dag-cbor' || accept === 'application/cbor') {
30
+ try {
31
+ // if vnd.ipld.dag-cbor has been specified, convert to the format - note
32
+ // that this supports more data types than regular JSON, the content-type
33
+ // response header is set so the user knows to process it differently
34
+ const obj = ipldDagJson.decode(block);
35
+ body = ipldDagCbor.encode(obj);
36
+ }
37
+ catch (err) {
38
+ this.log.error('could not transform %c to application/vnd.ipld.dag-cbor', err);
39
+ return notAcceptableResponse(resource);
40
+ }
41
+ }
42
+ else {
43
+ // skip decoding
44
+ body = block;
45
+ }
46
+ const response = okResponse(resource, body);
47
+ response.headers.set('content-type', accept ?? 'application/json');
48
+ return response;
49
+ }
50
+ }
51
+ //# sourceMappingURL=plugin-handle-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-json.js","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,gBAAgB,CAAA;AAC7C,OAAO,KAAK,WAAW,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7C;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,UAAU;IAC/B,KAAK,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IAC7C,SAAS,CAAE,EAAE,GAAG,EAAE,MAAM,EAAiB;QACvC,IAAI,CAAC,GAAG,CAAC,6CAA6C,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;QAEpE,IAAI,MAAM,KAAK,+BAA+B,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,EAAE,CAAC;YAChF,mHAAmH;YACnH,0DAA0D;YAC1D,OAAO,IAAI,CAAA;QACb,CAAC;QAED,OAAO,WAAW,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,QAAQ,KAAK,GAAG,CAAC,IAAI,CAAA;IAC/D,CAAC;IAED,KAAK,CAAC,MAAM,CAAE,OAAsB;QAClC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;QACxD,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,aAAa,CAAA;QAC5C,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,IAAI,CAAA;QAExC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAE3C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,eAAe,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAA;QAC3E,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;QACzE,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACxD,IAAI,IAAyB,CAAA;QAE7B,IAAI,MAAM,KAAK,+BAA+B,IAAI,MAAM,KAAK,kBAAkB,EAAE,CAAC;YAChF,IAAI,CAAC;gBACH,wEAAwE;gBACxE,yEAAyE;gBACzE,qEAAqE;gBACrE,MAAM,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBACrC,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAChC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,yDAAyD,EAAE,GAAG,CAAC,CAAA;gBAC9E,OAAO,qBAAqB,CAAC,QAAQ,CAAC,CAAA;YACxC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,gBAAgB;YAChB,IAAI,GAAG,KAAK,CAAA;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAC3C,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,MAAM,IAAI,kBAAkB,CAAC,CAAA;QAClE,OAAO,QAAQ,CAAA;IACjB,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import { BasePlugin } from './plugin-base.js';
2
+ import type { PluginContext } from './types.js';
3
+ export declare class RawPlugin extends BasePlugin {
4
+ codes: number[];
5
+ canHandle({ cid, accept, query }: PluginContext): boolean;
6
+ handle(context: PluginContext): Promise<Response>;
7
+ }
8
+ //# sourceMappingURL=plugin-handle-raw.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-handle-raw.d.ts","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-raw.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAsC/C,qBAAa,SAAU,SAAQ,UAAU;IACvC,KAAK,EAAE,MAAM,EAAE,CAA2B;IAE1C,SAAS,CAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,aAAa,GAAG,OAAO;IAKpD,MAAM,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC;CAsCzD"}