Skip to content

Commit

Permalink
nested streams support #39, catch and pass through data marshal error #…
Browse files Browse the repository at this point in the history
  • Loading branch information
newbreedofgeek committed Sep 12, 2023
1 parent ce1d727 commit 97d3bc0
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 5 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const dataNft = new DataNft({

// Create a new DataNft object from API
const nonce = 1;
const nft = await DataNft.createFromApi(nonce);
const nft = await DataNft.createFromApi({ nonce });

// Create a new DataNft object from API Response
const response = await fetch('https://devnet-api.multiversx.com/address/nfts');
Expand All @@ -60,7 +60,7 @@ const dataNfts = [];
dataNfts = await DataNft.ownedByAddress(address);

// Retrieves the specific DataNft
const dataNft = DataNft.createFromApi(nonce);
const dataNft = DataNft.createFromApi({ nonce });

// (A) Get a message from the Data Marshal node for your to sign to prove ownership
const message = await dataNft.messageToSign();
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@itheum/sdk-mx-data-nft",
"version": "1.1.0",
"version": "1.2.0",
"description": "SDK for Itheum's Data NFT Technology on MultiversX Blockchain",
"main": "out/index.js",
"types": "out/index.d.js",
Expand Down
45 changes: 44 additions & 1 deletion src/datanft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {
createNftIdentifier,
numberToPaddedHex,
parseDataNft,
validateSpecificParamsViewData
validateSpecificParamsViewData,
checkStatus
} from './utils';
import minterAbi from './abis/datanftmint.abi.json';
import { NftType, ViewDataReturnType } from './interfaces';
Expand Down Expand Up @@ -267,6 +268,7 @@ export class DataNft {
* @param fwdAllHeaders [optional] Forward all request headers to the Origin Data Stream server.
* @param fwdHeaderKeys [optional] Forward only selected headers to the Origin Data Stream server. Has priority over fwdAllHeaders param. A comma separated lowercase string with less than 5 items. e.g. cookie,authorization
* @param fwdHeaderMapLookup [optional] Used with fwdHeaderKeys to set a front-end client side lookup map of headers the SDK uses to setup the forward. e.g. { cookie : "xyz", authorization : "Bearer zxy" }. Note that these are case-sensitive and need to match fwdHeaderKeys exactly.
* @param nestedIdxToStream [optional] If you are accessing a "nested stream", this is the index of the nested item you want drill into and fetch
*/
async viewData(p: {
signedMessage: string;
Expand All @@ -277,6 +279,7 @@ export class DataNft {
fwdHeaderMapLookup?: {
[key: string]: any;
};
nestedIdxToStream?: number;
}): Promise<ViewDataReturnType> {
DataNft.ensureNetworkConfigSet();
if (!this.dataMarshal) {
Expand All @@ -298,6 +301,7 @@ export class DataNft {
fwdAllHeaders: p.fwdAllHeaders,
fwdHeaderKeys: p.fwdHeaderKeys,
fwdHeaderMapLookup: p.fwdHeaderMapLookup,
nestedIdxToStream: p.nestedIdxToStream,
_mandatoryParamsList: ['signedMessage', 'signableMessage']
});

Expand Down Expand Up @@ -354,6 +358,10 @@ export class DataNft {
url += p.fwdAllHeaders ? '&fwdAllHeaders=1' : '';
}

if (typeof p.nestedIdxToStream !== 'undefined') {
url += `&nestedIdxToStream=${p.nestedIdxToStream}`;
}

if (typeof p.fwdHeaderKeys !== 'undefined') {
url += `&fwdHeaderKeys=${p.fwdHeaderKeys}`;

Expand All @@ -375,6 +383,20 @@ export class DataNft {
const contentType = response.headers.get('content-type');
const data = await response.blob();

// if the marshal returned a error, we should throw it here so that the SDK integrator can handle it
// ... if we don't, the marshal error response is just passed through as a normal data stream response
// ... and the user won't know what went wrong
try {
checkStatus(response);
} catch (e: any) {
// as it's a data marshal error, we get it's payload which is in JSON and send that thrown as text
const errorPayload = await (data as Blob).text();

throw new Error(
`${e.toString()}. Detailed error trace follows : ${errorPayload}`
);
}

return {
data: data,
contentType: contentType || ''
Expand All @@ -396,6 +418,7 @@ export class DataNft {
* @param fwdHeaderKeys [optional] Forward only selected headers to the Origin Data Stream server. Has priority over fwdAllHeaders param. A comma separated lowercase string with less than 5 items. e.g. cookie,authorization
* @param fwdAllHeaders [optional] Forward all request headers to the Origin Data Stream server.
* @param stream [optional] Instead of auto-downloading if possible, request if data should always be streamed or not.i.e true=stream, false/undefined=default behavior
* @param nestedIdxToStream [optional] If you are accessing a "nested stream", this is the index of the nested item you want drill into and fetch
*/
async viewDataViaMVXNativeAuth(p: {
mvxNativeAuthOrigins: string[];
Expand All @@ -406,6 +429,7 @@ export class DataNft {
fwdHeaderKeys?: string;
fwdAllHeaders?: boolean;
stream?: boolean;
nestedIdxToStream?: number;
}): Promise<ViewDataReturnType> {
try {
// S: run any format specific validation
Expand All @@ -416,6 +440,7 @@ export class DataNft {
fwdHeaderMapLookup: p.fwdHeaderMapLookup,
fwdAllHeaders: p.fwdAllHeaders,
stream: p.stream,
nestedIdxToStream: p.nestedIdxToStream,
_fwdHeaderMapLookupMustContainBearerAuthHeader: true,
_mandatoryParamsList: [
'mvxNativeAuthOrigins',
Expand Down Expand Up @@ -466,6 +491,10 @@ export class DataNft {
url += p.fwdAllHeaders ? '&fwdAllHeaders=1' : '';
}

if (typeof p.nestedIdxToStream !== 'undefined') {
url += `&nestedIdxToStream=${p.nestedIdxToStream}`;
}

// if fwdHeaderMapLookup exists, send these headers and values to the data marshal for forwarding
if (
typeof p.fwdHeaderMapLookup !== 'undefined' &&
Expand Down Expand Up @@ -495,6 +524,20 @@ export class DataNft {
const contentType = response.headers.get('content-type');
const data = await response.blob();

// if the marshal returned a error, we should throw it here so that the SDK integrator can handle it
// ... if we don't, the marshal error response is just passed through as a normal data stream response
// ... and the user won't know what went wrong
try {
checkStatus(response);
} catch (e: any) {
// as it's a data marshal error, we get it's payload which is in JSON and send that thrown as text
const errorPayload = await (data as Blob).text();

throw new Error(
`${e.toString()}. Detailed error trace follows : ${errorPayload}`
);
}

return {
data: data,
contentType: contentType || ''
Expand Down
38 changes: 37 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export function validateSpecificParamsViewData(params: {
mvxNativeAuthMaxExpirySeconds?: number | undefined;
mvxNativeAuthOrigins?: string[] | undefined;
fwdHeaderMapLookup?: any;
nestedIdxToStream?: number | undefined;
_fwdHeaderMapLookupMustContainBearerAuthHeader?: boolean | undefined;
_mandatoryParamsList: string[]; // a pure JS fallback way to validate mandatory params, as typescript rules for mandatory can be bypassed by client app
}): {
Expand Down Expand Up @@ -301,6 +302,32 @@ export function validateSpecificParamsViewData(params: {
}
}

// nestedIdxToStream test
let nestedIdxToStreamValid = true;

if (
params.nestedIdxToStream !== undefined ||
params._mandatoryParamsList.includes('nestedIdxToStream')
) {
nestedIdxToStreamValid = false;

const nestedIdxToStreamToInt =
params.nestedIdxToStream !== undefined
? parseInt(params.nestedIdxToStream.toString(), 10)
: null;

if (
nestedIdxToStreamToInt !== null &&
!isNaN(nestedIdxToStreamToInt) &&
nestedIdxToStreamToInt >= 0
) {
nestedIdxToStreamValid = true;
} else {
validationMessages +=
'[nestedIdxToStream needs to be a number more than 0]';
}
}

if (
!signedMessageValid ||
!signableMessageValid ||
Expand All @@ -309,7 +336,8 @@ export function validateSpecificParamsViewData(params: {
!fwdHeaderKeysIsValid ||
!fwdHeaderMapLookupIsValid ||
!mvxNativeAuthMaxExpirySecondsValid ||
!mvxNativeAuthOriginsIsValid
!mvxNativeAuthOriginsIsValid ||
!nestedIdxToStreamValid
) {
allPassed = false;
}
Expand Down Expand Up @@ -532,3 +560,11 @@ export async function checkUrlIsUp(url: string, expectedHttpCodes: number[]) {
);
}
}

export function checkStatus(response: Response) {
if (!(response.status >= 200 && response.status <= 299)) {
throw new Error(
`Response returned non-success HTTP code. status = ${response?.status} statusText = ${response?.statusText}`
);
}
}

0 comments on commit 97d3bc0

Please sign in to comment.