Skip to content

Commit

Permalink
Patch for http-client URL constructor (#3012)
Browse files Browse the repository at this point in the history
* Initial commit for small patch to URL constructor for ceramic http client

* Testing

* updates from pairing

* changes to http client patch from pairing session

* Edits to patch with added unit tests

* Switching client type in test to generic

* Removing unused imports in http-client.test

* Minor code cleanup and resolve of redundancies

---------

Co-authored-by: Mark Krasner <[email protected]>
Co-authored-by: Mark Krasner <[email protected]>
Co-authored-by: Mohsin Zaidi <[email protected]>
  • Loading branch information
4 people authored Nov 14, 2023
1 parent 735541f commit 45d441a
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 13 deletions.
77 changes: 69 additions & 8 deletions packages/http-client/src/__tests__/ceramic-http-client.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import { DID } from 'dids'
import { CID } from 'multiformats/cid'
import { CommitType, StreamState } from '@ceramicnetwork/common'
import { jest } from '@jest/globals'
import { fetchJson, CommitType, StreamState } from '@ceramicnetwork/common'
import { CeramicClient } from '../ceramic-http-client.js'
import { TileDocument } from '@ceramicnetwork/stream-tile'
import { randomBytes } from '@stablelib/random'
import { Ed25519Provider } from 'key-did-provider-ed25519'
import KeyResolver from 'key-did-resolver'

const API_URLS = [
`https://example.com`,
`https://example.com/`,
'https://example.com/extension',
'https://example.com/extension/',
'https://example.com/extension/another-extension',
'https://example.com/extension/another-extension/',
]

const API_URL = 'https://example.com'
const FAKE_CID_1 = CID.parse('bafybeig6xv5nwphfmvcnektpnojts33jqcuam7bmye2pb54adnrtccjlsu')

const initial = {
type: 0,
log: [
Expand All @@ -15,11 +29,58 @@ const initial = {
],
} as unknown as StreamState

describe('buildStreamFromState', () => {
test('build instance of Streamtype', async () => {
const client = new CeramicClient(API_URL)
const a = client.buildStreamFromState(initial)
expect(a).toBeInstanceOf(TileDocument)
expect(a.id.cid).toEqual(FAKE_CID_1)
const GET_RESPONSE = {
...initial,
state: initial,
}

describe('URL constructor', () => {
test('build instances of Streamtype from URLs with extensions', async () => {
for (const URL of API_URLS) {
const client = new CeramicClient(URL)
const a = client.buildStreamFromState(initial)
expect(a).toBeInstanceOf(TileDocument)
expect(a.id.cid).toEqual(FAKE_CID_1)
}
})
test('setDID()', async () => {
for (const URL of API_URLS) {
const seed = randomBytes(32)
const provider = new Ed25519Provider(seed)
const actingDid = new DID({ provider, resolver: KeyResolver.getResolver() })
await actingDid.authenticate()
const did = actingDid
const client = new CeramicClient(URL)
const getDidFn = () => {
return did
}
await client.setDID(getDidFn())
expect(client.did).toEqual(getDidFn())
}
})
test('getSupportedChains()', async () => {
for (const API_URL of API_URLS) {
const client = new CeramicClient(API_URL)

const fauxFetch = jest.fn(async () => GET_RESPONSE) as typeof fetchJson
;(client as any)._fetchJson = fauxFetch

await client.getSupportedChains()
expect(fauxFetch.mock.calls[0][0]).toEqual(new URL('./api/v0/node/chains', API_URL))
}
})
test('requestAnchor()', async () => {
for (const API_URL of API_URLS) {
const client = new CeramicClient(API_URL)
const a = client.buildStreamFromState(initial)

const fauxFetch = jest.fn(async () => GET_RESPONSE) as typeof fetchJson
;(client as any)._fetchJson = fauxFetch

await client.requestAnchor(a.id)
expect(fauxFetch.mock.calls[0][0].toString()).toEqual(
new URL(`./api/v0/streams/${a.id}/anchor`, API_URL).toString()
)
}
})
})
13 changes: 8 additions & 5 deletions packages/http-client/src/ceramic-http-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { RemoteIndexApi } from './remote-index-api.js'
import { RemoteAdminApi } from './remote-admin-api.js'
import { DummyPinApi } from './dummy-pin-api.js'

const API_PATH = '/api/v0/'
const API_PATH = './api/v0/'
const CERAMIC_HOST = 'http://localhost:7007'

/**
Expand Down Expand Up @@ -64,6 +64,8 @@ export interface CeramicClientConfig {
* Ceramic client implementation
*/
export class CeramicClient implements CeramicApi {
// Stored as a member to make it easier to inject a mock in unit tests
private readonly _fetchJson: typeof fetchJson = fetchJson
private readonly _apiUrl: URL
private _supportedChains: Array<string>

Expand All @@ -78,6 +80,7 @@ export class CeramicClient implements CeramicApi {
constructor(apiHost: string = CERAMIC_HOST, config: Partial<CeramicClientConfig> = {}) {
this._config = { ...DEFAULT_CLIENT_CONFIG, ...config }

// API_PATH contains leading dot-slash, so preserves the full path
this._apiUrl = new URL(API_PATH, apiHost)
this.context = { api: this }

Expand Down Expand Up @@ -144,7 +147,7 @@ export class CeramicClient implements CeramicApi {
})

const url = new URL('./multiqueries', this._apiUrl)
const results = await fetchJson(url, {
const results = await this._fetchJson(url, {
method: 'POST',
body: {
queries: queriesJSON,
Expand Down Expand Up @@ -189,8 +192,8 @@ export class CeramicClient implements CeramicApi {
opts: LoadOpts & AnchorOpts = {}
): Promise<AnchorStatus> {
opts = { ...DEFAULT_LOAD_OPTS, ...opts }
const { anchorStatus } = await fetchJson(
`${this._apiUrl}/streams/${streamId.toString()}/anchor`,
const { anchorStatus } = await this._fetchJson(
`${this._apiUrl}streams/${streamId.toString()}/anchor`,
{
method: 'POST',
body: {
Expand Down Expand Up @@ -233,7 +236,7 @@ export class CeramicClient implements CeramicApi {
}

// Fetch the chainId from the daemon and cache the result
const { supportedChains } = await fetchJson(this._apiUrl + '/node/chains')
const { supportedChains } = await this._fetchJson(new URL('./node/chains', this._apiUrl))
this._supportedChains = supportedChains
return supportedChains
}
Expand Down

0 comments on commit 45d441a

Please sign in to comment.