From 09f22ee1b9cd462c6eb8bbc762ee58fdd1aa961e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenc=20S=C3=A1rai?= Date: Fri, 13 Sep 2024 07:59:57 +0200 Subject: [PATCH] feat!: add act (#942) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(act): add act * feat(act): rename addGrantees to createGrantees * feat(act): remove mention of ENS name in getGrantees method comment * feat(act): add grantee module for managing grantees * feat(act): revert import chai and jestExpect in bzz.spec.ts * feat(act): improve documentation for the createGrantees method * feat(act)!: update the return type of chunk upload to UploadResult from Reference * feat(act)!: update the return type of soc upload to UploadResult from Reference * feat(act): fix linter errors --------- Co-authored-by: Ferenc Sárai --- src/bee.ts | 69 +++++++++++++++++++- src/chunk/soc.ts | 14 +++- src/feed/index.ts | 3 +- src/feed/json.ts | 4 +- src/modules/bytes.ts | 1 + src/modules/bzz.ts | 2 + src/modules/chunk.ts | 11 +++- src/modules/grantee.ts | 68 ++++++++++++++++++++ src/modules/soc.ts | 11 +++- src/types/index.ts | 30 ++++++++- src/utils/headers.ts | 4 ++ src/utils/http.ts | 6 ++ test/integration/modules/bzz.spec.ts | 67 ++++++++++++++++++- test/integration/modules/chunk.spec.ts | 6 +- test/integration/modules/grantee.spec.ts | 82 ++++++++++++++++++++++++ test/shape/shape.spec.ts | 1 + test/unit/utils/http.spec.ts | 9 +++ test/utils.ts | 20 ++++++ 18 files changed, 386 insertions(+), 22 deletions(-) create mode 100644 src/modules/grantee.ts create mode 100644 test/integration/modules/grantee.spec.ts diff --git a/src/bee.ts b/src/bee.ts index 42a29b97..fda7b36b 100644 --- a/src/bee.ts +++ b/src/bee.ts @@ -10,6 +10,7 @@ import { makeTopic, makeTopicFromString } from './feed/topic' import { DEFAULT_FEED_TYPE, FeedType, assertFeedType } from './feed/type' import * as bytes from './modules/bytes' import * as bzz from './modules/bzz' +import * as grantee from './modules/grantee' import * as chunk from './modules/chunk' import * as balance from './modules/debug/balance' import * as chequebook from './modules/debug/chequebook' @@ -81,6 +82,8 @@ import type { UploadOptions, UploadRedundancyOptions, UploadResultWithCid, + GranteesResult, + GetGranteesResult, WalletBalance, } from './types' import { @@ -260,7 +263,7 @@ export class Bee { data: Uint8Array, options?: UploadOptions, requestOptions?: BeeRequestOptions, - ): Promise { + ): Promise { assertBatchId(postageBatchId) if (!(data instanceof Uint8Array)) { @@ -297,6 +300,68 @@ export class Bee { return chunk.download(this.getRequestOptionsForCall(options), reference) } + /** + * Create a grantees list from the given array of public keys. + * + * The grantees list can be obtained with the `getGrantees` method. + * + * @param postageBatchId - The ID of the postage batch. + * @param grantees - An array of public keys representing the grantees. + * @param requestOptions - Optional request options. + * @returns A promise that resolves to a `GranteesResult` object. + */ + async createGrantees( + postageBatchId: string | BatchId, + grantees: string[], + requestOptions?: BeeRequestOptions, + ): Promise { + assertBatchId(postageBatchId) + + return grantee.createGrantees(this.getRequestOptionsForCall(requestOptions), postageBatchId, grantees) + } + + /** + * Retrieves the grantees for a given reference. + * + * @param reference - The reference. + * @param requestOptions - Optional request options. + * @returns A promise that resolves to a `GetGranteesResult object. + */ + async getGrantees( + reference: ReferenceOrEns | string, + requestOptions?: BeeRequestOptions, + ): Promise { + return grantee.getGrantees(reference, this.getRequestOptionsForCall(requestOptions)) + } + + /** + * Updates the grantees of a specific reference and history. + * + * @param reference - The reference. + * @param history - The history. + * @param postageBatchId - The ID of the postage batch. + * @param grantees - The grantees. + * @param requestOptions - Optional request options. + * @returns A Promise that resolves to to a `GranteesResult` object. + */ + async patchGrantees( + reference: Reference | string, + histrory: Reference | string, + postageBatchId: string | BatchId, + grantees: string, + requestOptions?: BeeRequestOptions, + ): Promise { + assertBatchId(postageBatchId) + + return grantee.patchGrantees( + reference, + histrory, + postageBatchId, + grantees, + this.getRequestOptionsForCall(requestOptions), + ) + } + /** * Upload single file to a Bee node. * @@ -1024,7 +1089,7 @@ export class Bee { data: T, options?: JsonFeedOptions, requestOptions?: BeeRequestOptions, - ): Promise { + ): Promise { assertRequestOptions(options, 'JsonFeedOptions') assertBatchId(postageBatchId) diff --git a/src/chunk/soc.ts b/src/chunk/soc.ts index 53bba1f6..b28dfc84 100644 --- a/src/chunk/soc.ts +++ b/src/chunk/soc.ts @@ -1,7 +1,15 @@ import { Binary } from 'cafe-utility' import * as chunkAPI from '../modules/chunk' import * as socAPI from '../modules/soc' -import { BatchId, BeeRequestOptions, PlainBytesReference, Reference, Signature, Signer, UploadOptions } from '../types' +import { + BatchId, + BeeRequestOptions, + PlainBytesReference, + Signature, + Signer, + UploadOptions, + UploadResult, +} from '../types' import { Bytes, bytesAtOffset, bytesEqual, flexBytesAtOffset } from '../utils/bytes' import { BeeError } from '../utils/error' import { EthAddress } from '../utils/eth' @@ -130,7 +138,7 @@ export async function uploadSingleOwnerChunk( chunk: SingleOwnerChunk, postageBatchId: BatchId, options?: UploadOptions, -): Promise { +): Promise { const owner = bytesToHex(chunk.owner()) const identifier = bytesToHex(chunk.identifier()) const signature = bytesToHex(chunk.signature()) @@ -156,7 +164,7 @@ export async function uploadSingleOwnerChunkData( identifier: Identifier, data: Uint8Array, options?: UploadOptions, -): Promise { +): Promise { assertAddress(postageBatchId) const cac = makeContentAddressedChunk(data) const soc = await makeSingleOwnerChunk(cac, identifier, signer) diff --git a/src/feed/index.ts b/src/feed/index.ts index 7f91d61c..f296b8ab 100644 --- a/src/feed/index.ts +++ b/src/feed/index.ts @@ -15,6 +15,7 @@ import { Signer, Topic, UploadOptions, + UploadResult, } from '../types' import { Bytes, bytesAtOffset, makeBytes } from '../utils/bytes' import { EthAddress, HexEthAddress, makeHexEthAddress } from '../utils/eth' @@ -73,7 +74,7 @@ export async function updateFeed( reference: BytesReference, postageBatchId: BatchId, options?: FeedUploadOptions, -): Promise { +): Promise { const ownerHex = makeHexEthAddress(signer.address) const nextIndex = options?.index ?? (await findNextIndex(requestOptions, ownerHex, topic, options)) diff --git a/src/feed/json.ts b/src/feed/json.ts index 548971d7..94f3bbd9 100644 --- a/src/feed/json.ts +++ b/src/feed/json.ts @@ -6,8 +6,8 @@ import { FeedReader, FeedWriter, JsonFeedOptions, - Reference, UploadOptions, + UploadResult, } from '../types' import { isError } from '../utils/type' @@ -38,7 +38,7 @@ export async function setJsonData( data: AnyJson, options?: JsonFeedOptions & UploadOptions, requestOptions?: BeeRequestOptions, -): Promise { +): Promise { const serializedData = serializeJson(data) const { reference } = await bee.uploadData(postageBatchId, serializedData, options, requestOptions) diff --git a/src/modules/bytes.ts b/src/modules/bytes.ts index 04ec5585..c39f1360 100644 --- a/src/modules/bytes.ts +++ b/src/modules/bytes.ts @@ -44,6 +44,7 @@ export async function upload( return { reference: response.data.reference, tagUid: response.headers['swarm-tag'] ? makeTagUid(response.headers['swarm-tag']) : undefined, + history_address: response.headers['swarm-act-history-address'] || '', } } diff --git a/src/modules/bzz.ts b/src/modules/bzz.ts index c2d9453a..1706b563 100644 --- a/src/modules/bzz.ts +++ b/src/modules/bzz.ts @@ -78,6 +78,7 @@ export async function uploadFile( return { reference: response.data.reference, tagUid: response.headers['swarm-tag'] ? makeTagUid(response.headers['swarm-tag']) : undefined, + history_address: response.headers['swarm-act-history-address'] || '', } } @@ -180,5 +181,6 @@ export async function uploadCollection( return { reference: response.data.reference, tagUid: response.headers['swarm-tag'] ? makeTagUid(response.headers['swarm-tag']) : undefined, + history_address: response.headers['swarm-act-history-address'] || '', } } diff --git a/src/modules/chunk.ts b/src/modules/chunk.ts index cdcfeaf0..ef2ff11d 100644 --- a/src/modules/chunk.ts +++ b/src/modules/chunk.ts @@ -2,14 +2,15 @@ import type { BatchId, BeeRequestOptions, Data, - Reference, ReferenceOrEns, ReferenceResponse, UploadOptions, + UploadResult, } from '../types' import { wrapBytesWithHelpers } from '../utils/bytes' import { extractUploadHeaders } from '../utils/headers' import { http } from '../utils/http' +import { makeTagUid } from '../utils/type' const endpoint = 'chunks' @@ -30,7 +31,7 @@ export async function upload( data: Uint8Array, postageBatchId: BatchId, options?: UploadOptions, -): Promise { +): Promise { const response = await http(requestOptions, { method: 'post', url: `${endpoint}`, @@ -42,7 +43,11 @@ export async function upload( responseType: 'json', }) - return response.data.reference + return { + reference: response.data.reference, + tagUid: response.headers['swarm-tag'] ? makeTagUid(response.headers['swarm-tag']) : undefined, + history_address: response.headers['swarm-act-history-address'] || '', + } } /** diff --git a/src/modules/grantee.ts b/src/modules/grantee.ts new file mode 100644 index 00000000..3699692d --- /dev/null +++ b/src/modules/grantee.ts @@ -0,0 +1,68 @@ +import { BatchId, BeeRequestOptions, GetGranteesResult, GranteesResult } from '../types' +import { extractRedundantUploadHeaders } from '../utils/headers' +import { http } from '../utils/http' + +const granteeEndpoint = 'grantee' + +export async function getGrantees(reference: string, requestOptions: BeeRequestOptions): Promise { + const response = await http(requestOptions, { + method: 'get', + url: `${granteeEndpoint}/${reference}`, + responseType: 'json', + }) + + return { + status: response.status, + statusText: response.statusText, + data: response.data.data, + } +} + +export async function createGrantees( + requestOptions: BeeRequestOptions, + postageBatchId: BatchId, + grantees: string[], +): Promise { + const response = await http(requestOptions, { + method: 'post', + url: granteeEndpoint, + data: { grantees: grantees }, + headers: { + ...extractRedundantUploadHeaders(postageBatchId), + }, + responseType: 'json', + }) + + return { + status: response.status, + statusText: response.statusText, + ref: response.data.ref, + historyref: response.data.historyref, + } +} + +export async function patchGrantees( + reference: string, + historyRef: string, + postageBatchId: BatchId, + grantees: string, + requestOptions: BeeRequestOptions, +): Promise { + const response = await http(requestOptions, { + method: 'patch', + url: `${granteeEndpoint}/${reference}`, + data: grantees, + headers: { + ...extractRedundantUploadHeaders(postageBatchId), + 'swarm-act-history-address': historyRef, + }, + responseType: 'json', + }) + + return { + status: response.status, + statusText: response.statusText, + ref: response.data.ref, + historyref: response.data.historyref, + } +} diff --git a/src/modules/soc.ts b/src/modules/soc.ts index 6024c10c..2319ef15 100644 --- a/src/modules/soc.ts +++ b/src/modules/soc.ts @@ -1,6 +1,7 @@ -import { BatchId, BeeRequestOptions, Reference, ReferenceResponse, UploadOptions } from '../types' +import { BatchId, BeeRequestOptions, ReferenceResponse, UploadOptions, UploadResult } from '../types' import { extractUploadHeaders } from '../utils/headers' import { http } from '../utils/http' +import { makeTagUid } from '../utils/type' const socEndpoint = 'soc' @@ -23,7 +24,7 @@ export async function upload( data: Uint8Array, postageBatchId: BatchId, options?: UploadOptions, -): Promise { +): Promise { const response = await http(requestOptions, { method: 'post', url: `${socEndpoint}/${owner}/${identifier}`, @@ -36,5 +37,9 @@ export async function upload( params: { sig: signature }, }) - return response.data.reference + return { + reference: response.data.reference, + tagUid: response.headers['swarm-tag'] ? makeTagUid(response.headers['swarm-tag']) : undefined, + history_address: response.headers['swarm-act-history-address'] || '', + } } diff --git a/src/types/index.ts b/src/types/index.ts index 4450964c..a7f59fd3 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -101,6 +101,19 @@ export interface BeeOptions extends BeeRequestOptions { signer?: Signer | Uint8Array | string } +export interface GranteesResult { + status: number + statusText: string + ref: Reference + historyref: Reference +} + +export interface GetGranteesResult { + status: number + statusText: string + data: string[] +} + export interface UploadResultWithCid extends UploadResult { /** * Function that converts the reference into Swarm CIDs @@ -124,9 +137,19 @@ export interface UploadResult { * Automatically created tag's UID. */ tagUid?: number + + /** + * History address of the uploaded data with ACT. + */ + history_address: string } export interface UploadOptions { + /** + * If set to true, an ACT will be created for the uploaded data. + * + */ + act?: boolean /** * Will pin the data locally in the Bee node as well. * @@ -251,6 +274,7 @@ export interface CollectionUploadOptions extends UploadOptions { } export interface UploadHeaders { + 'swarm-act'?: string 'swarm-pin'?: string 'swarm-encrypt'?: string 'swarm-tag'?: string @@ -468,13 +492,13 @@ export interface FeedWriter extends FeedReader { * @param reference The reference to be stored in the new update * @param options Additional options like `at` * - * @returns Reference that points at Single Owner Chunk that contains the new update and pointer to the updated chunk reference. + * @returns UpdateResult that points at Single Owner Chunk that contains the new update and pointer to the updated chunk reference. */ upload( postageBatchId: string | BatchId, reference: BytesReference | Reference, options?: FeedUploadOptions, - ): Promise + ): Promise } /** @@ -506,7 +530,7 @@ export interface SOCWriter extends SOCReader { identifier: Identifier, data: Uint8Array, options?: UploadOptions, - ) => Promise + ) => Promise } /** diff --git a/src/utils/headers.ts b/src/utils/headers.ts index 63b78549..2607650f 100644 --- a/src/utils/headers.ts +++ b/src/utils/headers.ts @@ -53,6 +53,10 @@ export function extractUploadHeaders(postageBatchId: BatchId, options?: UploadOp 'swarm-postage-batch-id': postageBatchId, } + if (options?.act) { + headers['swarm-act'] = String(options.act) + } + if (options?.pin) { headers['swarm-pin'] = String(options.pin) } diff --git a/src/utils/http.ts b/src/utils/http.ts index b8863690..92882e3b 100644 --- a/src/utils/http.ts +++ b/src/utils/http.ts @@ -23,6 +23,12 @@ export async function http(options: BeeRequestOptions, config: AxiosRequestCo maybeRunOnRequestHook(options, requestConfig) const response = await axios(requestConfig) + // Axios does not parse array of strings as JSON + if (Array.isArray(response.data) && response.data.every(element => typeof element === 'string')) { + const array = response.data as string[] + response.data = { data: array } as any + } + // TODO: https://github.com/axios/axios/pull/6253 return response as AxiosResponse } catch (e: unknown) { diff --git a/test/integration/modules/bzz.spec.ts b/test/integration/modules/bzz.spec.ts index 3c62aabf..dfd8102a 100644 --- a/test/integration/modules/bzz.spec.ts +++ b/test/integration/modules/bzz.spec.ts @@ -3,13 +3,76 @@ import { expect as jestExpect } from 'expect' import { Readable } from 'stream' import * as bzz from '../../../src/modules/bzz' import * as tag from '../../../src/modules/tag' -import { Collection, ENCRYPTED_REFERENCE_HEX_LENGTH } from '../../../src/types' +import { BatchId, Collection, ENCRYPTED_REFERENCE_HEX_LENGTH } from '../../../src/types' import { makeCollectionFromFS } from '../../../src/utils/collection.node' -import { BIG_FILE_TIMEOUT, beeKyOptions, getPostageBatch, invalidReference, randomByteArray } from '../../utils' +import { + BIG_FILE_TIMEOUT, + actBeeKyOptions, + beeKyOptions, + getPostageBatch, + invalidReference, + randomByteArray, +} from '../../utils' +import { http } from '../../../src/utils/http' const BEE_KY_OPTIONS = beeKyOptions() describe('modules/bzz', () => { + describe('act', () => { + const data = 'hello act' + let publicKey: string + let batchID: BatchId + + before(async () => { + const responsePUBK = await http<{ publicKey: string }>(BEE_KY_OPTIONS, { + method: 'get', + url: 'addresses', + responseType: 'json', + }) + publicKey = responsePUBK.data.publicKey + + const responseBATCHID = await http<{ batchID: BatchId }>(BEE_KY_OPTIONS, { + method: 'post', + url: 'stamps/420000000/17', + responseType: 'json', + }) + batchID = responseBATCHID.data.batchID + }) + + it('should upload with act', async function () { + const result = await bzz.uploadFile(BEE_KY_OPTIONS, data, batchID, 'act-1.txt', { act: true }) + expect(result.reference).to.have.lengthOf(64) + expect(result.history_address).to.have.lengthOf(64) + }) + + it('should not be able to download without ACT header', async function () { + const result = await bzz.uploadFile(BEE_KY_OPTIONS, data, batchID, 'act-1.txt', { act: true }) + await expect(bzz.downloadFile(BEE_KY_OPTIONS, result.reference)).to.be.rejectedWith( + 'Request failed with status code 404', + ) + }) + + it('should not be able to download with ACT header but with wrong publicKey', async function () { + const result = await bzz.uploadFile(BEE_KY_OPTIONS, data, batchID, 'act-2.txt', { act: true }) + const requestOptionsBad = actBeeKyOptions( + '0x1234567890123456789012345678901234567890123456789012345678901234', + result.history_address, + '1', + ) + await expect(bzz.downloadFile(requestOptionsBad, result.reference)).rejectedWith( + 'Request failed with status code 400', + ) + }) + + it('should download with ACT and valid publicKey', async function () { + const filename = 'act-3.txt' + const result = await bzz.uploadFile(BEE_KY_OPTIONS, data, batchID, filename, { act: true }) + const requestOptionsOK = actBeeKyOptions(publicKey, result.history_address, '1') + const dFile = await bzz.downloadFile(requestOptionsOK, result.reference, filename) + expect(Buffer.from(dFile.data).toString()).to.eql(data) + }) + }) + describe('collections', () => { it('should store and retrieve collection with single file', async function () { const directoryStructure: Collection = [ diff --git a/test/integration/modules/chunk.spec.ts b/test/integration/modules/chunk.spec.ts index 53422987..2547366e 100644 --- a/test/integration/modules/chunk.spec.ts +++ b/test/integration/modules/chunk.spec.ts @@ -13,10 +13,10 @@ describe('modules/chunk', () => { // the hash is hardcoded because we would need the bmt hasher otherwise const reference = 'ca6357a08e317d15ec560fef34e4c45f8f19f01c372aa70f1da72bfa7f1a4338' - const response = await chunk.upload(BEE_KY_OPTIONS, data, getPostageBatch()) - expect(response).to.eql(reference) + const uploadResult = await chunk.upload(BEE_KY_OPTIONS, data, getPostageBatch()) + expect(uploadResult.reference).to.eql(reference) - const downloadedData = await chunk.download(BEE_KY_OPTIONS, response) + const downloadedData = await chunk.download(BEE_KY_OPTIONS, uploadResult.reference) expect(downloadedData).to.eql(data) }) diff --git a/test/integration/modules/grantee.spec.ts b/test/integration/modules/grantee.spec.ts new file mode 100644 index 00000000..476f4515 --- /dev/null +++ b/test/integration/modules/grantee.spec.ts @@ -0,0 +1,82 @@ +import { BatchId } from '../../../src/types' +import { http } from '../../../src/utils/http' +import { actBeeKyOptions, beeKyOptions } from '../../utils' +import * as bzz from '../../../src/modules/bzz' +import * as grantee from '../../../src/modules/grantee' +import { assert, expect } from 'chai' + +const BEE_KY_OPTIONS = beeKyOptions() + +describe('modules/grantee', () => { + let publicKey: string + let batchID: BatchId + + before(async () => { + const responsePUBK = await http<{ publicKey: string }>(BEE_KY_OPTIONS, { + method: 'get', + url: 'addresses', + responseType: 'json', + }) + publicKey = responsePUBK.data.publicKey + + const responseBATCHID = await http<{ batchID: BatchId }>(BEE_KY_OPTIONS, { + method: 'post', + url: 'stamps/420000000/17', + responseType: 'json', + }) + batchID = responseBATCHID.data.batchID + }) + const grantees = [ + '02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12e8', + '02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12e9', + '02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12ee', + ] + const patchGrantees = { + add: ['02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12e8'], + revoke: [ + '02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12e9', + '02ceff1422a7026ba54ad89967d81f2805a55eb3d05f64eb5c49ea6024212b12ee', + ], + } + + const patchGranteesString = JSON.stringify(patchGrantees) + it('should create grantee list', async function () { + const response = await grantee.createGrantees(BEE_KY_OPTIONS, batchID, grantees) + expect(response.ref).to.have.lengthOf(128) + expect(response.historyref).to.have.lengthOf(64) + }) + + it('should download grantee list', async function () { + const response = await grantee.createGrantees(BEE_KY_OPTIONS, batchID, grantees) + const list = await grantee.getGrantees(response.ref, BEE_KY_OPTIONS) + expect(list.data).to.have.lengthOf(grantees.length) + list.data.forEach((element: string, _index: number) => { + assert.isTrue(grantees.includes(element)) + }) + }) + + it('should patch grantee list', async function () { + const filename = 'act-4.txt' + const data = 'hello act grantees!' + const uploadResult = await bzz.uploadFile(BEE_KY_OPTIONS, data, batchID, filename, { act: true }) + + const createResponse = await grantee.createGrantees(BEE_KY_OPTIONS, batchID, grantees) + await new Promise(resolve => setTimeout(resolve, 1000)) + const patchResponse = await grantee.patchGrantees( + createResponse.ref, + uploadResult.history_address, + batchID, + patchGranteesString, + BEE_KY_OPTIONS, + ) + const list = await grantee.getGrantees(patchResponse.ref, BEE_KY_OPTIONS) + + expect(list.data).to.have.lengthOf(1) + expect(list.data[0]).to.eql(patchGrantees.add[0]) + + const requestOptionsOK = actBeeKyOptions(publicKey, patchResponse.historyref, '1') + const dFile = await bzz.downloadFile(requestOptionsOK, uploadResult.reference, filename) + + expect(Buffer.from(dFile.data).toString()).to.eql(data) + }) +}) diff --git a/test/shape/shape.spec.ts b/test/shape/shape.spec.ts index 1fa877d3..4b4fbdb3 100644 --- a/test/shape/shape.spec.ts +++ b/test/shape/shape.spec.ts @@ -21,6 +21,7 @@ import { getTimesettlementsShape } from './get-timesettlements' import { getTopologyShape } from './get-topology' import { getWalletShape } from './get-wallet' import { getWelcomeMessageShape } from './get-welcome-message' +import { test } from 'mocha' test('GET /addresses', async () => { await testGet('http://localhost:1635/addresses', getAddressesShape) diff --git a/test/unit/utils/http.spec.ts b/test/unit/utils/http.spec.ts index 710ecda1..5813d42b 100644 --- a/test/unit/utils/http.spec.ts +++ b/test/unit/utils/http.spec.ts @@ -7,6 +7,15 @@ import { MOCK_SERVER_URL } from '../nock' class ShouldHaveFailedError extends Error {} describe('http', () => { + it('should handle json with data for array', async function () { + const JSON_RESPONSE = `[1,2,5]` + + nock(MOCK_SERVER_URL).get('/endpoint').reply(200, JSON_RESPONSE) + const kyOptions = { baseURL: MOCK_SERVER_URL } + const response = await http(kyOptions, { url: 'endpoint', responseType: 'json', method: 'get' }) + await expect(response.data).to.eql(JSON.parse(JSON_RESPONSE)) + }) + it('should handle non-json response for 200', async function () { const HTML_RESPONSE = `

Some error!

` diff --git a/test/utils.ts b/test/utils.ts index 8000c3ca..17fef32d 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -157,6 +157,26 @@ export function beeKyOptions(): BeeRequestOptions { return { baseURL: beeUrl(), timeout: false } } +/** + * Creates BeeRequestOptions object with additional headers for swarm-act. + * + * @param publicKey - The public key of the publisher. + * @param historyAddress - The history address. + * @param timeStamp - The timestamp. + * @returns The BeeRequestOptions object with swarm-act headers. + */ +export function actBeeKyOptions(publicKey: string, historyAddress: string, timeStamp: string): BeeRequestOptions { + const reqOpt = beeKyOptions() + reqOpt.headers = { + 'swarm-act': 'true', + 'swarm-act-publisher': publicKey, + 'swarm-act-history-address': historyAddress, + 'swarm-act-timestamp': timeStamp, + } + + return reqOpt +} + /** * Returns a url of another peer for testing the Bee public API */