### Core Container Setup Example Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/migration.mdx This example demonstrates the setup of a core container using `createContainer` and adding dependencies like configuration, authentication service, and an API client. ```tsx import { createContainer } from "iti" export const createAppContainer = () => createContainer().add({ config: () => ({ apiUrl: process.env.API_URL, }), authService: async () => { const res = await fetch("/api/auth") return res.json() }, apiClient: (ctx) => new ApiClient(ctx.config.apiUrl), }) export type AppContainer = ReturnType ``` -------------------------------- ### Manual Dependency Injection Example Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/advanced/when-not-to-use-iti.md Demonstrates a basic manual dependency injection setup without a framework. Ensure Logger and UserData are properly implemented and instantiated. ```typescript export class PaymentService { constructor( private readonly logger: Logger, private readonly user: UserData ) {} sendMoney() { this.logger.info(`Sending money to the: ${this.user.name} `) return true } } const logger = new PinoLogger() const userData = getUserDataFromCookies() const ps = new PaymentService(logger, userData) ``` -------------------------------- ### Install ITI with bun Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/quick-start.mdx Install the ITI framework and its React bindings using bun. ```bash bun add iti iti-react ``` -------------------------------- ### Install Dependencies Source: https://github.com/molszanski/iti/blob/master/website/README.md Run this command in the root of your project to install all necessary dependencies. ```bash pnpm install ``` -------------------------------- ### React Hooks Setup Example Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/migration.mdx Sets up React context and hooks for the application container. It imports `getContainerHooks` from `iti-react` and exports updated `useItem` and `useItems` hooks. ```tsx import React from "react" import { getContainerHooks } from "iti-react" // ✨ Updated import { AppContainer } from "./app-container" export const AppContext = React.createContext(null) const hooks = getContainerHooks(AppContext) export const useItem = hooks.useItem // ✨ Updated export const useItems = hooks.useItems // ✨ Updated ``` -------------------------------- ### Install ITI with yarn Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/quick-start.mdx Install the ITI framework and its React bindings using yarn. ```bash yarn add iti iti-react ``` -------------------------------- ### Install ITI with npm Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/quick-start.mdx Install the ITI framework and its React bindings using npm. ```bash npm install -S iti iti-react ``` -------------------------------- ### Install Iti Core and React Bindings Source: https://context7.com/molszanski/iti/llms.txt Install the core 'iti' library and the optional 'iti-react' bindings using your preferred package manager. ```bash # npm npm install -S iti iti-react # pnpm pnpm add iti iti-react # yarn yarn add iti iti-react # bun bun add iti iti-react ``` -------------------------------- ### Install iti-react Source: https://github.com/molszanski/iti/blob/master/iti-react/README.md Install the iti-react package using npm. ```bash npm install -S iti-react ``` -------------------------------- ### Install ITI with pnpm Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/quick-start.mdx Install the ITI framework and its React bindings using pnpm. ```bash pnpm add iti iti-react ``` -------------------------------- ### Start Local Development Server Source: https://github.com/molszanski/iti/blob/master/website/README.md This command starts a local development server, typically accessible at `localhost:4321`. ```bash pnpm dev ``` -------------------------------- ### Use Multiple Containers with Auto-Subscription Source: https://github.com/molszanski/iti/blob/master/iti-react/README.md This example shows how to use `useContainerSet` to get multiple containers ('kitchen', 'auth') and automatically subscribe to changes. It displays data from the 'kitchen' container. ```tsx export const PizzaData = () => { const containerSet = useContainerSet((containers) => [ containers.kitchen, containers.auth, ]) if (!containerSet) { return <>Kitchen is loading } return <>{containerSet.kitchen.oven.pizzasInOven} } ``` -------------------------------- ### Create New Astro Project with Basics Template Source: https://github.com/molszanski/iti/blob/master/examples/astro-playground/README.md Use this command to initialize a new Astro project with the 'basics' template. This is the starting point for building your Astro website. ```sh yarn create astro@latest -- --template basics ``` -------------------------------- ### ITI vs. Without ITI Example Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/quick-start.mdx Compares code structure with and without ITI for asynchronous operations. The 'withIti' example demonstrates how ITI simplifies dependency management. ```tsx import { createContainer, InjectionToken } from "iti"; interface UserData { name: string; } const userDataToken: InjectionToken = "userData"; const app = createContainer({ items: { userData: async () => { const response = await fetch("/api/user"); return response.json(); }, }, }); export const useItem = () => app.useItems(); ``` ```ts const userData = await fetch("/api/user").then(res => res.json()); ``` -------------------------------- ### Before: Get and Subscribe to Multiple Items (v0.7.x) Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/migration.mdx Demonstrates how to get multiple items and subscribe to changes using the older API names in v0.7.x. ```typescript import { createContainer } from "iti" const container = createContainer().add({ serviceA: () => new ServiceA(), serviceB: () => new ServiceB(), }) // Get multiple items const items = await container.getContainerSet(["serviceA", "serviceB"]) // Subscribe to changes container.subscribeToContainer("serviceA", (err, service) => { console.log("Service A updated") }) container.subscribeToContainerSet(["serviceA", "serviceB"], (err, items) => { console.log("Services updated") }) ``` -------------------------------- ### Create Starlight Project Source: https://github.com/molszanski/iti/blob/master/website/README.md Use this command to create a new Astro project with the Starlight template. Ensure you have pnpm installed. ```bash pnpm create astro@latest -- --template starlight ``` -------------------------------- ### Manual DI Setup and Execution Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/guides/async-di/manual-di.mdx Illustrates manual dependency injection by creating instances of services and their dependencies. It shows how to conditionally instantiate a logger based on the environment and then uses these instances to create other services, demonstrating a complete application flow. ```typescript // prettier-ignore interface Logger { info: (msg: string) => void } // prettier-ignore class ConsoleLogger implements Logger { info(msg: string): void { console.log("[Console]:", msg) } } // prettier-ignore class PinoLogger implements Logger { info(msg: string): void { console.log("[Pino]:" , msg) } } // Part 1: Business Entities interface UserData { name: string } class AuthService { async getUserData(): Promise { return { name: "Big Lebowski" } } } class User { constructor(private data: UserData) {} name = () => this.data.name } class PaymentService { constructor(private readonly logger: Logger, private readonly user: User) {} sendMoney() { this.logger.info(`Sending monery to the: ${this.user.name()} `) return true } } // Step 2: Manual DI export async function runMyApp() { const logger = process.env.NODE_ENV === "production" ? new PinoLogger() : new ConsoleLogger() const auth = new AuthService() const user = new User(await auth.getUserData()) const paymentService = new PaymentService(logger, user) paymentService.sendMoney() } console.log(" ---- My App START \n\n") runMyApp().then(() => { console.log("\n\n ---- My App END") }) ``` -------------------------------- ### ITI Usage Example Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/quick-start.mdx Demonstrates how to access and use services from the ITI container. It shows lazy fetching of the 'paymentService'. ```tsx // Part 3: Usage import { app } from "./app"; // Will lazily fetch data and create PaymentService instance const paymentService = await app.items.paymentService; paymentService.sendMoney(); ``` -------------------------------- ### ITI Container Setup Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/quick-start.mdx Sets up the main application container using ITI, integrating business logic and other dependencies. This defines the 'app' instance. ```ts import { createContainer } from "iti"; import { businessLogic } from "./business-logic"; export const app = createContainer({ items: { ...businessLogic, }, }); ``` -------------------------------- ### Get Astro CLI Help Source: https://github.com/molszanski/iti/blob/master/website/README.md Displays help information for the Astro CLI, useful for understanding available commands and options. ```bash pnpm astro -- --help ``` -------------------------------- ### Pure DI Wiring Example Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/guides/basic-di/3. iti-vs-pure.mdx Demonstrates wiring dependencies manually in a 'Pure DI' approach. A logger instance is created based on the environment, and then used to instantiate the PaymentService. ```typescript const logger = process.env.NODE_ENV === "production" ? new PinoLogger() : new ConsoleLogger() const paymentService = new PaymentService(logger) paymentService.sendMoney() ``` -------------------------------- ### Migrate Ensure Wrapper Setup (After v0.8.0) Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/migration.mdx With v0.8.0, use `generateEnsureItems` for creating wrapper components and context hooks. This function replaces `generateEnsureContainerSet`. ```tsx import { generateEnsureItems } from "iti-react" import { useItems } from "./hooks" const { EnsureWrapper, contextHook } = generateEnsureItems(() => useItems(["auth", "config"]) ) export const EnsureAuth = EnsureWrapper export const useAuthContext = contextHook ``` -------------------------------- ### ITI Wiring Example Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/guides/basic-di/3. iti-vs-pure.mdx Shows how to wire dependencies using ITI's container. It defines providers for logger and PaymentService, demonstrating a more declarative approach to dependency injection. ```tsx const root = createContainer() .add({ logger: () => process.env.NODE_ENV === "production" ? new PinoLogger() : new ConsoleLogger(), }) .add((ctx) => ({ paymentService: () => new PaymentService(ctx.logger), })) const ps = root.items.paymentService ps.sendMoney() ``` -------------------------------- ### Async Dependency Injection with ITI Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/guides/async-di/iti.mdx This example shows how to set up an asynchronous dependency injection container using ITI. It includes defining services with async initialization and resolving them. ```typescript import { createContainer } from "iti" // prettier-ignore interface Logger { info: (msg: string) => void } // prettier-ignore class ConsoleLogger implements Logger { info(msg: string): void { console.log("[Console]:", msg) } } // prettier-ignore class PinoLogger implements Logger { info(msg: string): void { console.log("[Pino]:" , msg) } } interface UserData { name: string } class AuthService { async getUserData(): Promise { return { name: "Big Lebowski" } } } class User { constructor(private data: UserData) {} name = () => this.data.name } class PaymentService { constructor(private readonly logger: Logger, private readonly user: User) {} sendMoney() { this.logger.info(`Sending monery to the: ${this.user.name()} `) return true } } export async function runMyApp() { const root = createContainer() .add({ logger: () => process.env.NODE_ENV === "production" ? new PinoLogger() : new ConsoleLogger(), }) .add({ auth: new AuthService() }) .add((ctx) => ({ user: async () => new User(await ctx.auth.getUserData()), })) .add((ctx) => ({ paymentService: async () => new PaymentService(ctx.logger, await ctx.user), })) const ps = await root.items.paymentService ps.sendMoney() } console.log(" ---- My App START \n\n") runMyApp().then(() => { console.log("\n\n ---- My App END") }) ``` -------------------------------- ### Get Single and Multiple Instances Source: https://github.com/molszanski/iti/blob/master/iti/README.md Demonstrates how to retrieve single cached instances or multiple instances by key or a factory function. ```typescript container.get("oven") // Creates a new Oven instance container.get("oven") // Gets a cached Oven instance await container.get("kitchen") // { kitchen: Kitchen } also cached await container.items.kitchen // same as above // Get multiple instances at once await container.getItems(["oven", "userManual"]) // { userManual: '...', oven: Oven } await container.getItems((c) => [c.userManual, c.oven]) // same as above ``` -------------------------------- ### After: Get and Subscribe to Multiple Items (v0.8.0) Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/migration.mdx Shows the updated method names for getting multiple items and subscribing to changes in v0.8.0. The old names are deprecated but still functional. ```typescript import { createContainer } from "iti" const container = createContainer().add({ serviceA: () => new ServiceA(), serviceB: () => new ServiceB(), }) // Get multiple items (new name) const items = await container.getItems(["serviceA", "serviceB"]) // Subscribe to changes (new names) container.subscribeToItem("serviceA", (err, service) => { console.log("Service A updated") }) container.subscribeToItems(["serviceA", "serviceB"], (err, items) => { console.log("Services updated") }) ``` -------------------------------- ### ITI Business Logic Setup Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/quick-start.mdx Defines the core business logic and dependencies for an application using ITI. This snippet sets up the 'paymentService' dependency. ```ts import { InjectionToken } from "iti"; interface PaymentService { sendMoney(): Promise; } const paymentServiceToken: InjectionToken = "paymentService"; export const businessLogic = { paymentService: async (deps) => { // Simulate async initialization await new Promise(resolve => setTimeout(resolve, 100)); return { sendMoney: async () => { console.log("Sending money..."); }, }; }, }; ``` -------------------------------- ### Container Get Items Strategies Source: https://github.com/molszanski/iti/blob/master/iti/notes-and-ideas.md Demonstrates four different options for retrieving items from a container, ranging from direct token arrays to functional approaches and token object access. ```javascript // Option 1 let containerSet1 = await cont.getItems(["aCont", "bCont", "cCont"]) ``` ```javascript // Option 2 let containerSet2 = await cont.getItems((c) => [c.aCont, c.bCont, c.Cont]) ``` ```javascript // Option 3 let containerSet2 = await cont.getItems(({ aCont, bCont, cCont }) => ({ aCont, bCont, cCont, })) ``` ```javascript // Option 4 let c = cont.tokens let containerSet2 = await cont.getItems([c.aCont, c.bCont, c.Cont]) ``` -------------------------------- ### typed-inject Monkey-Patching Example Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/advanced/alternatives.md Illustrates typed-inject's approach using monkey-patching by defining injection points on factories and classes. ```typescript import { createInjector } from "typed-inject" function barFactory(foo: number) { return foo + 1 } barFactory.inject = ["foo"] as const class Baz { constructor(bar: number) { console.log(`bar is: ${bar}`) } static inject = ["bar"] as const } ``` -------------------------------- ### Astro Project Commands Source: https://github.com/molszanski/iti/blob/master/examples/astro-playground/README.md These are the essential commands for managing your Astro project. They cover dependency installation, local development server, production builds, and previewing. ```sh yarn install ``` ```sh yarn dev ``` ```sh yarn build ``` ```sh yarn preview ``` ```sh yarn astro ... ``` ```sh yarn astro -- --help ``` -------------------------------- ### Singleton Lifecycle Management Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/advanced/patterns-and-tips.md Demonstrates the singleton (single instance) pattern where a dependency is created only once and reused across the application. Subsequent calls to `get` will return the same instance. ```typescript let node = createContainer().add({ oven: () => new Oven(), }) node.get("oven") === node.get("oven") // true ``` -------------------------------- ### Async Dependency Injection Example Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/advanced/when-not-to-use-iti.md Illustrates dependency injection with asynchronous operations, such as fetching user data. This approach is useful when dependencies are loaded dynamically or involve async calls. ```typescript const logger = process.env.NODE_ENV === "production" ? new PinoLogger() : new ConsoleLogger() const auth = new AuthService() const userInfo = new User(await auth.getUserData()) const paymentService = new PaymentService(logger, userInfo) paymentService.sendMoney() ``` -------------------------------- ### Migrate Ensure Wrapper Setup (Before v0.7.x) Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/migration.mdx In versions prior to v0.8.0, `generateEnsureContainerSet` was used to create wrapper components and context hooks for ensuring container availability. ```tsx import { generateEnsureContainerSet } from "iti-react" import { useContainerSet } from "./hooks" const { EnsureWrapper, contextHook } = generateEnsureContainerSet(() => useContainerSet(["auth", "config"]) ) export const EnsureAuth = EnsureWrapper export const useAuthContext = contextHook ``` -------------------------------- ### Get and Delete Dependencies in Iti Source: https://github.com/molszanski/iti/blob/master/README.md Demonstrates how to retrieve single or multiple instances of dependencies from the container and how to remove them. Caching behavior is shown for single instances. ```typescript // Get a single instance container.get("oven") // Creates a new Oven instance container.get("oven") // Gets a cached Oven instance await container.get("kitchen") // { kitchen: Kitchen } also cached await container.items.kitchen // same as above // Get multiple instances at once await container.getItems(["oven", "userManual"]) // { userManual: '...', oven: Oven } await container.getItems((c) => [c.userManual, c.oven]) // same as above // Plain deletion container.delete("kitchen") ``` -------------------------------- ### Add and Upsert Dependencies in Iti Source: https://github.com/molszanski/iti/blob/master/README.md Demonstrates adding new dependencies to the container and updating existing ones using `upsert`. The example highlights type safety and error handling for overwriting tokens. ```typescript let container = createContainer() .add({ userManual: "Please preheat before use", oven: () => new Oven(), }) .upsert((items, cont) => ({ userManual: "Works better when hot", preheatedOven: async () => { await items.oven.preheat() return items.oven }, })) // `add` is typesafe and a runtime safe method. Hence we've used `upsert` try { container.add({ // @ts-expect-error userManual: "You shall not pass", // Type Error: (property) userManual: "You are overwriting this token. It is not safe. Use an unsafe `upsert` method" }) } catch (err) { err.message // Error Tokens already exist: ['userManual'] } ``` -------------------------------- ### Get Multiple Instances (Async) Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/usage.md Retrieve multiple item instances concurrently. Can accept an array of keys or a function that returns an array of items. ```ts await root.getItems(["oven", "userManual"]) // { userManual: '...', oven: Oven } await root.getItems((c) => [c.userManual, c.oven]) // same as above ``` -------------------------------- ### get(token) Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/api.mdx Retrieves a single item from the container using its token (string identifier). Returns a Promise that resolves to the item instance. ```APIDOC ## `get(token)` - Get single item ```ts const service = await container.get("myService") // Returns a Promise that resolves to the service instance ``` ``` -------------------------------- ### Component Usage Example Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/migration.mdx Demonstrates how to use the updated `useItem` and `useItems` hooks within a React component to access single and multiple container items, respectively. ```tsx import { useItem, useItems } from "../_containers/hooks" export function Profile() { // Single item const [auth, authErr] = useItem().authService // Multiple items const [deps, depsErr] = useItems(["authService", "config"]) if (authErr || depsErr) return
Error loading
if (!auth || !deps) return
Loading...
return
Hello {auth.user.name}!
} ``` -------------------------------- ### ITI Container Setup with Conditional Logger Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/guides/basic-di/2. iti.mdx Sets up an ITI container with a conditional logger registration. The logger implementation (Pino or Console) is chosen based on the NODE_ENV environment variable. This snippet also demonstrates adding a service that depends on the registered logger. ```typescript import { createContainer } from "iti" export interface Logger { info: (msg: string) => void warn: (msg: string) => void error: (msg: string) => void } export class ConsoleLogger implements Logger { info(msg: string): void { console.log("Console Logger: ", msg) } warn(msg: string): void {} error(msg: string): void {} } export class PinoLogger implements Logger { info(msg: string): void { console.log("Pino Logger: ", msg) } warn(msg: string): void {} error(msg: string): void {} } export class PaymentService { private readonly logger: Logger constructor(_logger: Logger) { this.logger = _logger } sendMoney() { this.logger.info("inversify logger info") return true } } const root = createContainer() .add({ logger: () => process.env.NODE_ENV === "production" ? new PinoLogger() : new ConsoleLogger(), }) .add((ctx) => ({ paymentService: () => new PaymentService(ctx.logger), })) const ps = root.congainers.paymentService ps.sendMoney() ``` -------------------------------- ### React-Query Data Fetching in React Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/guides/react/1.react-basic.mdx Utilize `react-query`'s `useQuery` hook for managing server state in React. It provides loading, error, and data states. Requires `axios` for HTTP requests and `QueryClientProvider` setup. ```tsx import { QueryClient, QueryClientProvider, useQuery } from "react-query" import axios from "axios" export function Profile() { const { isLoading, error, data, isFetching } = useQuery("userData", () => axios.get("/api/user").then((res) => res.data) ) if (isLoading) return "Loading..." if (error) return "An error has occurred: " + error.message return
hello {data.name}!
} ``` -------------------------------- ### Generate Container Hooks Source: https://github.com/molszanski/iti/blob/master/iti-react/README.md Generates a set of app-specific container hooks using `getContainerHooks`. This example shows how to import necessary types and functions to create custom hooks for your application's container. ```ts // my-app-hooks.ts import React, { useContext } from "react" import { getContainerHooks } from "iti-react" import { getProviders, PizzaAppContainer } from "./_root.store" export const MyRootCont = React.createContext({}) let mega = getContainerHooks(getProviders, MyRootCont) export const useContainerSet = mega.useContainerSet ``` -------------------------------- ### Preventing Circular Dependencies with TypeScript and ITI Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/faq.mdx Demonstrates how ITI, combined with TypeScript, prevents the creation of circular dependencies at compile time. The example shows a conceptual circular dependency in business logic that cannot be expressed in the ITI container setup due to TypeScript's type checking. ```typescript import { createContainer } from "iti" /* // Part 1: You can create a circular dependency // in your business logic ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ A │──▶│ B │──▶│ C │──▶│ D │──▶│ E │ └───┘ └───┘ └───┘ └───┘ └───┘ ▲ │ │ │ └───────────────┘ */ class A { constructor() {} } class B { constructor(a: A) {} } class C { constructor(b: B, e: E) {} } class D { constructor(c: C) {} } class E { constructor(d: E) {} } // Part 2: You can't express a circular dependency because of typescript checks createContainer() .add((ctx) => ({ a: () => new A(), })) .add((ctx) => ({ b: () => new B(ctx.a), })) .add((ctx) => ({ // This line will throw a Typescript error at compile time c: () => new C(ctx.a, ctx.e), })) ``` -------------------------------- ### Build Production Site Source: https://github.com/molszanski/iti/blob/master/website/README.md Generates the production-ready static site in the `./dist/` directory. ```bash pnpm build ``` -------------------------------- ### useContainerSet Source: https://github.com/molszanski/iti/blob/master/iti-react/README.md Get multiple containers and automatically subscribes to changes. This hook is useful for accessing several containers simultaneously. ```APIDOC ## useContainerSet ### Description Get multiple containers and autosubscribes to change. ### Usage ```tsx export const PizzaData = () => { const containerSet = useContainerSet((containers) => [ containers.kitchen, containers.auth, ]) if (!containerSet) { return <>Kitchen is loading } return <>{containerSet.kitchen.oven.pizzasInOven} } ``` ``` -------------------------------- ### Preview Production Build Source: https://github.com/molszanski/iti/blob/master/website/README.md Locally previews the production build before deploying to ensure everything looks correct. ```bash pnpm preview ``` -------------------------------- ### Create a Container Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/api.mdx Initialize a new container with a root application scope. You can add initial items using the `add` method. ```typescript import { createContainer } from "iti" export function getMainMockAppContainer() { return createContainer().add({ kitchen: () => new Kitchen(/* deps */) }) } ``` -------------------------------- ### Get Single Item Synchronously Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/api.mdx Retrieve a single item instance synchronously if it has already been resolved. Returns `undefined` if the item is not yet cached. ```typescript // Get an item synchronously if it's already resolved const service = container.getSync("myService") // Returns the instance immediately if cached, otherwise undefined ``` -------------------------------- ### Get Single Item by Token Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/api.mdx Retrieve a single item instance from the container using its token. This method returns a Promise that resolves to the item. ```typescript const service = await container.get("myService") // Returns a Promise that resolves to the service instance ``` -------------------------------- ### Access Item Instance Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/usage.md Access an item instance directly via the node's items property, which is equivalent to using the get method. ```ts await node.get("kitchen") // Kitchen instance await node.items.kitchen // same as above ``` -------------------------------- ### Get Single Instance (Sync) Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/usage.md Retrieve a cached instance synchronously. Returns undefined if the instance has not been created yet. Available since v0.8.0. ```ts root.getSync("oven") // Returns cached instance or undefined ``` -------------------------------- ### Clone Playground Repository Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/advanced/playground.mdx Clone the ITI playground repository to your local machine to set up the interactive environment. Navigate into the cloned directory to begin. ```bash git clone git@github.com:molszanski/iti-playground.git cd iti-playground/src/ ``` -------------------------------- ### Astro Project Structure Overview Source: https://github.com/molszanski/iti/blob/master/examples/astro-playground/README.md This outlines the typical folder and file structure of an Astro project. Familiarize yourself with these directories to navigate your project effectively. ```text / ├── public/ │ └── favicon.svg ├── src │ ├── assets │ │ └── astro.svg │ ├── components │ │ └── Welcome.astro │ ├── layouts │ │ └── Layout.astro │ └── pages │ └── index.astro └── package.json ``` -------------------------------- ### Create and Configure IoC Container Source: https://github.com/molszanski/iti/blob/master/iti/README.md Initialize the Iti container and add dependencies using plain functions or async functions. Dependencies can reference other registered items. ```typescript import { createContainer } from "iti" import { Oven, Kitchen } from "./kitchen" const container = createContainer() .add({ key: () => new Item(), oven: () => new Oven(), userManual: async () => "Please preheat before use", }) .add((items) => ({ kitchen: async () => new Kitchen(items.oven, await items.userManual), })) await container.get("kitchen") // Kitchen ``` -------------------------------- ### Create and Add Items to Container Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/usage.md Create a new container, add initial items, and then upsert additional items with dependencies. The `add` method is typesafe and runtime safe. ```ts let cont1 = createContainer() .add({ userManual: "Please preheat before use", oven: () => new Oven(), }) .upsert((containers, node) => ({ userManual: "Works better when hot", preheatedOven: async () => { await containers.oven.preheat() return containers.oven }, })) ``` -------------------------------- ### Dispose Individual Dependency Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/api.mdx Use `dispose` to remove a specific dependency from the container. Note that this does not dispose child elements. The disposer for 'b' will not be called in this example. ```ts 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") ``` -------------------------------- ### Get Multiple Items Synchronously Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/api.mdx Retrieve multiple item instances synchronously if all are resolved. Returns either an object of instances or a Promise if any item needs resolution. ```typescript // Returns synchronously if all items are resolved, otherwise returns a Promise const items = container.getItemsSync(["serviceA", "serviceB"]) // Can be either: { serviceA: ..., serviceB: ... } OR Promise<{ serviceA: ..., serviceB: ... }> ``` -------------------------------- ### Dynamic Imports for Services Source: https://github.com/molszanski/iti/blob/master/iti/README.md Illustrates how to use dynamic imports to lazily load services and their dependencies, improving initial load times. ```typescript // ./kitchen/index.ts export async function provideKitchenContainer() { const { Kitchen } = await import("./kitchen/kitchen") return { kitchen: () => new Kitchen(), oven: async () => { const { Oven } = await import("./kitchen/oven") const oven = new Oven() await oven.preheat() return oven }, } } // ./index.ts import { createContainer } from "iti" import { provideKitchenContainer } from "./kitchen" let cont = createContainer().add({ kitchen: async () => provideKitchenContainer(), }) // Next line will load `./kitchen/kitchen` module await cont.items.kitchen // Next line will load `./kitchen/oven` module await cont.items.kitchen.oven ``` -------------------------------- ### Create a Root Container with Iti Source: https://context7.com/molszanski/iti/llms.txt Use `createContainer` to build a dependency injection container. Register services using `.add()`, with optional context callbacks to chain dependencies. ```typescript import { createContainer } from "iti" // Business logic — zero framework imports class CookieStorageService { async getSessionToken() { return { token: "magicToken123" } } } class AuthService { constructor(private cs: CookieStorageService) {} async getUserData() { const { token } = await this.cs.getSessionToken() if (token === "magicToken123") return { name: "Big Lebowski" } throw new Error("Unauthorized") } } class PaymentService { constructor(private logger: Console, private user: { name: string }) {} sendMoney() { this.logger.log(`Sending money to: ${this.user.name}`); return true } } // Container wiring — all in one place export const app = createContainer() .add({ logger: () => process.env.NODE_ENV === "production" ? console : console, cookieStorage: () => new CookieStorageService(), }) .add((ctx) => ({ auth: () => new AuthService(ctx.cookieStorage), })) .add((ctx) => ({ userData: async () => await ctx.auth.getUserData(), })) .add((ctx) => ({ paymentService: async () => new PaymentService(ctx.logger, await ctx.userData), })) ``` -------------------------------- ### Get Multiple Instances (Sync) Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/usage.md Retrieve multiple cached item instances synchronously. Returns items if cached, otherwise a Promise. Available since v0.8.0. ```ts root.getItemsSync(["oven", "userManual"]) // Returns items if cached, otherwise Promise ``` -------------------------------- ### Dynamic Imports with Iti Source: https://context7.com/molszanski/iti/llms.txt Demonstrates how Iti's async nature allows for dynamic loading of modules using `import()` when a token is first requested. This is useful for code splitting. ```typescript // kitchen/index.ts — dynamic provider export async function provideKitchenContainer() { const { Kitchen } = await import("./kitchen") // loaded on demand return { kitchen: () => new Kitchen(), oven: async () => { const { Oven } = await import("./oven") // loaded on demand const oven = new Oven() await oven.preheat() return oven }, } } // index.ts — root container import { createContainer } from "iti" import { provideKitchenContainer } from "./kitchen" const app = createContainer().add({ kitchen: async () => provideKitchenContainer(), }) // Loads './kitchen/kitchen' only when accessed for the first time const kitchenContainer = await app.items.kitchen // Loads './kitchen/oven' only when accessed for the first time const oven = await kitchenContainer.oven ``` -------------------------------- ### Get Single Instance (Async) Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/usage.md Retrieve a single instance of an item. The first call creates and caches the instance, subsequent calls return the cached version. ```ts await root.get("oven") // Creates a new Oven instance await root.get("oven") // Gets a cached Oven instance ``` -------------------------------- ### Create and Configure Iti Container Source: https://github.com/molszanski/iti/blob/master/README.md Use `createContainer` to initialize an Iti container and `add` methods to register dependencies. Dependencies can be synchronous or asynchronous. ```typescript // app.ts import { createContainer } from "iti" import { Oven, Kitchen } from "./kitchen" const container = createContainer() .add({ key: () => new Item(), oven: () => new Oven(), userManual: async () => "Please preheat before use", }) .add((items) => ({ kitchen: async () => new Kitchen(items.oven, await items.userManual), })) await container.get("kitchen") // Kitchen ``` -------------------------------- ### createContainer Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/api.mdx Initializes a new container with specified items. This is the primary way to set up your application's dependency injection structure. ```APIDOC ## `createContainer` Setting app root ```ts import { createContainer } from "iti" export function getMainMockAppContainer() { return createContainer().add({ kitchen: () => new Kitchen(/* deps */) }) } ``` ``` -------------------------------- ### Get Multiple Items by Tokens Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/api.mdx Retrieve multiple item instances from the container using an array of tokens or a callback function. Returns a Promise resolving to an object of instances. ```typescript // Get multiple instances at once const items = await container.getItems(["serviceA", "serviceB"]) // Returns: { serviceA: ..., serviceB: ... } // Callback style const items = await container.getItems((c) => [c.serviceA, c.serviceB]) ``` -------------------------------- ### Project Structure Overview Source: https://github.com/molszanski/iti/blob/master/website/README.md This is the typical directory structure for an Astro + Starlight project. Starlight content is located in `src/content/docs/`. ```bash .\n├── public/\n├── src/\n│ ├── assets/\n│ ├── content/\n│ │ └── docs/\n│ └── content.config.ts\n├── astro.config.mjs\n├── package.json\n└── tsconfig.json ``` -------------------------------- ### ITI - Clean Business Logic Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/advanced/alternatives.md Shows how ITI integrates dependencies directly into the constructor without decorators, promoting cleaner business logic. Providers are defined separately. ```typescript import type { Ingredients } from "./store.ingredients" import type { Oven } from "./store.oven" export class Kitchen { constructor(private oven: Oven, private ingredients: Ingredients) {} } // provider / factory import { IngredientsService } from "../services/ingredients-manager" import { Kitchen } from "../stores/store.kitchen" import { Oven } from "../stores/store.oven" export async function provideKitchenContainer() { let oven = new Oven() let ingredients = await IngredientsService.buySomeIngredients() let kitchen = new Kitchen(oven, ingredients) return { oven: oven, ingredients: ingredients, kitchen: kitchen, } } ``` -------------------------------- ### Use Single Container with Error Handling Source: https://github.com/molszanski/iti/blob/master/iti-react/README.md Demonstrates using the `useContainer` hook to access a single container ('kitchen') and includes basic error handling for loading states. ```tsx export const PizzaData = () => { const [kitchenContainer, err] = useContainer().kitchen if (!kitchenContainer || err) { return <>Kitchen is loading } return <>{kitchenContainer.oven.pizzasInOven} } ``` -------------------------------- ### container.delete(token) Source: https://context7.com/molszanski/iti/llms.txt `delete(token)` removes a token's cached instance from the container. Subsequent calls to `get()` for this token will re-execute its factory function, effectively refreshing the cached value. ```APIDOC ## `container.delete(token)` — Remove a cached item ### Description `delete(token)` removes a token's cached instance from the container. The next call to `get()` will re-execute the factory. ### Method `delete` ### Parameters #### Path Parameters - **token** (string) - Required - The token identifier for the cached item to remove. ### Request Example ```ts import { createContainer } from "iti" class Kitchen { name = "my kitchen" } const container = createContainer().add({ kitchen: () => new Kitchen(), }) const k1 = await container.get("kitchen") container.delete("kitchen") const k2 = await container.get("kitchen") console.log(k1 === k2) // false — new instance after deletion ``` ### Response #### Success Response (Container) - Returns the container instance after the token has been deleted. #### Response Example ```json { "container": "instance" } ``` ``` -------------------------------- ### Remove Cached Item with delete Source: https://context7.com/molszanski/iti/llms.txt The delete(token) method removes a token's cached instance from the container. The next call to get() will re-execute the factory, creating a new instance. ```typescript import { createContainer } from "iti" class Kitchen { name = "my kitchen" } const container = createContainer().add({ kitchen: () => new Kitchen(), }) const k1 = await container.get("kitchen") container.delete("kitchen") const k2 = await container.get("kitchen") console.log(k1 === k2) // false — new instance after deletion ``` -------------------------------- ### Manage Multiple Independent Containers with Iti Source: https://context7.com/molszanski/iti/llms.txt Demonstrates creating and managing multiple independent Iti container instances. Infrastructure and domain containers can coexist, with the domain container consuming services from the infrastructure container. ```ts import { createContainer } from "iti" class DB { query(sql: string) { return [] } } class Cache{ get(key: string) { return null } } class UserService { constructor(private db: DB, private cache: Cache) {} getUser(id: string) { return this.db.query(`SELECT * FROM users WHERE id='${id}'`) } // Infrastructure container const infraContainer = createContainer() .add({ db: () => new DB(), cache: () => new Cache() }) .addDisposer({ db: (_db) => console.log("DB closed") }) // Domain container — consumes from infraContainer const domainContainer = createContainer().add({ userService: () => new UserService(infraContainer.getSync("db")!, infraContainer.getSync("cache")!), }) await infraContainer.get("db") await infraContainer.get("cache") const users = domainContainer.getSync("userService") // Dispose infrastructure independently await infraContainer.disposeAll() ``` -------------------------------- ### disposeAll(): Promise Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/api.mdx Runs cleanup functions on provided (created) dependencies. Returns a Promise that resolves when all disposers of cached resolutions have resolved. ```APIDOC ## `disposeAll(): Promise` ### Description Runs cleanup functions on provided (created) dependencies. Returns a Promise that resolves when all disposers of cached resolutions have resolved. ### Method `disposeAll` ### Returns `Promise` ### Example ```ts import { createContainer } from "iti" const container = createContainer() .add({ a: () => "123" }) .addDisposer({ a: () => {} }) container.get("a") === "123" // true await container.disposeAll() ``` ``` -------------------------------- ### Dynamic Imports for Dependencies in Iti Source: https://github.com/molszanski/iti/blob/master/README.md Illustrates how to use dynamic imports to load modules on demand. This is useful for lazy loading features and reducing initial bundle size. ```typescript // ./kitchen/index.ts export async function provideKitchenContainer() { const { Kitchen } = await import("./kitchen/kitchen") return { kitchen: () => new Kitchen(), oven: async () => { const { Oven } = await import("./kitchen/oven") const oven = new Oven() await oven.preheat() return oven }, } } ``` ```typescript // ./index.ts import { createContainer } from "iti" import { provideKitchenContainer } from "./kitchen" let cont = createContainer().add({ kitchen: async () => provideKitchenContainer(), }) // Next line will load `./kitchen/kitchen` module await cont.items.kitchen // Next line will load `./kitchen/oven` module await cont.items.kitchen.oven ``` -------------------------------- ### Simplifying Dependency Fetching with Custom Hooks Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/guides/react/1.react-basic.mdx Illustrates a pattern for simplifying dependency fetching in React components. Instead of directly calling a hook that fetches multiple dependencies, a custom hook provides a cleaner interface. ```tsx const [profileDeps, profileDepsErr] = useContainerSet(["auth", "env"]) if (!profileDeps || profileDepsErr) return null ``` ```tsx const { auth, env } = useProfileDeps() ``` -------------------------------- ### Run Astro CLI Commands Source: https://github.com/molszanski/iti/blob/master/website/README.md Execute various Astro CLI commands, such as adding integrations or checking your project. ```bash pnpm astro ... ``` -------------------------------- ### Dynamic Imports for Modules Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/advanced/patterns-and-tips.md Shows how to use dynamic imports to load modules on demand. This is useful for code splitting and lazy loading features, improving initial load times. ```typescript // ./kitchen/index.ts export async function provideKitchenContainer() { const { Kitchen } = await import("./kitchen/kitchen") return { kitchen: () => new Kitchen(), oven: async () => { const { Oven } = await import("./kitchen/oven") const oven = new Oven() await oven.preheat() return oven }, } } ``` ```typescript // ./index.ts import { createContainer } from "iti" import { provideKitchenContainer } from "./kitchen" let node = createContainer().add({ kitchen: async () => provideKitchenContainer(), }) // Next line will load `./kitchen/kitchen` module await node.items.kitchen // Next line will load `./kitchen/oven` module await node.items.kitchen.oven ``` -------------------------------- ### Dispose Dependencies in Iti Source: https://github.com/molszanski/iti/blob/master/README.md Illustrates how to add disposers for asynchronous cleanup operations and how to dispose of individual or all dependencies from the container. ```typescript // Disposing container .add({ dbConnection: () => connectToDb(process.env.dbUrl) }) .addDisposer({ dbConnection: (db) => db.disconnect() }) // waits for promise await container.dispose("dbConnection") await container.disposeAll() ``` -------------------------------- ### Lazy Initialization with Functions Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/advanced/patterns-and-tips.md Prefer using functions for dependency initialization to ensure lazy loading, which improves application startup performance. Eagerly created instances are initialized immediately when the container is created. ```typescript // Good createContainer().add({ eventBus: () => new EventBus(), userAuthService: () => new UserAuthService(), }) // Meh... createContainer().add({ eventBus: new EventBus(), userAuthService: new UserAuthService(), }) ``` -------------------------------- ### Singleton Lifecycle in Iti Source: https://github.com/molszanski/iti/blob/master/README.md Shows how to configure a dependency to be a singleton, ensuring that only one instance is created and reused throughout the container's lifetime. This is the default behavior. ```typescript let cont = createContainer().add({ oven: () => new Oven(), }) cont.get("oven") === cont.get("oven") // true ``` -------------------------------- ### Create ITI Container with Async Dependencies Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/guides/react/2.configuration.md Define an ITI container and add asynchronous dependencies like fetching user profile data. This sets up the core of your application's dependency graph. ```tsx import { createContainer } from "iti" export const mainApp = () => createContainer().add(() => ({ auth: async () => { const res = await fetch("/api/profile") return { profile: res.json(), } }, })) export type MainAppContainer = ReturnType ``` -------------------------------- ### Dispose All Dependencies Source: https://github.com/molszanski/iti/blob/master/website/src/content/docs/api.mdx Use `disposeAll` to run cleanup functions for all registered dependencies. It returns a Promise that resolves when all cached resolutions have been disposed. ```ts import { createContainer } from "iti" container = createContainer() .add({ a: () => "123" }) .addDisposer({ a: () => {} }) container.get("a") === "123" // true await container.disposeAll() // Promise ``` -------------------------------- ### Register New Tokens with add Source: https://context7.com/molszanski/iti/llms.txt The add() method is the primary way to register factories. It provides runtime and compile-time safety against accidental overwrites, throwing an error if a token already exists. ```typescript import { createContainer } from "iti" class Oven {} let container = createContainer().add({ userManual: "Please preheat before use", // plain value — stored as-is oven: () => new Oven(), // factory — called lazily, result cached }) // Runtime and compile-time guard against accidental overwrites try { container.add({ // @ts-expect-error — TypeScript error: "You are overwriting this token..." userManual: "You shall not pass", }) } catch (err: any) { console.error(err.message) // "Error Tokens already exist: ['userManual']" } ```