From 56fe10a9a249fd850bf4060beeb374323f8c9b0d Mon Sep 17 00:00:00 2001 From: Teo Gebhard Date: Mon, 1 Mar 2021 15:48:54 +0200 Subject: [PATCH 1/3] Types for authFetch --- package-lock.json | 23 +++++++++++ package.json | 1 + src/dataunion/DataUnion.ts | 6 +-- src/rest/LoginEndpoints.ts | 20 ++++++--- src/rest/StreamEndpoints.ts | 48 ++++++++++++++++------ src/rest/{authFetch.js => authFetch.ts} | 15 ++++--- src/stream/index.ts | 32 +++++++++++---- test/unit/{utils.test.js => utils.test.ts} | 10 +++-- 8 files changed, 117 insertions(+), 38 deletions(-) rename src/rest/{authFetch.js => authFetch.ts} (83%) rename test/unit/{utils.test.js => utils.test.ts} (91%) diff --git a/package-lock.json b/package-lock.json index 5a1a2dda0..f3125693d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2469,6 +2469,29 @@ "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==", "dev": true }, + "@types/node-fetch": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.8.tgz", + "integrity": "sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + }, + "dependencies": { + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, "@types/normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", diff --git a/package.json b/package.json index 5ffed06f4..6ed916736 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@types/jest": "^26.0.20", "@types/lodash.uniqueid": "^4.0.6", "@types/node": "^14.14.31", + "@types/node-fetch": "^2.5.8", "@types/qs": "^6.9.5", "@types/uuid": "^8.3.0", "@typescript-eslint/eslint-plugin": "^4.15.1", diff --git a/src/dataunion/DataUnion.ts b/src/dataunion/DataUnion.ts index 70d72c1a4..a499bb387 100644 --- a/src/dataunion/DataUnion.ts +++ b/src/dataunion/DataUnion.ts @@ -92,7 +92,7 @@ export class DataUnion { /** * Send a joinRequest, or get into data union instantly with a data union secret */ - async join(secret?: string): Promise { + async join(secret?: string): Promise { const memberAddress = this.client.getAddress() as string const body: any = { memberAddress @@ -100,7 +100,7 @@ export class DataUnion { if (secret) { body.secret = secret } const url = getEndpointUrl(this.client.options.restUrl, 'dataunions', this.contractAddress, 'joinRequests') - const response = await authFetch( + const response = await authFetch( url, this.client.session, { @@ -330,7 +330,7 @@ export class DataUnion { */ async createSecret(name: string = 'Untitled Data Union Secret'): Promise { const url = getEndpointUrl(this.client.options.restUrl, 'dataunions', this.contractAddress, 'secrets') - const res = await authFetch( + const res = await authFetch<{secret: string}>( url, this.client.session, { diff --git a/src/rest/LoginEndpoints.ts b/src/rest/LoginEndpoints.ts index af281830f..4a70bf49c 100644 --- a/src/rest/LoginEndpoints.ts +++ b/src/rest/LoginEndpoints.ts @@ -3,8 +3,16 @@ import { getEndpointUrl } from '../utils' import authFetch, { AuthFetchError } from './authFetch' +export interface UserDetails { + name: string + username: string + imageUrlSmall?: string + imageUrlLarge?: string + lastLogin?: string +} + async function getSessionToken(url: string, props: any) { - return authFetch( + return authFetch<{ token: string }>( url, undefined, { @@ -30,7 +38,7 @@ export class LoginEndpoints { address, }) const url = getEndpointUrl(this.client.options.restUrl, 'login', 'challenge', address) - return authFetch( + return authFetch<{ challenge: string }>( url, undefined, { @@ -39,7 +47,7 @@ export class LoginEndpoints { ) } - async sendChallengeResponse(challenge: string, signature: string, address: string) { + async sendChallengeResponse(challenge: { challenge: string }, signature: string, address: string) { this.client.debug('sendChallengeResponse %o', { challenge, signature, @@ -98,12 +106,12 @@ export class LoginEndpoints { async getUserInfo() { this.client.debug('getUserInfo') - return authFetch(`${this.client.options.restUrl}/users/me`, this.client.session) + return authFetch(`${this.client.options.restUrl}/users/me`, this.client.session) } - async logoutEndpoint() { + async logoutEndpoint(): Promise { this.client.debug('logoutEndpoint') - return authFetch(`${this.client.options.restUrl}/logout`, this.client.session, { + await authFetch(`${this.client.options.restUrl}/logout`, this.client.session, { method: 'POST', }) } diff --git a/src/rest/StreamEndpoints.ts b/src/rest/StreamEndpoints.ts index f56e6349c..fb51677ae 100644 --- a/src/rest/StreamEndpoints.ts +++ b/src/rest/StreamEndpoints.ts @@ -13,6 +13,8 @@ import { isKeyExchangeStream } from '../stream/KeyExchange' import authFetch from './authFetch' import { Todo } from '../types' import StreamrClient from '../StreamrClient' +// TODO change this import when streamr-client-protocol exports StreamMessage type or the enums types directly +import { ContentType, EncryptionType, SignatureType, StreamMessageType } from 'streamr-client-protocol/dist/src/protocol/message_layer/StreamMessage' const debug = debugFactory('StreamrClient') @@ -30,6 +32,28 @@ export interface StreamListQuery { operation?: StreamOperation } +export interface StreamValidationInfo { + partitions: number, + requireSignedData: boolean + requireEncryptedData: boolean +} + +export interface StreamMessageAsObject { // TODO this could be in streamr-protocol + streamId: string + streamPartition: number + timestamp: number + sequenceNumber: number + publisherId: string + msgChainId: string + messageType: StreamMessageType + contentType: ContentType + encryptionType: EncryptionType + groupKeyId: string|null + content: any + signatureType: SignatureType + signature: string|null +} + const agentSettings = { keepAlive: true, keepAliveMsecs: 5000, @@ -74,7 +98,7 @@ export class StreamEndpoints { const url = getEndpointUrl(this.client.options.restUrl, 'streams', streamId) try { - const json = await authFetch(url, this.client.session) + const json = await authFetch(url, this.client.session) return new Stream(this.client, json) } catch (e) { if (e.response && e.response.status === 404) { @@ -89,8 +113,8 @@ export class StreamEndpoints { query, }) const url = getEndpointUrl(this.client.options.restUrl, 'streams') + '?' + qs.stringify(query) - const json = await authFetch(url, this.client.session) - return json ? json.map((stream: any) => new Stream(this.client, stream)) : [] + const json = await authFetch(url, this.client.session) + return json ? json.map((stream: StreamProperties) => new Stream(this.client, stream)) : [] } async getStreamByName(name: string) { @@ -110,7 +134,7 @@ export class StreamEndpoints { props, }) - const json = await authFetch( + const json = await authFetch( getEndpointUrl(this.client.options.restUrl, 'streams'), this.client.session, { @@ -153,7 +177,7 @@ export class StreamEndpoints { streamId, }) const url = getEndpointUrl(this.client.options.restUrl, 'streams', streamId, 'publishers') - const json = await authFetch(url, this.client.session) + const json = await authFetch<{ addresses: string[]}>(url, this.client.session) return json.addresses.map((a: string) => a.toLowerCase()) } @@ -180,7 +204,7 @@ export class StreamEndpoints { streamId, }) const url = getEndpointUrl(this.client.options.restUrl, 'streams', streamId, 'subscribers') - const json = await authFetch(url, this.client.session) + const json = await authFetch<{ addresses: string[] }>(url, this.client.session) return json.addresses.map((a: string) => a.toLowerCase()) } @@ -206,11 +230,11 @@ export class StreamEndpoints { streamId, }) const url = getEndpointUrl(this.client.options.restUrl, 'streams', streamId, 'validation') - const json = await authFetch(url, this.client.session) + const json = await authFetch(url, this.client.session) return json } - async getStreamLast(streamObjectOrId: Stream|string) { + async getStreamLast(streamObjectOrId: Stream|string): Promise { const { streamId, streamPartition = 0, count = 1 } = validateOptions(streamObjectOrId) this.client.debug('getStreamLast %o', { streamId, @@ -223,14 +247,14 @@ export class StreamEndpoints { + `?${qs.stringify({ count })}` ) - const json = await authFetch(url, this.client.session) + const json = await authFetch(url, this.client.session) return json } async getStreamPartsByStorageNode(address: string) { - const json = await authFetch(getEndpointUrl(this.client.options.restUrl, 'storageNodes', address, 'streams'), this.client.session) + const json = await authFetch(getEndpointUrl(this.client.options.restUrl, 'storageNodes', address, 'streams'), this.client.session) let result: StreamPart[] = [] - json.forEach((stream: { id: string, partitions: number }) => { + json.forEach((stream: StreamProperties) => { result = result.concat(StreamPart.fromStream(stream)) }) return result @@ -248,7 +272,7 @@ export class StreamEndpoints { }) // Send data to the stream - return authFetch( + await authFetch( getEndpointUrl(this.client.options.restUrl, 'streams', streamId, 'data'), this.client.session, { diff --git a/src/rest/authFetch.js b/src/rest/authFetch.ts similarity index 83% rename from src/rest/authFetch.js rename to src/rest/authFetch.ts index 7fd8b2297..55083faf4 100644 --- a/src/rest/authFetch.js +++ b/src/rest/authFetch.ts @@ -1,14 +1,18 @@ -import fetch from 'node-fetch' +import fetch, { Response } from 'node-fetch' import Debug from 'debug' import { getVersionString } from '../utils' +import Session from '../Session' export const DEFAULT_HEADERS = { 'Streamr-Client': `streamr-client-javascript/${getVersionString()}`, } export class AuthFetchError extends Error { - constructor(message, response, body) { + response: Response + body?: any + + constructor(message: string, response: Response, body?: any) { // add leading space if there is a body set const bodyMessage = body ? ` ${(typeof body === 'string' ? body : JSON.stringify(body).slice(0, 1024))}...` : '' super(message + bodyMessage) @@ -25,7 +29,7 @@ const debug = Debug('StreamrClient:utils:authfetch') // TODO: could use the debu let ID = 0 -export default async function authFetch(url, session, opts, requireNewToken = false) { +export default async function authFetch(url: string, session?: Session, opts?: any, requireNewToken = false): Promise { ID += 1 const timeStart = Date.now() const id = ID @@ -44,7 +48,7 @@ export default async function authFetch(url, session, opts, requireNewToken = fa debug('%d %s >> %o', id, url, opts) - const response = await fetch(url, { + const response: Response = await fetch(url, { ...opts, headers: { ...(session && !session.options.unauthenticated ? { @@ -54,6 +58,7 @@ export default async function authFetch(url, session, opts, requireNewToken = fa }, }) const timeEnd = Date.now() + // @ts-expect-error debug('%d %s << %d %s %s %s', id, url, response.status, response.statusText, Debug.humanize(timeEnd - timeStart)) const body = await response.text() @@ -67,7 +72,7 @@ export default async function authFetch(url, session, opts, requireNewToken = fa } } else if ([400, 401].includes(response.status) && !requireNewToken) { debug('%d %s – revalidating session') - return authFetch(url, session, options, true) + return authFetch(url, session, options, true) } else { debug('%d %s – failed', id, url) throw new AuthFetchError(`Request ${id} to ${url} returned with error code ${response.status}.`, response, body) diff --git a/src/stream/index.ts b/src/stream/index.ts index aad96d989..d6c11893e 100644 --- a/src/stream/index.ts +++ b/src/stream/index.ts @@ -5,6 +5,20 @@ import StorageNode from './StorageNode' import StreamrClient from '../StreamrClient' import { Todo } from '../types' +interface StreamPermisionBase { + operation: StreamOperation +} + +export interface UserStreamPermission extends StreamPermisionBase { + user: string +} + +export interface AnonymousStreamPermisson extends StreamPermisionBase { + anonymous: true +} + +export type StreamPermision = UserStreamPermission | AnonymousStreamPermisson + export enum StreamOperation { STREAM_GET = 'stream_get', STREAM_EDIT = 'stream_edit', @@ -59,7 +73,7 @@ export default class Stream { } async update() { - const json = await authFetch( + const json = await authFetch( getEndpointUrl(this._client.options.restUrl, 'streams', this.id), this._client.session, { @@ -82,7 +96,7 @@ export default class Stream { } async delete() { - return authFetch( + await authFetch( getEndpointUrl(this._client.options.restUrl, 'streams', this.id), this._client.session, { @@ -92,14 +106,14 @@ export default class Stream { } async getPermissions() { - return authFetch( + return authFetch( getEndpointUrl(this._client.options.restUrl, 'streams', this.id, 'permissions'), this._client.session, ) } async getMyPermissions() { - return authFetch( + return authFetch( getEndpointUrl(this._client.options.restUrl, 'streams', this.id, 'permissions', 'me'), this._client.session, ) @@ -134,7 +148,7 @@ export default class Stream { permissionObject.anonymous = true } - return authFetch( + return authFetch( getEndpointUrl(this._client.options.restUrl, 'streams', this.id, 'permissions'), this._client.session, { @@ -145,7 +159,7 @@ export default class Stream { } async revokePermission(permissionId: number) { - return authFetch( + await authFetch( getEndpointUrl(this._client.options.restUrl, 'streams', this.id, 'permissions', String(permissionId)), this._client.session, { @@ -183,7 +197,7 @@ export default class Stream { } async addToStorageNode(address: string) { - return authFetch( + await authFetch( getEndpointUrl(this._client.options.restUrl, 'streams', this.id, 'storageNodes'), this._client.session, { @@ -196,7 +210,7 @@ export default class Stream { } async removeFromStorageNode(address: string) { - return authFetch( + await authFetch( getEndpointUrl(this._client.options.restUrl, 'streams', this.id, 'storageNodes', address), this._client.session, { @@ -206,7 +220,7 @@ export default class Stream { } async getStorageNodes() { - const json = await authFetch( + const json = await authFetch<{ storageNodeAddress: string}[] >( getEndpointUrl(this._client.options.restUrl, 'streams', this.id, 'storageNodes'), this._client.session, ) diff --git a/test/unit/utils.test.js b/test/unit/utils.test.ts similarity index 91% rename from test/unit/utils.test.js rename to test/unit/utils.test.ts index f5fc089d8..5d6fad197 100644 --- a/test/unit/utils.test.js +++ b/test/unit/utils.test.ts @@ -7,6 +7,10 @@ import { uuid, getEndpointUrl } from '../../src/utils' const debug = Debug('StreamrClient::test::utils') +interface TestResponse { + test: string +} + describe('utils', () => { let session let expressApp @@ -44,7 +48,7 @@ describe('utils', () => { describe('authFetch', () => { it('should return normally when valid session token is passed', async () => { session.getSessionToken = sinon.stub().resolves('session-token') - const res = await authFetch(baseUrl + testUrl, session) + const res = await authFetch(baseUrl + testUrl, session) expect(session.getSessionToken.calledOnce).toBeTruthy() expect(res.test).toBeTruthy() }) @@ -52,7 +56,7 @@ describe('utils', () => { it('should return 401 error when invalid session token is passed twice', async () => { session.getSessionToken = sinon.stub().resolves('invalid token') const onCaught = jest.fn() - await authFetch(baseUrl + testUrl, session).catch((err) => { + await authFetch(baseUrl + testUrl, session).catch((err) => { onCaught() expect(session.getSessionToken.calledTwice).toBeTruthy() expect(err.toString()).toMatch( @@ -68,7 +72,7 @@ describe('utils', () => { session.getSessionToken.onCall(0).resolves('expired-session-token') session.getSessionToken.onCall(1).resolves('session-token') - const res = await authFetch(baseUrl + testUrl, session) + const res = await authFetch(baseUrl + testUrl, session) expect(session.getSessionToken.calledTwice).toBeTruthy() expect(res.test).toBeTruthy() }) From a32fa30ca6eed24d189312eda5c91b508c2673e3 Mon Sep 17 00:00:00 2001 From: Teo Gebhard Date: Mon, 1 Mar 2021 17:56:38 +0200 Subject: [PATCH 2/3] Types for utils.test.ts --- package-lock.json | 79 +++++++++++++++++++++++++++++++++++++++++ package.json | 2 ++ test/unit/utils.test.ts | 13 +++---- test/utils.ts | 4 +-- 4 files changed, 90 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index f3125693d..19ba7d60c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2361,6 +2361,25 @@ "@babel/types": "^7.3.0" } }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/debug": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", @@ -2393,6 +2412,29 @@ "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==", "dev": true }, + "@types/express": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz", + "integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.18", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.18.tgz", + "integrity": "sha512-m4JTwx5RUBNZvky/JJ8swEJPKFd8si08pPF2PfizYjGZOKr/svUWPcoUmLow6MmPzhasphB7gSTINY67xn3JNA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -2463,6 +2505,12 @@ "@types/lodash": "*" } }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, "@types/node": { "version": "14.14.31", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", @@ -2510,6 +2558,37 @@ "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==", "dev": true }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", + "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/sinon": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.10.tgz", + "integrity": "sha512-/faDC0erR06wMdybwI/uR8wEKV/E83T0k4sepIpB7gXuy2gzx2xiOjmztq6a2Y6rIGJ04D+6UU0VBmWy+4HEMA==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz", + "integrity": "sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg==", + "dev": true + }, "@types/stack-utils": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", diff --git a/package.json b/package.json index 6ed916736..8f8e0bd1b 100644 --- a/package.json +++ b/package.json @@ -58,11 +58,13 @@ "@babel/preset-typescript": "^7.12.17", "@tsconfig/node14": "^1.0.0", "@types/debug": "^4.1.5", + "@types/express": "^4.17.11", "@types/jest": "^26.0.20", "@types/lodash.uniqueid": "^4.0.6", "@types/node": "^14.14.31", "@types/node-fetch": "^2.5.8", "@types/qs": "^6.9.5", + "@types/sinon": "^9.0.10", "@types/uuid": "^8.3.0", "@typescript-eslint/eslint-plugin": "^4.15.1", "@typescript-eslint/parser": "^4.15.1", diff --git a/test/unit/utils.test.ts b/test/unit/utils.test.ts index 5d6fad197..491ecd113 100644 --- a/test/unit/utils.test.ts +++ b/test/unit/utils.test.ts @@ -1,9 +1,10 @@ import sinon from 'sinon' import Debug from 'debug' -import express from 'express' +import express, { Application } from 'express' import authFetch from '../../src/rest/authFetch' import { uuid, getEndpointUrl } from '../../src/utils' +import { Server } from 'http' const debug = Debug('StreamrClient::test::utils') @@ -12,9 +13,9 @@ interface TestResponse { } describe('utils', () => { - let session - let expressApp - let server + let session: any + let expressApp: Application + let server: Server const baseUrl = 'http://127.0.0.1:30000' const testUrl = '/some-test-url' @@ -23,7 +24,7 @@ describe('utils', () => { session.options = {} expressApp = express() - function handle(req, res) { + function handle(req: any, res: any) { if (req.get('Authorization') !== 'Bearer session-token') { res.sendStatus(401) } else { @@ -33,7 +34,7 @@ describe('utils', () => { } } - expressApp.get(testUrl, (req, res) => handle(req, res)) + expressApp.get(testUrl, (req: any, res: any) => handle(req, res)) server = expressApp.listen(30000, () => { debug('Mock server started on port 30000\n') diff --git a/test/utils.ts b/test/utils.ts index 7d2e92ce9..f260ca07b 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -87,7 +87,7 @@ export function getWaitForStorage(client: StreamrClient, defaultOpts = {}) { } const start = Date.now() - let last + let last: any // eslint-disable-next-line no-constant-condition let found = false while (!found) { @@ -98,7 +98,7 @@ export function getWaitForStorage(client: StreamrClient, defaultOpts = {}) { duration }, { publishRequest, - last: last.map((l: any) => l.content), + last: last!.map((l: any) => l.content), }) const err: any = new Error(`timed out after ${duration}ms waiting for message`) err.publishRequest = publishRequest From dd782a0ff4b5abbadfb79b85e413856e2bb79587 Mon Sep 17 00:00:00 2001 From: Teo Gebhard Date: Mon, 1 Mar 2021 18:42:57 +0200 Subject: [PATCH 3/3] StreamProperties --- src/rest/StreamEndpoints.ts | 5 +++-- src/stream/index.ts | 14 +++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/rest/StreamEndpoints.ts b/src/rest/StreamEndpoints.ts index fb51677ae..01c1c5a6a 100644 --- a/src/rest/StreamEndpoints.ts +++ b/src/rest/StreamEndpoints.ts @@ -252,9 +252,10 @@ export class StreamEndpoints { } async getStreamPartsByStorageNode(address: string) { - const json = await authFetch(getEndpointUrl(this.client.options.restUrl, 'storageNodes', address, 'streams'), this.client.session) + type ItemType = { id: string, partitions: number} + const json = await authFetch(getEndpointUrl(this.client.options.restUrl, 'storageNodes', address, 'streams'), this.client.session) let result: StreamPart[] = [] - json.forEach((stream: StreamProperties) => { + json.forEach((stream: ItemType) => { result = result.concat(StreamPart.fromStream(stream)) }) return result diff --git a/src/stream/index.ts b/src/stream/index.ts index d6c11893e..b0b6a0595 100644 --- a/src/stream/index.ts +++ b/src/stream/index.ts @@ -28,7 +28,19 @@ export enum StreamOperation { STREAM_SHARE = 'stream_share' } -export type StreamProperties = Todo +export interface StreamProperties { + id?: string + name?: string + description?: string + config?: { + fields: Field[]; + } + partitions?: number + requireSignedData?: boolean + requireEncryptedData?: boolean + storageDays?: number + inactivityThresholdHours?: number +} const VALID_FIELD_TYPES = ['number', 'string', 'boolean', 'list', 'map'] as const