Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Discussion: IPFS.create({ ... }) should return same API regardless of the init and start options. #3285

Closed
@Gozala

Description

@Gozala

At the moment IPFS.create will return API object that has different interface depending on init and start options:

const { api } = apiManager.update({
init: Components.init({ apiManager, print, options }),
dns: Components.dns(),
isOnline: Components.isOnline({ libp2p: undefined })
}, async () => { throw new NotInitializedError() }) // eslint-disable-line require-await
const initializedApi = options.init && await api.init()
const startedApi = options.start && initializedApi && await initializedApi.start()
/**
* @template T, THEN, ELSE
* @typedef {NonNullable<T> extends false
* ? THEN : ELSE } IsFalse
*/
/** @type {IsFalse<INIT, typeof api, IsFalse<START, typeof initializedApi, typeof startedApi>>} */
// @ts-ignore
const ipfs = startedApi || initializedApi || api
return ipfs

It is kind of cool that one could do that in JS (and even make TS infer it properly), but I think it has enough drawbacks that I would like to make an argument against it:

  1. It is difficult to document this kind of behavior. In fact documentation seems to incorrectly suggest that it returned object will implement IPFS Core API. And only vaguely mentions that initialization is different from creating because many special properties are set during initialization.
  2. Unsurprisingly (per @lidel) some (of even our) code assumes that returned API object implements same interface.
  3. This introduces side effects into the system. Some APIs will not be available before init and will be after init. This specific aspet is impossible to type in TS because types can just change in side effect of a call.
  4. I think this is primary reason for ApiManager which introduces quite a bit complexity in exchange for unclear (at least to me) benefits.

I understand that IPFS node can not provide all the core functionality when it's not initialized / started. However I would propose to either (or both):

  1. Have the same core API and throw error e.g. not initialized / not started error(s) when specific functionality is in-operational.
  2. Have a way to distinguish between 'unitialized | started | initialized' states so that function that is passed IPFS API object can asses what API subset can be used (without try catch or subapi in)
  3. Have a different factory functions, for different API objects.
  4. Remove side effects e.g. api.init() can return InitilaizedAPI instance, without mutating the api itself.

Metadata

Metadata

Assignees

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions