@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.
- package/README.md +192 -0
- package/dist/index.min.js +357 -32
- package/dist/src/index.d.ts +198 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +192 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugins/errors.d.ts +25 -0
- package/dist/src/plugins/errors.d.ts.map +1 -0
- package/dist/src/plugins/errors.js +33 -0
- package/dist/src/plugins/errors.js.map +1 -0
- package/dist/src/plugins/index.d.ts +8 -0
- package/dist/src/plugins/index.d.ts.map +1 -0
- package/dist/src/plugins/index.js +7 -0
- package/dist/src/plugins/index.js.map +1 -0
- package/dist/src/plugins/plugin-base.d.ts +19 -0
- package/dist/src/plugins/plugin-base.d.ts.map +1 -0
- package/dist/src/plugins/plugin-base.js +26 -0
- package/dist/src/plugins/plugin-base.js.map +1 -0
- package/dist/src/plugins/plugin-handle-car.d.ts +11 -0
- package/dist/src/plugins/plugin-handle-car.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-car.js +28 -0
- package/dist/src/plugins/plugin-handle-car.js.map +1 -0
- package/dist/src/plugins/plugin-handle-dag-cbor.d.ts +11 -0
- package/dist/src/plugins/plugin-handle-dag-cbor.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-dag-cbor.js +73 -0
- package/dist/src/plugins/plugin-handle-dag-cbor.js.map +1 -0
- package/dist/src/plugins/plugin-handle-dag-pb.d.ts +15 -0
- package/dist/src/plugins/plugin-handle-dag-pb.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-dag-pb.js +152 -0
- package/dist/src/plugins/plugin-handle-dag-pb.js.map +1 -0
- package/dist/src/plugins/plugin-handle-dag-walk.d.ts +16 -0
- package/dist/src/plugins/plugin-handle-dag-walk.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-dag-walk.js +45 -0
- package/dist/src/plugins/plugin-handle-dag-walk.js.map +1 -0
- package/dist/src/plugins/plugin-handle-dir-index-html.d.ts +9 -0
- package/dist/src/plugins/plugin-handle-dir-index-html.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-dir-index-html.js +37 -0
- package/dist/src/plugins/plugin-handle-dir-index-html.js.map +1 -0
- package/dist/src/plugins/plugin-handle-ipns-record.d.ts +12 -0
- package/dist/src/plugins/plugin-handle-ipns-record.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-ipns-record.js +62 -0
- package/dist/src/plugins/plugin-handle-ipns-record.js.map +1 -0
- package/dist/src/plugins/plugin-handle-json.d.ts +11 -0
- package/dist/src/plugins/plugin-handle-json.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-json.js +51 -0
- package/dist/src/plugins/plugin-handle-json.js.map +1 -0
- package/dist/src/plugins/plugin-handle-raw.d.ts +8 -0
- package/dist/src/plugins/plugin-handle-raw.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-raw.js +80 -0
- package/dist/src/plugins/plugin-handle-raw.js.map +1 -0
- package/dist/src/plugins/plugin-handle-tar.d.ts +12 -0
- package/dist/src/plugins/plugin-handle-tar.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-tar.js +36 -0
- package/dist/src/plugins/plugin-handle-tar.js.map +1 -0
- package/dist/src/plugins/plugins.d.ts +5 -0
- package/dist/src/plugins/plugins.d.ts.map +1 -0
- package/dist/src/plugins/plugins.js +5 -0
- package/dist/src/plugins/plugins.js.map +1 -0
- package/dist/src/plugins/types.d.ts +68 -0
- package/dist/src/plugins/types.d.ts.map +1 -0
- package/dist/src/plugins/types.js +2 -0
- package/dist/src/plugins/types.js.map +1 -0
- package/dist/src/types.d.ts +0 -27
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +1 -2
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils/dir-index-html.d.ts +16 -0
- package/dist/src/utils/dir-index-html.d.ts.map +1 -0
- package/dist/src/utils/dir-index-html.js +387 -0
- package/dist/src/utils/dir-index-html.js.map +1 -0
- package/dist/src/utils/get-e-tag.d.ts +1 -1
- package/dist/src/utils/get-e-tag.d.ts.map +1 -1
- package/dist/src/utils/get-e-tag.js +18 -3
- package/dist/src/utils/get-e-tag.js.map +1 -1
- package/dist/src/utils/walk-path.d.ts +3 -2
- package/dist/src/utils/walk-path.d.ts.map +1 -1
- package/dist/src/utils/walk-path.js +1 -1
- package/dist/src/utils/walk-path.js.map +1 -1
- package/dist/src/verified-fetch.d.ts +6 -24
- package/dist/src/verified-fetch.d.ts.map +1 -1
- package/dist/src/verified-fetch.js +164 -387
- package/dist/src/verified-fetch.js.map +1 -1
- package/dist/typedoc-urls.json +32 -24
- package/package.json +6 -2
- package/src/index.ts +199 -0
- package/src/plugins/errors.ts +37 -0
- package/src/plugins/index.ts +8 -0
- package/src/plugins/plugin-base.ts +30 -0
- package/src/plugins/plugin-handle-car.ts +32 -0
- package/src/plugins/plugin-handle-dag-cbor.ts +84 -0
- package/src/plugins/plugin-handle-dag-pb.ts +168 -0
- package/src/plugins/plugin-handle-dag-walk.ts +53 -0
- package/src/plugins/plugin-handle-dir-index-html.ts +44 -0
- package/src/plugins/plugin-handle-ipns-record.ts +69 -0
- package/src/plugins/plugin-handle-json.ts +57 -0
- package/src/plugins/plugin-handle-raw.ts +92 -0
- package/src/plugins/plugin-handle-tar.ts +44 -0
- package/src/plugins/plugins.ts +4 -0
- package/src/plugins/types.ts +73 -0
- package/src/types.ts +0 -34
- package/src/utils/dir-index-html.ts +445 -0
- package/src/utils/get-e-tag.ts +20 -3
- package/src/utils/walk-path.ts +3 -3
- package/src/verified-fetch.ts +187 -430
package/dist/src/index.d.ts
CHANGED
|
@@ -626,12 +626,204 @@
|
|
|
626
626
|
* 2. `TypeError` - If the options argument is passed and not an object.
|
|
627
627
|
* 3. `TypeError` - If the options argument is passed and is malformed.
|
|
628
628
|
* 4. `AbortError` - If the content request is aborted due to user aborting provided AbortSignal. Note that this is a `AbortError` from `@libp2p/interface` and not the standard `AbortError` from the Fetch API.
|
|
629
|
+
*
|
|
630
|
+
* ## Pluggability and Extensibility
|
|
631
|
+
*
|
|
632
|
+
* Verified‑fetch can now be extended to alter how it handles requests by using plugins.
|
|
633
|
+
* Plugins are classes that extend the `BasePlugin` class and implement the `VerifiedFetchPlugin`
|
|
634
|
+
* interface. They are instantiated with `PluginOptions` when the `VerifiedFetch` class is created.
|
|
635
|
+
*
|
|
636
|
+
* Each plugin must implement two methods:
|
|
637
|
+
*
|
|
638
|
+
* - **`canHandle(context: PluginContext): boolean`**
|
|
639
|
+
* Inspects the current `PluginContext` (which includes the CID, path, query, accept header, etc.)
|
|
640
|
+
* and returns `true` if the plugin can operate on the current state of the request.
|
|
641
|
+
*
|
|
642
|
+
* - **`handle(context: PluginContext): Promise<Response | null>`**
|
|
643
|
+
* Performs the plugin’s work. It may:
|
|
644
|
+
* - **Return a final `Response`**: This stops the pipeline immediately.
|
|
645
|
+
* - **Return `null`**: This indicates that the plugin has only partially processed the request
|
|
646
|
+
* (for example, by performing path walking or decoding) and the pipeline should continue.
|
|
647
|
+
* - **Throw a `PluginError`**: This logs a non-fatal error and continues the pipeline.
|
|
648
|
+
* - **Throw a `PluginFatalError`**: This logs a fatal error and stops the pipeline immediately.
|
|
649
|
+
*
|
|
650
|
+
* Plugins are executed in a chain (a **plugin pipeline**):
|
|
651
|
+
*
|
|
652
|
+
* 1. **Initialization:**
|
|
653
|
+
* - The `VerifiedFetch` class is instantiated with a list of plugins.
|
|
654
|
+
* - When a request is made via the `fetch` method, the resource and options are parsed to
|
|
655
|
+
* create a mutable `PluginContext` object.
|
|
656
|
+
*
|
|
657
|
+
* 2. **Pipeline Execution:**
|
|
658
|
+
* - The pipeline repeatedly checks, up to a maximum number of passes (default = 3), which plugins
|
|
659
|
+
* are currently able to handle the request by calling each plugin’s `canHandle()` method.
|
|
660
|
+
* - Plugins that have not yet been called in the current run and return `true` for `canHandle()`
|
|
661
|
+
* are invoked in sequence.
|
|
662
|
+
* - If a plugin returns a final `Response` or throws a `PluginFatalError`, the pipeline immediately
|
|
663
|
+
* stops and that response is returned.
|
|
664
|
+
* - If a plugin returns `null`, it may have updated the context (for example, by
|
|
665
|
+
* performing path walking), other plugins that said they `canHandle` will run.
|
|
666
|
+
* - If no plugin modifies the context (i.e. no change to `context.modified`) and no final response is
|
|
667
|
+
* produced after iterating through all plugins, the pipeline exits and a default “Not Supported”
|
|
668
|
+
* response is returned.
|
|
669
|
+
*
|
|
670
|
+
* **Diagram of the Plugin Pipeline:**
|
|
671
|
+
*
|
|
672
|
+
* ```mermaid
|
|
673
|
+
* flowchart TD
|
|
674
|
+
* A[Resource & Options] --> B[Parse into PluginContext]
|
|
675
|
+
* B --> C[Plugin Pipeline]
|
|
676
|
+
* subgraph IP[Iterative Passes max 3 passes]
|
|
677
|
+
* C1[Check canHandle for each plugin]
|
|
678
|
+
* C2[Call handle on ready plugins]
|
|
679
|
+
* C3[Update PluginContext if partial work is done]
|
|
680
|
+
* C1 --> C2
|
|
681
|
+
* C2 --> C3
|
|
682
|
+
* end
|
|
683
|
+
* C --> IP
|
|
684
|
+
* IP --> D[Final Response]
|
|
685
|
+
* ```
|
|
686
|
+
*
|
|
687
|
+
* 3. **Finalization:**
|
|
688
|
+
* - After the pipeline completes, the resulting response & context is processed (e.g. headers such as ETag,
|
|
689
|
+
* Cache‑Control, and Content‑Disposition are set) and returned.
|
|
690
|
+
*
|
|
691
|
+
* Please see the original discussion on extensibility in [Issue #167](https://github.com/ipfs/helia-verified-fetch/issues/167).
|
|
692
|
+
*
|
|
693
|
+
* ---
|
|
694
|
+
*
|
|
695
|
+
* ### Extending Verified‑Fetch with Custom Plugins
|
|
696
|
+
*
|
|
697
|
+
* To add your own plugin:
|
|
698
|
+
*
|
|
699
|
+
* 1. **Extend the BasePlugin:**
|
|
700
|
+
*
|
|
701
|
+
* Create a new class that extends `BasePlugin` and implements:
|
|
702
|
+
*
|
|
703
|
+
* - `canHandle(context: PluginContext): boolean`
|
|
704
|
+
* - `handle(context: PluginContext): Promise<Response | null>`
|
|
705
|
+
*
|
|
706
|
+
* @example custom plugin
|
|
707
|
+
*
|
|
708
|
+
* ```typescript
|
|
709
|
+
* import { BasePlugin, type PluginContext, type VerifiedFetchPluginFactory, type PluginOptions } from '@helia/verified-fetch'
|
|
710
|
+
* import { okResponse } from './dist/src/utils/responses.js'
|
|
711
|
+
*
|
|
712
|
+
* export class MyCustomPlugin extends BasePlugin {
|
|
713
|
+
* // Optionally, list any codec codes your plugin supports:
|
|
714
|
+
* codes = [] //
|
|
715
|
+
*
|
|
716
|
+
* canHandle(context: PluginContext): boolean {
|
|
717
|
+
* // Only handle requests if the Accept header matches your custom type
|
|
718
|
+
* // Or check context for pathDetails, custom values, etc...
|
|
719
|
+
* return context.accept === 'application/vnd.my-custom-type'
|
|
720
|
+
* }
|
|
721
|
+
*
|
|
722
|
+
* async handle(context: PluginContext): Promise<Response | null> {
|
|
723
|
+
* // Perform any partial processing here, e.g., modify the context:
|
|
724
|
+
* context.customProcessed = true;
|
|
725
|
+
*
|
|
726
|
+
* // If you are ready to finalize the response:
|
|
727
|
+
* return new Response('Hello, world!', {
|
|
728
|
+
* status: 200,
|
|
729
|
+
* headers: {
|
|
730
|
+
* 'Content-Type': 'text/plain'
|
|
731
|
+
* }
|
|
732
|
+
});
|
|
733
|
+
*
|
|
734
|
+
* // Or, if further processing is needed by another plugin, simply return null.
|
|
735
|
+
* }
|
|
736
|
+
* }
|
|
737
|
+
* export const myCustomPluginFactory: VerifiedFetchPluginFactory = (opts: PluginOptions) => new MyCustomPlugin(opts)
|
|
738
|
+
* ```
|
|
739
|
+
*
|
|
740
|
+
* 2. **Integrate Your Plugin:**
|
|
741
|
+
*
|
|
742
|
+
* Add your custom plugin to Verified‑Fetch’s plugin list when instantiating Verified‑Fetch:
|
|
743
|
+
*
|
|
744
|
+
* @example Integrate custom plugin
|
|
745
|
+
*
|
|
746
|
+
* ```typescript
|
|
747
|
+
* import { createVerifiedFetch, type VerifiedFetchPluginFactory } from '@helia/verified-fetch'
|
|
748
|
+
* import { createHelia } from 'helia'
|
|
749
|
+
*
|
|
750
|
+
* const helia = await createHelia()
|
|
751
|
+
* const plugins: VerifiedFetchPluginFactory[] = [
|
|
752
|
+
* // myCustomPluginFactory
|
|
753
|
+
* ]
|
|
754
|
+
*
|
|
755
|
+
* const fetch = await createVerifiedFetch(helia, { plugins })
|
|
756
|
+
* ```
|
|
757
|
+
*
|
|
758
|
+
* ---
|
|
759
|
+
*
|
|
760
|
+
* ### Error Handling in the Plugin Pipeline
|
|
761
|
+
*
|
|
762
|
+
* Verified‑Fetch distinguishes between two types of errors thrown by plugins:
|
|
763
|
+
*
|
|
764
|
+
* - **PluginError (Non‑Fatal):**
|
|
765
|
+
* - Use this when your plugin encounters an issue that should be logged but does not prevent the pipeline
|
|
766
|
+
* from continuing.
|
|
767
|
+
* - When a plugin throws a `PluginError`, the error is logged and the pipeline continues with the next plugin.
|
|
768
|
+
*
|
|
769
|
+
* - **PluginFatalError (Fatal):**
|
|
770
|
+
* - Use this when a critical error occurs that should immediately abort the request.
|
|
771
|
+
* - When a plugin throws a `PluginFatalError`, the pipeline immediately terminates and the provided error
|
|
772
|
+
* response is returned.
|
|
773
|
+
*
|
|
774
|
+
* @example Plugin error Handling
|
|
775
|
+
*
|
|
776
|
+
* ```typescript
|
|
777
|
+
* import { PluginError, PluginFatalError } from '@helia/verified-fetch'
|
|
778
|
+
*
|
|
779
|
+
* // async handle(context: PluginContext): Promise<Response | null> {
|
|
780
|
+
* const recoverable = Math.random() > 0.5 // Use more sophisticated logic here ;)
|
|
781
|
+
* if (recoverable === true) {
|
|
782
|
+
* throw new PluginError('MY_CUSTOM_WARNING', 'A non‑fatal issue occurred', {
|
|
783
|
+
* details: {
|
|
784
|
+
* someKey: 'Additional details here'
|
|
785
|
+
* }
|
|
786
|
+
* });
|
|
787
|
+
* }
|
|
788
|
+
*
|
|
789
|
+
* if (recoverable === false) {
|
|
790
|
+
* throw new PluginFatalError('MY_CUSTOM_FATAL', 'A critical error occurred', {
|
|
791
|
+
* response: new Response('Something happened', { status: 500 }) // Required: supply your own error response
|
|
792
|
+
* });
|
|
793
|
+
* }
|
|
794
|
+
*
|
|
795
|
+
* // Otherwise, continue processing...
|
|
796
|
+
* // }
|
|
797
|
+
* ```
|
|
798
|
+
*
|
|
799
|
+
* ### How the Plugin Pipeline Works
|
|
800
|
+
*
|
|
801
|
+
* - **Shared Context:**
|
|
802
|
+
* A mutable `PluginContext` is created for each request. It includes the parsed CID, path, query parameters,
|
|
803
|
+
* accept header, and any other metadata. Plugins can update this context as they perform partial work (for example,
|
|
804
|
+
* by doing path walking or decoding).
|
|
805
|
+
*
|
|
806
|
+
* - **Iterative Processing:**
|
|
807
|
+
* The pipeline repeatedly checks which plugins can currently handle the request by calling `canHandle(context)`.
|
|
808
|
+
* - Plugins that perform partial processing update the context and return `null`, allowing subsequent passes by other plugins.
|
|
809
|
+
* - Once a plugin is ready to finalize the response, it returns a final `Response` and the pipeline terminates.
|
|
810
|
+
*
|
|
811
|
+
* - **No Strict Ordering:**
|
|
812
|
+
* Plugins are invoked based solely on whether they can handle the current state of the context.
|
|
813
|
+
* This means you do not have to specify a rigid order, each plugin simply checks the context and acts if appropriate.
|
|
814
|
+
*
|
|
815
|
+
* - **Error Handling:**
|
|
816
|
+
* - A thrown `PluginError` is considered non‑fatal and is logged, allowing the pipeline to continue.
|
|
817
|
+
* - A thrown `PluginFatalError` immediately stops the pipeline and returns the error response.
|
|
818
|
+
*
|
|
819
|
+
* For a detailed explanation of the pipeline, please refer to the discussion in [Issue #167](https://github.com/ipfs/helia-verified-fetch/issues/167).
|
|
629
820
|
*/
|
|
630
821
|
import { type ResolveDNSLinkProgressEvents } from '@helia/ipns';
|
|
631
822
|
import { type ServiceMap } from '@libp2p/interface';
|
|
632
823
|
import { type HeliaInit } from 'helia';
|
|
633
824
|
import { type Libp2pOptions } from 'libp2p';
|
|
634
825
|
import { type ContentTypeParser } from './types.js';
|
|
826
|
+
import type { VerifiedFetchPluginFactory } from './plugins/types.js';
|
|
635
827
|
import type { GetBlockProgressEvents, Helia } from '@helia/interface';
|
|
636
828
|
import type { DNSResolvers } from '@multiformats/dns';
|
|
637
829
|
import type { DNSResolver } from '@multiformats/dns/resolvers';
|
|
@@ -745,6 +937,11 @@ export interface CreateVerifiedFetchOptions {
|
|
|
745
937
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing
|
|
746
938
|
*/
|
|
747
939
|
withServerTiming?: boolean;
|
|
940
|
+
/**
|
|
941
|
+
* Plugins to use with the verified-fetch instance. Note that we have a set of default plugins that are always used.
|
|
942
|
+
* If you want to replace one of the default plugins, you can do so by passing a plugin with the same name.
|
|
943
|
+
*/
|
|
944
|
+
plugins?: VerifiedFetchPluginFactory[];
|
|
748
945
|
}
|
|
749
946
|
export type { ContentTypeParser } from './types.js';
|
|
750
947
|
export type BubbledProgressEvents = ExporterProgressEvents | GetBlockProgressEvents | ResolveDNSLinkProgressEvents;
|
|
@@ -808,4 +1005,5 @@ export interface VerifiedFetchInit extends RequestInit, ProgressOptions<BubbledP
|
|
|
808
1005
|
*/
|
|
809
1006
|
export declare function createVerifiedFetch(init?: Helia | CreateVerifiedFetchInit, options?: CreateVerifiedFetchOptions): Promise<VerifiedFetch>;
|
|
810
1007
|
export { verifiedFetch } from './singleton.js';
|
|
1008
|
+
export * from './plugins/index.js';
|
|
811
1009
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmzBG;AAIH,OAAO,EAAE,KAAK,4BAA4B,EAAE,MAAM,aAAa,CAAA;AAE/D,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAEhE,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AACnD,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAA;AACzD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGnD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAA;AACpE,OAAO,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAW,MAAM,kBAAkB,CAAA;AAC9E,OAAO,KAAK,EAAE,YAAY,EAAO,MAAM,mBAAmB,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACrE;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,GAAG,CAAA;AAEnC,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,QAAQ,CAAA;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,GAAG,CAAA;IACR,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,KAAK,EAAE,KAAK,CAAA;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IACpE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAElB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,WAAW,EAAE,GAAG,YAAY,CAAA;IAE3C;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IAE9B;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IAEpB;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IAEvB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAA;CAClD;AAED,MAAM,WAAW,0BAA0B;IACzC;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IAErC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAEzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAE1B;;;OAGG;IACH,OAAO,CAAC,EAAE,0BAA0B,EAAE,CAAA;CACvC;AAED,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,MAAM,MAAM,qBAAqB,GAE/B,sBAAsB,GAEtB,sBAAsB,GAEtB,4BAA4B,CAAA;AAE9B,MAAM,MAAM,2BAA2B,GACrC,aAAa,CAAC,8BAA8B,EAAE,SAAS,CAAC,GACxD,aAAa,CAAC,6BAA6B,EAAE,MAAM,CAAC,GACpD,aAAa,CAAC,uCAAuC,EAAE,SAAS,CAAC,GACjE,aAAa,CAAC,4BAA4B,EAAE,SAAS,CAAC,GACtD,aAAa,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAA;AAE/D;;;;;;GAMG;AACH,MAAM,WAAW,iBAAkB,SAAQ,WAAW,EAAE,eAAe,CAAC,qBAAqB,GAAG,2BAA2B,CAAC;IAC1H;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IAEpB;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IAEvB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAE,IAAI,CAAC,EAAE,KAAK,GAAG,uBAAuB,EAAE,OAAO,CAAC,EAAE,0BAA0B,GAAG,OAAO,CAAC,aAAa,CAAC,CAiD/I;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,cAAc,oBAAoB,CAAA"}
|
package/dist/src/index.js
CHANGED
|
@@ -626,6 +626,197 @@
|
|
|
626
626
|
* 2. `TypeError` - If the options argument is passed and not an object.
|
|
627
627
|
* 3. `TypeError` - If the options argument is passed and is malformed.
|
|
628
628
|
* 4. `AbortError` - If the content request is aborted due to user aborting provided AbortSignal. Note that this is a `AbortError` from `@libp2p/interface` and not the standard `AbortError` from the Fetch API.
|
|
629
|
+
*
|
|
630
|
+
* ## Pluggability and Extensibility
|
|
631
|
+
*
|
|
632
|
+
* Verified‑fetch can now be extended to alter how it handles requests by using plugins.
|
|
633
|
+
* Plugins are classes that extend the `BasePlugin` class and implement the `VerifiedFetchPlugin`
|
|
634
|
+
* interface. They are instantiated with `PluginOptions` when the `VerifiedFetch` class is created.
|
|
635
|
+
*
|
|
636
|
+
* Each plugin must implement two methods:
|
|
637
|
+
*
|
|
638
|
+
* - **`canHandle(context: PluginContext): boolean`**
|
|
639
|
+
* Inspects the current `PluginContext` (which includes the CID, path, query, accept header, etc.)
|
|
640
|
+
* and returns `true` if the plugin can operate on the current state of the request.
|
|
641
|
+
*
|
|
642
|
+
* - **`handle(context: PluginContext): Promise<Response | null>`**
|
|
643
|
+
* Performs the plugin’s work. It may:
|
|
644
|
+
* - **Return a final `Response`**: This stops the pipeline immediately.
|
|
645
|
+
* - **Return `null`**: This indicates that the plugin has only partially processed the request
|
|
646
|
+
* (for example, by performing path walking or decoding) and the pipeline should continue.
|
|
647
|
+
* - **Throw a `PluginError`**: This logs a non-fatal error and continues the pipeline.
|
|
648
|
+
* - **Throw a `PluginFatalError`**: This logs a fatal error and stops the pipeline immediately.
|
|
649
|
+
*
|
|
650
|
+
* Plugins are executed in a chain (a **plugin pipeline**):
|
|
651
|
+
*
|
|
652
|
+
* 1. **Initialization:**
|
|
653
|
+
* - The `VerifiedFetch` class is instantiated with a list of plugins.
|
|
654
|
+
* - When a request is made via the `fetch` method, the resource and options are parsed to
|
|
655
|
+
* create a mutable `PluginContext` object.
|
|
656
|
+
*
|
|
657
|
+
* 2. **Pipeline Execution:**
|
|
658
|
+
* - The pipeline repeatedly checks, up to a maximum number of passes (default = 3), which plugins
|
|
659
|
+
* are currently able to handle the request by calling each plugin’s `canHandle()` method.
|
|
660
|
+
* - Plugins that have not yet been called in the current run and return `true` for `canHandle()`
|
|
661
|
+
* are invoked in sequence.
|
|
662
|
+
* - If a plugin returns a final `Response` or throws a `PluginFatalError`, the pipeline immediately
|
|
663
|
+
* stops and that response is returned.
|
|
664
|
+
* - If a plugin returns `null`, it may have updated the context (for example, by
|
|
665
|
+
* performing path walking), other plugins that said they `canHandle` will run.
|
|
666
|
+
* - If no plugin modifies the context (i.e. no change to `context.modified`) and no final response is
|
|
667
|
+
* produced after iterating through all plugins, the pipeline exits and a default “Not Supported”
|
|
668
|
+
* response is returned.
|
|
669
|
+
*
|
|
670
|
+
* **Diagram of the Plugin Pipeline:**
|
|
671
|
+
*
|
|
672
|
+
* ```mermaid
|
|
673
|
+
* flowchart TD
|
|
674
|
+
* A[Resource & Options] --> B[Parse into PluginContext]
|
|
675
|
+
* B --> C[Plugin Pipeline]
|
|
676
|
+
* subgraph IP[Iterative Passes max 3 passes]
|
|
677
|
+
* C1[Check canHandle for each plugin]
|
|
678
|
+
* C2[Call handle on ready plugins]
|
|
679
|
+
* C3[Update PluginContext if partial work is done]
|
|
680
|
+
* C1 --> C2
|
|
681
|
+
* C2 --> C3
|
|
682
|
+
* end
|
|
683
|
+
* C --> IP
|
|
684
|
+
* IP --> D[Final Response]
|
|
685
|
+
* ```
|
|
686
|
+
*
|
|
687
|
+
* 3. **Finalization:**
|
|
688
|
+
* - After the pipeline completes, the resulting response & context is processed (e.g. headers such as ETag,
|
|
689
|
+
* Cache‑Control, and Content‑Disposition are set) and returned.
|
|
690
|
+
*
|
|
691
|
+
* Please see the original discussion on extensibility in [Issue #167](https://github.com/ipfs/helia-verified-fetch/issues/167).
|
|
692
|
+
*
|
|
693
|
+
* ---
|
|
694
|
+
*
|
|
695
|
+
* ### Extending Verified‑Fetch with Custom Plugins
|
|
696
|
+
*
|
|
697
|
+
* To add your own plugin:
|
|
698
|
+
*
|
|
699
|
+
* 1. **Extend the BasePlugin:**
|
|
700
|
+
*
|
|
701
|
+
* Create a new class that extends `BasePlugin` and implements:
|
|
702
|
+
*
|
|
703
|
+
* - `canHandle(context: PluginContext): boolean`
|
|
704
|
+
* - `handle(context: PluginContext): Promise<Response | null>`
|
|
705
|
+
*
|
|
706
|
+
* @example custom plugin
|
|
707
|
+
*
|
|
708
|
+
* ```typescript
|
|
709
|
+
* import { BasePlugin, type PluginContext, type VerifiedFetchPluginFactory, type PluginOptions } from '@helia/verified-fetch'
|
|
710
|
+
* import { okResponse } from './dist/src/utils/responses.js'
|
|
711
|
+
*
|
|
712
|
+
* export class MyCustomPlugin extends BasePlugin {
|
|
713
|
+
* // Optionally, list any codec codes your plugin supports:
|
|
714
|
+
* codes = [] //
|
|
715
|
+
*
|
|
716
|
+
* canHandle(context: PluginContext): boolean {
|
|
717
|
+
* // Only handle requests if the Accept header matches your custom type
|
|
718
|
+
* // Or check context for pathDetails, custom values, etc...
|
|
719
|
+
* return context.accept === 'application/vnd.my-custom-type'
|
|
720
|
+
* }
|
|
721
|
+
*
|
|
722
|
+
* async handle(context: PluginContext): Promise<Response | null> {
|
|
723
|
+
* // Perform any partial processing here, e.g., modify the context:
|
|
724
|
+
* context.customProcessed = true;
|
|
725
|
+
*
|
|
726
|
+
* // If you are ready to finalize the response:
|
|
727
|
+
* return new Response('Hello, world!', {
|
|
728
|
+
* status: 200,
|
|
729
|
+
* headers: {
|
|
730
|
+
* 'Content-Type': 'text/plain'
|
|
731
|
+
* }
|
|
732
|
+
});
|
|
733
|
+
*
|
|
734
|
+
* // Or, if further processing is needed by another plugin, simply return null.
|
|
735
|
+
* }
|
|
736
|
+
* }
|
|
737
|
+
* export const myCustomPluginFactory: VerifiedFetchPluginFactory = (opts: PluginOptions) => new MyCustomPlugin(opts)
|
|
738
|
+
* ```
|
|
739
|
+
*
|
|
740
|
+
* 2. **Integrate Your Plugin:**
|
|
741
|
+
*
|
|
742
|
+
* Add your custom plugin to Verified‑Fetch’s plugin list when instantiating Verified‑Fetch:
|
|
743
|
+
*
|
|
744
|
+
* @example Integrate custom plugin
|
|
745
|
+
*
|
|
746
|
+
* ```typescript
|
|
747
|
+
* import { createVerifiedFetch, type VerifiedFetchPluginFactory } from '@helia/verified-fetch'
|
|
748
|
+
* import { createHelia } from 'helia'
|
|
749
|
+
*
|
|
750
|
+
* const helia = await createHelia()
|
|
751
|
+
* const plugins: VerifiedFetchPluginFactory[] = [
|
|
752
|
+
* // myCustomPluginFactory
|
|
753
|
+
* ]
|
|
754
|
+
*
|
|
755
|
+
* const fetch = await createVerifiedFetch(helia, { plugins })
|
|
756
|
+
* ```
|
|
757
|
+
*
|
|
758
|
+
* ---
|
|
759
|
+
*
|
|
760
|
+
* ### Error Handling in the Plugin Pipeline
|
|
761
|
+
*
|
|
762
|
+
* Verified‑Fetch distinguishes between two types of errors thrown by plugins:
|
|
763
|
+
*
|
|
764
|
+
* - **PluginError (Non‑Fatal):**
|
|
765
|
+
* - Use this when your plugin encounters an issue that should be logged but does not prevent the pipeline
|
|
766
|
+
* from continuing.
|
|
767
|
+
* - When a plugin throws a `PluginError`, the error is logged and the pipeline continues with the next plugin.
|
|
768
|
+
*
|
|
769
|
+
* - **PluginFatalError (Fatal):**
|
|
770
|
+
* - Use this when a critical error occurs that should immediately abort the request.
|
|
771
|
+
* - When a plugin throws a `PluginFatalError`, the pipeline immediately terminates and the provided error
|
|
772
|
+
* response is returned.
|
|
773
|
+
*
|
|
774
|
+
* @example Plugin error Handling
|
|
775
|
+
*
|
|
776
|
+
* ```typescript
|
|
777
|
+
* import { PluginError, PluginFatalError } from '@helia/verified-fetch'
|
|
778
|
+
*
|
|
779
|
+
* // async handle(context: PluginContext): Promise<Response | null> {
|
|
780
|
+
* const recoverable = Math.random() > 0.5 // Use more sophisticated logic here ;)
|
|
781
|
+
* if (recoverable === true) {
|
|
782
|
+
* throw new PluginError('MY_CUSTOM_WARNING', 'A non‑fatal issue occurred', {
|
|
783
|
+
* details: {
|
|
784
|
+
* someKey: 'Additional details here'
|
|
785
|
+
* }
|
|
786
|
+
* });
|
|
787
|
+
* }
|
|
788
|
+
*
|
|
789
|
+
* if (recoverable === false) {
|
|
790
|
+
* throw new PluginFatalError('MY_CUSTOM_FATAL', 'A critical error occurred', {
|
|
791
|
+
* response: new Response('Something happened', { status: 500 }) // Required: supply your own error response
|
|
792
|
+
* });
|
|
793
|
+
* }
|
|
794
|
+
*
|
|
795
|
+
* // Otherwise, continue processing...
|
|
796
|
+
* // }
|
|
797
|
+
* ```
|
|
798
|
+
*
|
|
799
|
+
* ### How the Plugin Pipeline Works
|
|
800
|
+
*
|
|
801
|
+
* - **Shared Context:**
|
|
802
|
+
* A mutable `PluginContext` is created for each request. It includes the parsed CID, path, query parameters,
|
|
803
|
+
* accept header, and any other metadata. Plugins can update this context as they perform partial work (for example,
|
|
804
|
+
* by doing path walking or decoding).
|
|
805
|
+
*
|
|
806
|
+
* - **Iterative Processing:**
|
|
807
|
+
* The pipeline repeatedly checks which plugins can currently handle the request by calling `canHandle(context)`.
|
|
808
|
+
* - Plugins that perform partial processing update the context and return `null`, allowing subsequent passes by other plugins.
|
|
809
|
+
* - Once a plugin is ready to finalize the response, it returns a final `Response` and the pipeline terminates.
|
|
810
|
+
*
|
|
811
|
+
* - **No Strict Ordering:**
|
|
812
|
+
* Plugins are invoked based solely on whether they can handle the current state of the context.
|
|
813
|
+
* This means you do not have to specify a rigid order, each plugin simply checks the context and acts if appropriate.
|
|
814
|
+
*
|
|
815
|
+
* - **Error Handling:**
|
|
816
|
+
* - A thrown `PluginError` is considered non‑fatal and is logged, allowing the pipeline to continue.
|
|
817
|
+
* - A thrown `PluginFatalError` immediately stops the pipeline and returns the error response.
|
|
818
|
+
*
|
|
819
|
+
* For a detailed explanation of the pipeline, please refer to the discussion in [Issue #167](https://github.com/ipfs/helia-verified-fetch/issues/167).
|
|
629
820
|
*/
|
|
630
821
|
import { bitswap, trustlessGateway } from '@helia/block-brokers';
|
|
631
822
|
import { createDelegatedRoutingV1HttpApiClient } from '@helia/delegated-routing-v1-http-api-client';
|
|
@@ -686,6 +877,7 @@ export async function createVerifiedFetch(init, options) {
|
|
|
686
877
|
return verifiedFetch;
|
|
687
878
|
}
|
|
688
879
|
export { verifiedFetch } from './singleton.js';
|
|
880
|
+
export * from './plugins/index.js';
|
|
689
881
|
function isHelia(obj) {
|
|
690
882
|
// test for the presence of known Helia properties, return a boolean value
|
|
691
883
|
return obj?.blockstore != null &&
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FatalPluginErrorOptions, PluginErrorOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* If a plugin encounters an error, it should throw an instance of this class.
|
|
4
|
+
*/
|
|
5
|
+
export declare class PluginError extends Error {
|
|
6
|
+
name: string;
|
|
7
|
+
code: string;
|
|
8
|
+
fatal: boolean;
|
|
9
|
+
details?: Record<string, any>;
|
|
10
|
+
response?: any;
|
|
11
|
+
constructor(code: string, message: string, options?: PluginErrorOptions);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* If a plugin encounters a fatal error and verified-fetch should not continue processing the request, it should throw
|
|
15
|
+
* an instance of this class.
|
|
16
|
+
*
|
|
17
|
+
* Note that you should be very careful when throwing a `PluginFatalError`, as it will stop the request from being
|
|
18
|
+
* processed further. If you do not have a response to return to the client, you should consider throwing a
|
|
19
|
+
* `PluginError` instead.
|
|
20
|
+
*/
|
|
21
|
+
export declare class PluginFatalError extends PluginError {
|
|
22
|
+
name: string;
|
|
23
|
+
constructor(code: string, message: string, options: FatalPluginErrorOptions);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/plugins/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAE7E;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;IAC7B,IAAI,SAAgB;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC7B,QAAQ,CAAC,EAAE,GAAG,CAAA;gBAER,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB;CAOzE;AAED;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;IACxC,IAAI,SAAqB;gBAEnB,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB;CAI7E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* If a plugin encounters an error, it should throw an instance of this class.
|
|
3
|
+
*/
|
|
4
|
+
export class PluginError extends Error {
|
|
5
|
+
name = 'PluginError';
|
|
6
|
+
code;
|
|
7
|
+
fatal;
|
|
8
|
+
details;
|
|
9
|
+
response;
|
|
10
|
+
constructor(code, message, options) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.fatal = options?.fatal ?? false;
|
|
14
|
+
this.details = options?.details;
|
|
15
|
+
this.response = options?.response;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* If a plugin encounters a fatal error and verified-fetch should not continue processing the request, it should throw
|
|
20
|
+
* an instance of this class.
|
|
21
|
+
*
|
|
22
|
+
* Note that you should be very careful when throwing a `PluginFatalError`, as it will stop the request from being
|
|
23
|
+
* processed further. If you do not have a response to return to the client, you should consider throwing a
|
|
24
|
+
* `PluginError` instead.
|
|
25
|
+
*/
|
|
26
|
+
export class PluginFatalError extends PluginError {
|
|
27
|
+
name = 'PluginFatalError';
|
|
28
|
+
constructor(code, message, options) {
|
|
29
|
+
super(code, message, { ...options, fatal: true });
|
|
30
|
+
this.name = 'PluginFatalError';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/plugins/errors.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC7B,IAAI,GAAG,aAAa,CAAA;IACpB,IAAI,CAAQ;IACZ,KAAK,CAAS;IACd,OAAO,CAAsB;IAC7B,QAAQ,CAAM;IAErB,YAAa,IAAY,EAAE,OAAe,EAAE,OAA4B;QACtE,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,KAAK,CAAA;QACpC,IAAI,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,CAAA;QAC/B,IAAI,CAAC,QAAQ,GAAG,OAAO,EAAE,QAAQ,CAAA;IACnC,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,gBAAiB,SAAQ,WAAW;IACxC,IAAI,GAAG,kBAAkB,CAAA;IAEhC,YAAa,IAAY,EAAE,OAAe,EAAE,OAAgC;QAC1E,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACjD,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAA;IAChC,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is the entry into all things we export from the `src/plugins` directory.
|
|
3
|
+
*/
|
|
4
|
+
export { PluginError, PluginFatalError } from './errors.js';
|
|
5
|
+
export { BasePlugin } from './plugin-base.js';
|
|
6
|
+
export type { PluginOptions, PluginContext, VerifiedFetchPluginFactory } from './types.js';
|
|
7
|
+
export * from './plugins.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAA;AAC1F,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is the entry into all things we export from the `src/plugins` directory.
|
|
3
|
+
*/
|
|
4
|
+
export { PluginError, PluginFatalError } from './errors.js';
|
|
5
|
+
export { BasePlugin } from './plugin-base.js';
|
|
6
|
+
export * from './plugins.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { VerifiedFetchPlugin, PluginContext, PluginOptions } from './types.js';
|
|
2
|
+
import type { Logger } from '@libp2p/interface';
|
|
3
|
+
/**
|
|
4
|
+
* Base class for verified-fetch plugins. This class provides a basic implementation of the `FetchHandlerPlugin`
|
|
5
|
+
* interface.
|
|
6
|
+
*
|
|
7
|
+
* Subclasses should implement the `canHandle` and `handle` methods, and may override the `codes` and `log` properties.
|
|
8
|
+
*
|
|
9
|
+
* If your plugin adds/edits the context supplied in `handle`, you should increment the `context.modified` property.
|
|
10
|
+
*/
|
|
11
|
+
export declare class BasePlugin implements VerifiedFetchPlugin {
|
|
12
|
+
readonly codes: number[];
|
|
13
|
+
readonly log: Logger;
|
|
14
|
+
readonly pluginOptions: PluginOptions;
|
|
15
|
+
constructor(options: PluginOptions);
|
|
16
|
+
canHandle(context: PluginContext): boolean;
|
|
17
|
+
handle(context: PluginContext): Promise<Response | null>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=plugin-base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-base.d.ts","sourceRoot":"","sources":["../../../src/plugins/plugin-base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACnF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE/C;;;;;;;GAOG;AACH,qBAAa,UAAW,YAAW,mBAAmB;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAK;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAA;gBACxB,OAAO,EAAE,aAAa;IAOnC,SAAS,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO;IAIrC,MAAM,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;CAGhE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for verified-fetch plugins. This class provides a basic implementation of the `FetchHandlerPlugin`
|
|
3
|
+
* interface.
|
|
4
|
+
*
|
|
5
|
+
* Subclasses should implement the `canHandle` and `handle` methods, and may override the `codes` and `log` properties.
|
|
6
|
+
*
|
|
7
|
+
* If your plugin adds/edits the context supplied in `handle`, you should increment the `context.modified` property.
|
|
8
|
+
*/
|
|
9
|
+
export class BasePlugin {
|
|
10
|
+
codes = [];
|
|
11
|
+
log;
|
|
12
|
+
pluginOptions;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
// convert a CamelCase string to a kebab-case string for the logger name of subclasses
|
|
15
|
+
const loggerName = this.constructor.name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
16
|
+
this.log = options.logger.forComponent(loggerName);
|
|
17
|
+
this.pluginOptions = options;
|
|
18
|
+
}
|
|
19
|
+
canHandle(context) {
|
|
20
|
+
throw new Error('Not implemented');
|
|
21
|
+
}
|
|
22
|
+
async handle(context) {
|
|
23
|
+
throw new Error('Not implemented');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=plugin-base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-base.js","sourceRoot":"","sources":["../../../src/plugins/plugin-base.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,OAAO,UAAU;IACZ,KAAK,GAAa,EAAE,CAAA;IACpB,GAAG,CAAQ;IACX,aAAa,CAAe;IACrC,YAAa,OAAsB;QACjC,sFAAsF;QACtF,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,WAAW,EAAE,CAAA;QAC7F,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAA;QAClD,IAAI,CAAC,aAAa,GAAG,OAAO,CAAA;IAC9B,CAAC;IAED,SAAS,CAAE,OAAsB;QAC/B,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,MAAM,CAAE,OAAsB;QAClC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BasePlugin } from './plugin-base.js';
|
|
2
|
+
import type { PluginContext } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Accepts a `CID` and returns a `Response` with a body stream that is a CAR
|
|
5
|
+
* of the `DAG` referenced by the `CID`.
|
|
6
|
+
*/
|
|
7
|
+
export declare class CarPlugin extends BasePlugin {
|
|
8
|
+
canHandle(context: PluginContext): boolean;
|
|
9
|
+
handle(context: PluginContext): Promise<Response>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=plugin-handle-car.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-handle-car.d.ts","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-car.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C;;;GAGG;AACH,qBAAa,SAAU,SAAQ,UAAU;IACvC,SAAS,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO;IAKrC,MAAM,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC;CAezD"}
|