API Reference
work in progress
- container - is a collection of items
- item - is a value you want to store in a container, like a class instance
- token - is a unique string identifier for an item
Events
Section titled “Events”In a container, if you update or replace an item, users will be notified.
In React it happens automatically
const kitchenApp = new RootContainer((ctx) => ({ // you can use tokens (`oven`, `kitchen`) here and later on oven: async () => ovenContainer(), kitchen: async () => kitchenContainer(await ctx.oven()),}))
kitchenApp.on("containerCreated", (event) => { console.log(`event: 'containerCreated' ~~> token: '${event.key}'`) // `event.container` is also available here})
kitchenApp.on("containerRequested", (event) => { console.log(`event: 'containerRequested' ~~> token: '${event.key}' `)})
kitchenApp.on("containerRemoved", (event) => { console.log(`event: 'containerRemoved' ~~> token: '${event.key}' `)})
await kitchenApp.items.kitchen
// event: 'containerRequested' ~~> token: 'kitchen'// event: 'containerRequested' ~~> token: 'oven'// event: 'containerCreated' ~~> token: 'oven'// event: 'containerCreated' ~~> token: 'kitchen'
// Notice how oven was created before kitchen.// This is because kitchen depends on oven
API documentation JS / TS
Section titled “API documentation JS / TS”createContainer
Setting app root
Section titled “createContainer Setting app root”import { createContainer } from "iti"export function getMainMockAppContainer() { return createContainer().add({ kitchen: () => new Kitchen(/* deps */) })}
items
getter
Section titled “items getter”let container = getMainPizzaAppContainer()let kitchen = await container.items.kitchenkitchen.oven.pizzaCapacity // 4
getContainerSet
Section titled “getContainerSet”getContainerSetNew
Section titled “getContainerSetNew”upsert
Section titled “upsert”delete
Section titled “delete”When containers are updated React is updated too via hooks
Disposing
Section titled “Disposing”You can launch a live playground on Stackblitz
or checkout
the playground repo with the playground locally
cd iti-playgroundcat src/examples/0.disposing.ts
disposeAll(): Promise<void>
Section titled “disposeAll(): Promise<void>”Runs cleanup functions on provided (created) dependencies.
Returns a Promise that resolves when all disposers of cached resolutions have resolved.
import { createContainer } from "iti"
container = createContainer() .add({ a: () => "123" }) .addDisposer({ a: () => {} })
container.get("a") === "123" // trueawait container.disposeAll() // Promise<void>
Practical example
import { Client } from "pg"import { createContainer } from "iti"
const container = createContainer() .add(() => ({ dbConnection: async () => { const pg = new Client(process.env["DB_CONNECTION_URL"]) await pg.connect() return pg }, })) .addDisposer({ dbConnection: (dbConnection) => dbConnection.end(), })
const db = await container.get("dbConnection")await db.query("...")
// Later..await container.disposeAll()
console.log("All dependencies disposed, you can exit now. :)")
dispose(token:): Promise<void>
Section titled “dispose(token:): Promise<void>”Disposes individual container
class A {}class B {}const container = createContainer() .add({ a: () => new A(), b: () => new B(), }) .addDisposer({ a: (a) => console.log("disposing a", a), b: (a) => throw new Error("this should not be called"), })
container.get("a")// will print `disposing a A {}`container.dispose("a")
addDisposer(disposer: fn | {}): Promise<void>
Section titled “addDisposer(disposer: fn | {}): Promise<void>”import { createContainer } from "iti"
class A { dispose() {}}class B {}container = createContainer().add({ a: () => new A(), b: () => new B(),})
// Adding disposer for token `a`container.addDisposer({ a: () => {} })
// Accessing `A` instance in disposer for token `a`container.addDisposer({ a: (a: A) => a instanceof A === true,})
// Accessing ctx in disposer for token `a`container.addDisposer((ctx) => ({ a: () => ctx.b instanceof B === true,}))
import { createContainer } from "iti"import { Client } from "pg"
class A {}
createContainer() .add({ db: async () => { const pg = new Client(process.env["DB_CONNECTION_URL"]) await pg.connect() return pg }, }) .add((ctx) => ({ a: () => new A(), b: async () => { const db = await ctx.db db.query("SELECT 1") }, })) // ↓ `ctx` to access any other dependency .addDisposer((ctx) => ({ // ↓ `db` is a resolved value of a `DB` db: (db) => { console.log(ctx.a) return db.disconnect() }, }))
class B {}const container = createContainer() .add({ a: () => new A(), b: () => new B(), }) .addDisposer({ a: (a) => console.log("disposing a", a), })
container.dispose("a")
.on('containerDisposed', ({ key: string }) => void)
Section titled “.on('containerDisposed', ({ key: string }) => void)”import { createContainer } from "iti"
container = createContainer() .add({ a: () => "123" }) .addDisposer({ a: () => {} }) .on("containerDisposed", (payload) => { console.log(payload.key) // prints 'a' })
container.get("a") === "123" // trueawait container.disposeAll()
Notes on disposing
Section titled “Notes on disposing”disposal graph
Please note that .dispose('token')
doesn’t dispose child elements.
This would be risky to implement due to reasons explained in dispose-graph.ts.api.spec.ts.
In a nutshell, due to an async nature of iti
we could potentially dispose unrelated dependencies as well.
But there are a few workarounds:
you can create your custom dispose function that will dispose dependencies you care about
import { createContainer } from "iti"container = createContainer() .add({ a: () => "A", b: () => "B", }) .addDisposer((ctx) => ({ a: () => { console.log("do something to dispose a: ", ctx.a) console.log("do something to dispose b: ", ctx.b) }, }))
you can create multiple containers (createContainer
) and dispose them separately
import { createContainer } from "iti"class A {}class B {}class C {}class D { constructor(b: B) {}}const cont1 = createContainer() .add({ a: () => new A(), b: () => new B(), }) .addDisposer({ a: (a) => console.log("disposing a", a), b: (b) => console.log("disposing b", b), })
const cont2 = createContainer().add({ c: () => new C(), d: () => new D(cont1.get("b")),})
cont2.get("d") // Creates a new instance of D, which in turn creates a new instance of Bcont1.disposeAll() // Disposes B