Skip to content

Commit

Permalink
feat(client): suppport headers in client
Browse files Browse the repository at this point in the history
  • Loading branch information
javadkh2 committed Oct 24, 2024
1 parent b0190ca commit edca4e4
Show file tree
Hide file tree
Showing 14 changed files with 138 additions and 42 deletions.
29 changes: 23 additions & 6 deletions packages/libs/chainweb-node-client/etc/chainweb-node-client.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export interface ILocalCommandResult {

// @alpha (undocumented)
export interface ILocalOptions {
// (undocumented)
headers?: Record<string, string>;
// (undocumented)
preflight?: boolean;
// (undocumented)
Expand Down Expand Up @@ -153,7 +155,9 @@ export interface ISPVRequestBody {
}

// @alpha
export function listen(requestBody: IListenRequestBody, apiHost: string): Promise<ICommandResult>;
export function listen(requestBody: IListenRequestBody, apiHost: string, { headers }?: {
headers?: Record<string, string>;
}): Promise<ICommandResult>;

// @alpha (undocumented)
export type ListenResponse = ICommandResult;
Expand All @@ -162,9 +166,10 @@ export type ListenResponse = ICommandResult;
export function local<T extends ILocalOptions>(requestBody: LocalRequestBody, apiHost: string, options?: T): Promise<LocalResponse<T>>;

// @alpha
export function localRaw(requestBody: LocalRequestBody, apiHost: string, { preflight, signatureVerification, }: {
export function localRaw(requestBody: LocalRequestBody, apiHost: string, { preflight, signatureVerification, headers, }: {
signatureVerification: boolean;
preflight: boolean;
headers?: Record<string, string>;
}): Promise<IPreflightResult | ICommandResult>;

// @alpha (undocumented)
Expand All @@ -191,22 +196,34 @@ export function parseResponse<T>(response: Response): Promise<T>;
export function parseResponseTEXT(response: Response): Promise<string>;

// @alpha
export function poll(requestBody: IPollRequestBody, apiHost: string, confirmationDepth?: number): Promise<IPollResponse>;
export function poll(requestBody: IPollRequestBody, apiHost: string, confirmationDepth?: number, { headers }?: {
headers?: Record<string, string>;
}): Promise<IPollResponse>;

// @alpha
export function send(requestBody: ISendRequestBody, apiHost: string): Promise<SendResponse>;
export function send(requestBody: ISendRequestBody, apiHost: string, { headers }?: {
headers?: Record<string, string>;
}): Promise<SendResponse>;

// @alpha
export type SendResponse = IRequestKeys;

// @alpha
export function spv(requestBody: ISPVRequestBody, apiHost: string): Promise<SPVResponse | Response>;
export function spv(requestBody: ISPVRequestBody, apiHost: string, { headers }?: {
headers?: Record<string, string>;
}): Promise<SPVResponse | Response>;

// @alpha
export type SPVResponse = SPVProof;

// @alpha
export function stringifyAndMakePOSTRequest<T>(body: T): object;
export function stringifyAndMakePOSTRequest<T>(body: T, headers?: Record<string, string>): {
headers: {
'Content-Type': string;
};
method: string;
body: string;
};

// (No @packageDocumentation comment for this package)

Expand Down
3 changes: 2 additions & 1 deletion packages/libs/chainweb-node-client/src/listen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import { fetch } from './utils/fetch';
export async function listen(
requestBody: IListenRequestBody,
apiHost: string,
{ headers }: { headers?: Record<string, string> } = {},
): Promise<ICommandResult> {
const request = stringifyAndMakePOSTRequest(requestBody);
const request = stringifyAndMakePOSTRequest(requestBody, headers);
const listenUrl = new URL(`${apiHost}/api/v1/listen`);

const response = await fetch(listenUrl.toString(), request);
Expand Down
17 changes: 14 additions & 3 deletions packages/libs/chainweb-node-client/src/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { fetch } from './utils/fetch';
export interface ILocalOptions {
preflight?: boolean;
signatureVerification?: boolean;
headers?: Record<string, string>;
}

/**
Expand All @@ -41,7 +42,11 @@ export async function local<T extends ILocalOptions>(
apiHost: string,
options?: T,
): Promise<LocalResponse<T>> {
const { signatureVerification = true, preflight = true } = options ?? {};
const {
signatureVerification = true,
preflight = true,
headers = {},
} = options ?? {};

if (!signatureVerification) {
requestBody = convertIUnsignedTransactionToNoSig(requestBody);
Expand All @@ -51,6 +56,7 @@ export async function local<T extends ILocalOptions>(
const result = await localRaw(body, apiHost, {
preflight,
signatureVerification,
headers,
});

return parsePreflight(result);
Expand All @@ -72,9 +78,14 @@ export async function localRaw(
{
preflight,
signatureVerification,
}: { signatureVerification: boolean; preflight: boolean },
headers = {},
}: {
signatureVerification: boolean;
preflight: boolean;
headers?: Record<string, string>;
},
): Promise<IPreflightResult | ICommandResult> {
const request = stringifyAndMakePOSTRequest(requestBody);
const request = stringifyAndMakePOSTRequest(requestBody, headers);
const localUrlWithQueries = new URL(`${apiHost}/api/v1/local`);

localUrlWithQueries.searchParams.append('preflight', preflight.toString());
Expand Down
3 changes: 2 additions & 1 deletion packages/libs/chainweb-node-client/src/poll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ export async function poll(
requestBody: IPollRequestBody,
apiHost: string,
confirmationDepth = 0,
{ headers }: { headers?: Record<string, string> } = {},
): Promise<IPollResponse> {
const request = stringifyAndMakePOSTRequest(requestBody);
const request = stringifyAndMakePOSTRequest(requestBody, headers);
const pollUrl = new URL(`${apiHost}/api/v1/poll`);
if (confirmationDepth > 0) {
pollUrl.searchParams.append(
Expand Down
3 changes: 2 additions & 1 deletion packages/libs/chainweb-node-client/src/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import { fetch } from './utils/fetch';
export async function send(
requestBody: ISendRequestBody,
apiHost: string,
{ headers }: { headers?: Record<string, string> } = {},
): Promise<SendResponse> {
const request = stringifyAndMakePOSTRequest(requestBody);
const request = stringifyAndMakePOSTRequest(requestBody, headers);
const sendUrl = new URL(`${apiHost}/api/v1/send`);

const response = await fetch(sendUrl.toString(), request);
Expand Down
3 changes: 2 additions & 1 deletion packages/libs/chainweb-node-client/src/spv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import { fetch } from './utils/fetch';
export async function spv(
requestBody: ISPVRequestBody,
apiHost: string,
{ headers }: { headers?: Record<string, string> } = {},
): Promise<SPVResponse | Response> {
const request = stringifyAndMakePOSTRequest(requestBody);
const request = stringifyAndMakePOSTRequest(requestBody, headers);
const spvUrl = new URL(`${apiHost}/spv`);

const response = await fetch(spvUrl.toString(), request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
* https://github.com/kadena-io/pact-lang-api/blob/master/pact-lang-api.js#L533
* @alpha
*/
export function stringifyAndMakePOSTRequest<T>(body: T): object {
export function stringifyAndMakePOSTRequest<T>(
body: T,
headers: Record<string, string> = {},
) {
return {
headers: {
'Content-Type': 'application/json',
...headers,
},
method: 'POST',
body: JSON.stringify(body),
Expand Down
8 changes: 7 additions & 1 deletion packages/libs/client/etc/client.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ export interface ICreateClient {
(hostAddressGenerator?: (options: {
chainId: ChainId;
networkId: string;
}) => string, defaults?: {
type?: 'local' | 'send' | 'poll' | 'listen' | 'spv';
}) => string | {
host: string;
headers: Record<string, string>;
}, defaults?: {
confirmationDepth?: number;
}): IClient;
}
Expand Down Expand Up @@ -280,6 +284,8 @@ export interface IPartialPactCommand extends AllPartial<IPactCommand> {
export interface IPollOptions {
// (undocumented)
confirmationDepth?: number;
// (undocumented)
headers?: Record<string, string>;
// Warning: (ae-incompatible-release-tags) The symbol "interval" is marked as @public, but its signature references "Milliseconds" which is marked as @alpha
//
// (undocumented)
Expand Down
2 changes: 2 additions & 0 deletions packages/libs/client/src/client/api/runPact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export function runPact(
hostUrl: string,
code: string,
data: Record<string, unknown> = {},
requestOptions: { headers?: Record<string, string> } = {},
): Promise<ICommandResult> {
const pactCommand = composePactCommand(execution(code), {
payload: { exec: { data } },
Expand All @@ -23,6 +24,7 @@ export function runPact(
{
preflight: false,
signatureVerification: false,
...requestOptions,
},
);
}
3 changes: 2 additions & 1 deletion packages/libs/client/src/client/api/spv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ export async function getSpv(
host: string,
requestKey: string,
targetChainId: ChainId,
requestOptions: { headers?: Record<string, string> } = {},
): Promise<SPVResponse> {
const proof = await spv({ requestKey, targetChainId }, host);
const proof = await spv({ requestKey, targetChainId }, host, requestOptions);
if (typeof proof !== 'string') throw new Error('PROOF_IS_NOT_AVAILABLE');
return proof;
}
Expand Down
5 changes: 4 additions & 1 deletion packages/libs/client/src/client/api/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const pollStatus: IPollStatus = (
timeout,
interval,
confirmationDepth = 0,
headers = {},
} = options ?? {};
let requestKeys = [...requestIds];
const prs: Record<string, IExtPromise<ICommandResult>> = requestKeys.reduce(
Expand All @@ -40,7 +41,9 @@ export const pollStatus: IPollStatus = (
);
const task = async (): Promise<void> => {
requestKeys.forEach(onPoll);
const pollResponse = await poll({ requestKeys }, host, confirmationDepth);
const pollResponse = await poll({ requestKeys }, host, confirmationDepth, {
headers,
});
Object.values(pollResponse).forEach((item) => {
prs[item.reqKey].resolve(item);
requestKeys = requestKeys.filter((key) => key !== item.reqKey);
Expand Down
90 changes: 67 additions & 23 deletions packages/libs/client/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,20 @@ export interface ICreateClient {
hostAddressGenerator?: (options: {
chainId: ChainId;
networkId: string;
}) => string,
type?: 'local' | 'send' | 'poll' | 'listen' | 'spv';
}) => string | { host: string; headers: Record<string, string> },
defaults?: { confirmationDepth?: number },
): IClient;
}

const getHostData = (
hostObject: string | { host: string; headers: Record<string, string> },
) => {
const hostUrl = typeof hostObject === 'string' ? hostObject : hostObject.host;
const headers = typeof hostObject === 'object' ? hostObject.headers : {};
return { hostUrl, headers };
};

/**
* Creates Chainweb client
* @public
Expand All @@ -290,6 +299,12 @@ export const createClient: ICreateClient = (
chainId: cmd.meta.chainId,
networkId: cmd.networkId,
});
if (typeof hostUrl === 'object') {
return local(body, hostUrl.host, {
...options,
headers: hostUrl.headers,
});
}
return local(body, hostUrl, options);
},
submit: (async (body) => {
Expand All @@ -300,11 +315,18 @@ export const createClient: ICreateClient = (
throw new Error('EMPTY_COMMAND_LIST');
}
const cmd: IPactCommand = JSON.parse(first.cmd);
const hostUrl = getHost({
const hostObject = getHost({
chainId: cmd.meta.chainId,
networkId: cmd.networkId,
});
const { requestKeys } = await send({ cmds: commands }, hostUrl);

const hostUrl =
typeof hostObject === 'string' ? hostObject : hostObject.host;
const headers = typeof hostObject === 'object' ? hostObject.headers : {};

const { requestKeys } = await send({ cmds: commands }, hostUrl, {
headers,
});

const transactionDescriptors = requestKeys.map((key) => ({
requestKey: key,
Expand All @@ -322,13 +344,23 @@ export const createClient: ICreateClient = (
? transactionDescriptors
: [transactionDescriptors];
const results = groupByHost(
requestsList.map(({ requestKey, chainId, networkId }) => ({
requestKey,
hostUrl: getHost({ chainId, networkId }),
})),
).map(([hostUrl, requestKeys]) =>
pollStatus(hostUrl, requestKeys, { confirmationDepth, ...options }),
);
requestsList.map(({ requestKey, chainId, networkId }) => {
const hostObject = getHost({ chainId, networkId, type: 'poll' });
const { hostUrl, headers } = getHostData(hostObject);
const host = JSON.stringify({ host: hostUrl, headers });
return {
requestKey,
host,
};
}),
).map(([host, requestKeys]) => {
const { hostUrl, headers } = JSON.parse(host);
return pollStatus(hostUrl, requestKeys, {
confirmationDepth,
...options,
headers,
});
});

// merge all of the result in one object
const mergedPollRequestPromises = mergeAllPollRequestPromises(results);
Expand All @@ -342,10 +374,15 @@ export const createClient: ICreateClient = (

const results = await Promise.all(
groupByHost(
requestsList.map(({ requestKey, chainId, networkId }) => ({
requestKey,
hostUrl: getHost({ chainId, networkId }),
})),
requestsList.map(({ requestKey, chainId, networkId }) => {
const hostObject = getHost({ chainId, networkId, type: 'poll' });
const { hostUrl, headers } = getHostData(hostObject);
const host = JSON.stringify({ host: hostUrl, headers });
return {
requestKey,
host,
};
}),
).map(([hostUrl, requestKeys]) => poll({ requestKeys }, hostUrl)),
);

Expand All @@ -356,21 +393,26 @@ export const createClient: ICreateClient = (
},

async listen({ requestKey, chainId, networkId }) {
const hostUrl = getHost({ chainId, networkId });

const result = await listen({ listen: requestKey }, hostUrl);
const hostObject = getHost({ chainId, networkId, type: 'listen' });
const { hostUrl, headers } = getHostData(hostObject);
const result = await listen({ listen: requestKey }, hostUrl, { headers });

return result;
},

pollCreateSpv({ requestKey, chainId, networkId }, targetChainId, options) {
const hostUrl = getHost({ chainId, networkId });
return pollSpv(hostUrl, requestKey, targetChainId, options);
const hostObject = getHost({ chainId, networkId, type: 'spv' });
const { hostUrl, headers } = getHostData(hostObject);
return pollSpv(hostUrl, requestKey, targetChainId, {
...options,
headers,
});
},

async createSpv({ requestKey, chainId, networkId }, targetChainId) {
const hostUrl = getHost({ chainId, networkId });
return getSpv(hostUrl, requestKey, targetChainId);
const hostObject = getHost({ chainId, networkId, type: 'spv' });
const { hostUrl, headers } = getHostData(hostObject);
return getSpv(hostUrl, requestKey, targetChainId, { headers });
},
};

Expand All @@ -396,9 +438,11 @@ export const createClient: ICreateClient = (
});
},
runPact: (code, data, options) => {
const hostUrl = getHost(options);
const hostObject = getHost(options);
const { hostUrl, headers } = getHostData(hostObject);
if (hostUrl === '') throw new Error('NO_HOST_URL');
return runPact(hostUrl, code, data);

return runPact(hostUrl, code, data, { headers });
},
send: client.submit,
getPoll: client.getStatus,
Expand Down
Loading

0 comments on commit edca4e4

Please sign in to comment.