feat: fetch options plugin (#255)
This commit is contained in:
19
README.md
19
README.md
@@ -588,6 +588,25 @@ An example - LMDB - implementation is available [here](https://github.com/warp-c
|
||||
|
||||
A dedicated CLI which eases the process of using main methods of the Warp SDK library has been created. Please refer to [`warp-contracts-cli` npm page](https://www.npmjs.com/package/warp-contracts-cli) for more details.
|
||||
|
||||
### Customize `fetch` options
|
||||
|
||||
It is possible to customize `fetch` options using dedicated plugin. In order to change `fetch` options one needs to create an implementation of [WarpPlugin](https://github.com/warp-contracts/warp/blob/main/src/core/WarpPlugin.ts) interface. `process` method will receive following properties:
|
||||
|
||||
```ts
|
||||
interface FetchRequest {
|
||||
input: RequestInfo | URL;
|
||||
init: Partial<RequestInit>;
|
||||
}
|
||||
```
|
||||
|
||||
...and it should return updated `fetch` options (by returning updated `init` object). An example of such implementation in [src/tools/fetch-options-plugin.ts](https://github.com/warp-contracts/warp/tree/main/tools/fetch-options-plugin.ts).
|
||||
|
||||
In order to use this plugin, it needs to be attached while creating `Warp` instance, e.g.:
|
||||
|
||||
```ts
|
||||
const warp = WarpFactory.forMainnet().use(new FetchOptionsPlugin());
|
||||
```
|
||||
|
||||
### Migrations
|
||||
|
||||
#### old factories to WarpFactory
|
||||
|
||||
@@ -36,6 +36,7 @@ import { generateMockVrf } from '../utils/vrf';
|
||||
import { Signature, SignatureType } from './Signature';
|
||||
import { ContractDefinition } from '../core/ContractDefinition';
|
||||
import { EvaluationOptionsEvaluator } from './EvaluationOptionsEvaluator';
|
||||
import { WarpFetchWrapper } from '../core/WarpFetchWrapper';
|
||||
|
||||
/**
|
||||
* An implementation of {@link Contract} that is backwards compatible with current style
|
||||
@@ -59,6 +60,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
private _sorter: InteractionsSorter;
|
||||
private _rootSortKey: string;
|
||||
private signature: Signature;
|
||||
private warpFetchWrapper: WarpFetchWrapper;
|
||||
|
||||
constructor(
|
||||
private readonly _contractTxId: string,
|
||||
@@ -113,6 +115,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
}
|
||||
|
||||
this.getCallStack = this.getCallStack.bind(this);
|
||||
this.warpFetchWrapper = new WarpFetchWrapper(this.warp);
|
||||
}
|
||||
|
||||
async readState(
|
||||
@@ -301,7 +304,8 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
options.vrf
|
||||
);
|
||||
|
||||
const response = await fetch(`${this._evaluationOptions.sequencerUrl}gateway/sequencer/register`, {
|
||||
const response = await this.warpFetchWrapper
|
||||
.fetch(`${this._evaluationOptions.sequencerUrl}gateway/sequencer/register`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(interactionTx),
|
||||
headers: {
|
||||
@@ -746,7 +750,8 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
|
||||
async syncState(externalUrl: string, params?: any): Promise<Contract> {
|
||||
const { stateEvaluator } = this.warp;
|
||||
const response = await fetch(
|
||||
const response = await this.warpFetchWrapper
|
||||
.fetch(
|
||||
`${externalUrl}?${new URLSearchParams({
|
||||
id: this._contractTxId,
|
||||
...params
|
||||
|
||||
@@ -2,11 +2,20 @@
|
||||
import Arweave from 'arweave';
|
||||
import Transaction from 'arweave/node/lib/transaction';
|
||||
import { Signature, SignatureType } from '../../../contract/Signature';
|
||||
import { WarpFetchWrapper } from '../../../core/WarpFetchWrapper';
|
||||
import { SmartWeaveTags } from '../../../core/SmartWeaveTags';
|
||||
import { Warp } from '../../../core/Warp';
|
||||
import { WARP_GW_URL } from '../../../core/WarpFactory';
|
||||
import { LoggerFactory } from '../../../logging/LoggerFactory';
|
||||
import { CreateContract, ContractData, ContractDeploy, FromSrcTxContractData, ArWallet, BundlrNodeType, BUNDLR_NODES } from '../CreateContract';
|
||||
import {
|
||||
CreateContract,
|
||||
ContractData,
|
||||
ContractDeploy,
|
||||
FromSrcTxContractData,
|
||||
ArWallet,
|
||||
BundlrNodeType,
|
||||
BUNDLR_NODES
|
||||
} from '../CreateContract';
|
||||
import { SourceData, SourceImpl } from './SourceImpl';
|
||||
import { Buffer } from 'redstone-isomorphic';
|
||||
|
||||
@@ -15,10 +24,12 @@ export class DefaultCreateContract implements CreateContract {
|
||||
private readonly source: SourceImpl;
|
||||
|
||||
private signature: Signature;
|
||||
private readonly warpFetchWrapper: WarpFetchWrapper;
|
||||
|
||||
constructor(private readonly arweave: Arweave, private warp: Warp) {
|
||||
this.deployFromSourceTx = this.deployFromSourceTx.bind(this);
|
||||
this.source = new SourceImpl(this.warp);
|
||||
this.warpFetchWrapper = new WarpFetchWrapper(this.warp);
|
||||
}
|
||||
|
||||
async deploy(contractData: ContractData, disableBundling?: boolean): Promise<ContractDeploy> {
|
||||
@@ -190,7 +201,7 @@ export class DefaultCreateContract implements CreateContract {
|
||||
};
|
||||
}
|
||||
|
||||
const response = await fetch(`${WARP_GW_URL}/gateway/contracts/deploy`, {
|
||||
const response = await this.warpFetchWrapper.fetch(`${WARP_GW_URL}/gateway/contracts/deploy`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
headers: {
|
||||
|
||||
37
src/core/WarpFetchWrapper.ts
Normal file
37
src/core/WarpFetchWrapper.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { LoggerFactory } from '../logging/LoggerFactory';
|
||||
import { Warp } from './Warp';
|
||||
|
||||
export interface FetchRequest {
|
||||
input: RequestInfo | URL;
|
||||
init: Partial<RequestInit>;
|
||||
}
|
||||
|
||||
export class WarpFetchWrapper {
|
||||
private readonly name = 'WarpFetchWrapper';
|
||||
private readonly logger = LoggerFactory.INST.create(this.name);
|
||||
|
||||
constructor(private warp: Warp) {
|
||||
this.warp = warp;
|
||||
}
|
||||
|
||||
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
|
||||
let fetchOptions: RequestInit;
|
||||
|
||||
if (this.warp.hasPlugin('fetch-options')) {
|
||||
const fetchOptionsPlugin = this.warp.loadPlugin<FetchRequest, Partial<RequestInit>>('fetch-options');
|
||||
try {
|
||||
const updatedFetchOptions = fetchOptionsPlugin.process({ input, init: init || {} });
|
||||
fetchOptions = { ...init, ...updatedFetchOptions };
|
||||
} catch (e) {
|
||||
if (e.message) {
|
||||
this.logger.error(e.message);
|
||||
}
|
||||
throw new Error(`Unable to process fetch options: ${e.message}`);
|
||||
}
|
||||
} else {
|
||||
fetchOptions = init;
|
||||
}
|
||||
|
||||
return fetch(input, fetchOptions);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@ export const knownWarpPlugins = [
|
||||
'smartweave-extension-ethers',
|
||||
'subscription',
|
||||
'ivm-handler-api',
|
||||
'evaluation-progress'
|
||||
'evaluation-progress',
|
||||
'fetch-options'
|
||||
] as const;
|
||||
export type WarpPluginType = typeof knownWarpPlugins[number];
|
||||
|
||||
|
||||
70
tools/fetch-options-plugin.ts
Normal file
70
tools/fetch-options-plugin.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { WarpPlugin, WarpPluginType } from '../src/core/WarpPlugin';
|
||||
import { FetchRequest } from '../src/core/WarpFetchWrapper';
|
||||
import { JWKInterface } from 'arweave/node/lib/wallet';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { LoggerFactory } from '../src/logging/LoggerFactory';
|
||||
import { defaultCacheOptions, WarpFactory } from '../src/core/WarpFactory';
|
||||
|
||||
class FetchOptionsPlugin implements WarpPlugin<FetchRequest, RequestInit> {
|
||||
process(request: FetchRequest): Partial<RequestInit> {
|
||||
const url = request.input;
|
||||
|
||||
let fetchOptions: Partial<RequestInit> = {};
|
||||
|
||||
if (url == `https://d1o5nlqr4okus2.cloudfront.net/gateway/sequencer/register`) {
|
||||
fetchOptions = {
|
||||
keepalive: true
|
||||
};
|
||||
}
|
||||
|
||||
return fetchOptions;
|
||||
}
|
||||
|
||||
type(): WarpPluginType {
|
||||
return 'fetch-options';
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const wallet: JWKInterface = readJSON('./.secrets/jwk.json');
|
||||
LoggerFactory.INST.logLevel('debug');
|
||||
const logger = LoggerFactory.INST.create('FetchOptionsPlugin');
|
||||
|
||||
try {
|
||||
const warp = WarpFactory.forMainnet({ ...defaultCacheOptions, inMemory: true }).use(new FetchOptionsPlugin());
|
||||
|
||||
const jsContractSrc = fs.readFileSync(path.join(__dirname, 'data/js/token-pst.js'), 'utf8');
|
||||
const initialState = fs.readFileSync(path.join(__dirname, 'data/js/token-pst.json'), 'utf8');
|
||||
|
||||
const { contractTxId } = await warp.createContract.deploy({
|
||||
wallet,
|
||||
initState: initialState,
|
||||
src: jsContractSrc
|
||||
});
|
||||
|
||||
const contract = warp.contract(contractTxId).connect(wallet);
|
||||
|
||||
await contract.writeInteraction({
|
||||
function: 'transfer',
|
||||
target: 'uhE-QeYS8i4pmUtnxQyHD7dzXFNaJ9oMK-IM-QPNY6M',
|
||||
qty: 55555
|
||||
});
|
||||
|
||||
const { cachedValue } = await contract.readState();
|
||||
logger.info(`Cached value: ${cachedValue}`);
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export function readJSON(path: string): JWKInterface {
|
||||
const content = fs.readFileSync(path, 'utf-8');
|
||||
try {
|
||||
return JSON.parse(content);
|
||||
} catch (e) {
|
||||
throw new Error(`File "${path}" does not contain a valid JSON`);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => console.error(e));
|
||||
Reference in New Issue
Block a user