{"_id":"@carlhopf/iti","_rev":"4-8863199ccc3214b555d3c3de2e005734","time":{"created":"2023-01-19T10:23:38.250Z","0.6.0":"2023-01-19T10:07:47.036Z","modified":"2023-01-19T10:27:42.100Z","0.6.1":"2023-01-19T10:23:38.472Z","0.6.2":"2023-01-19T10:27:42.023Z"},"name":"@carlhopf/iti","dist-tags":{"latest":"0.6.2"},"versions":{"0.6.1":{"name":"@carlhopf/iti","version":"0.6.1","description":"~1kB Dependency Injection Library for Typescript and React with a unique async flow support","type":"module","sideEffects":false,"source":"src/index.ts","exports":{"require":"./dist/iti.cjs","default":"./dist/iti.modern.js","types":"./dist/src/index.d.ts"},"main":"./dist/iti.cjs","module":"./dist/iti.module.js","typings":"./dist/src/index.d.ts","scripts":{"_build":"rm -rf ./dist && microbundle build -o dist/ && cp -R src/* dist/src","build":"rm -rf ./dist && microbundle build -o dist/","jest":"jest","stryker":"stryker","stryker:run":"stryker run","test":"yarn jest && yarn tsd","jestWatch":"jest --watch --verbose","tsd":"tsd tsd_project"},"dependencies":{"utility-types":"^3.10.0"},"devDependencies":{"@stryker-mutator/core":"^6.1.2","@stryker-mutator/jest-runner":"^6.1.2","@stryker-mutator/typescript-checker":"^6.1.2","@types/jest":"^27.4.1","@types/react":"^18.0.15","jest":"^27.4.7","stryker-cli":"^1.0.2","microbundle":"^0.15.0","nodemon":"^2.0.19","ts-jest":"^27.1.3","tsd":"^0.22.0","typescript":"^4.7.4"},"engines":{"node":">=12"},"license":"MIT","authors":["Nick Olszanski <nick@dinosaurs-with-jetpacks.com>"],"repository":{"type":"git","url":"git+https://github.com/molszanski/iti.git"},"keywords":["ioc","di","inversion of control","dependency injection","dependency inversion","inversion of control container","container","javascript","typescript","type-safe"],"homepage":"https://itijs.org","prettier":{"semi":false,"singleQuote":false,"arrowParens":"always","trailingComma":"all"},"gitHead":"51caae6773bc8991c916890ed191ea0042f57c94","bugs":{"url":"https://github.com/molszanski/iti/issues"},"_id":"@carlhopf/iti@0.6.1","_nodeVersion":"19.2.0","_npmVersion":"8.19.3","dist":{"integrity":"sha512-II1GFuz37D4Jo8BiDm7/cm6zDtd0EJHKc+Jya23+EhLEZN/RfgSKFf2xMM+jCyE8Mpcd5ExEsg713nw2z1KjeQ==","shasum":"b6c1ced1ad54b2fb841ac7598853894935f1f361","tarball":"https://registry.npmjs.org/@carlhopf/iti/-/iti-0.6.1.tgz","fileCount":3,"unpackedSize":11405,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCk5pZPgt86QJrBH9dLOdz0mT9FKfGHTr3isAl/VccCOgIhAL9NHGh3kBQy8SgIPl2JEKTEqvc3ZyrgLiogm7XPLjWx"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjyRoqACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp28g//dbCuoKa7t7ADjvV/QSyHxLNgCMrtWe32Y1dvV0zmQRbRs31l\r\nuPdvLvgqhp3hZTW1FIMKJPgwPSstd9SrYzmEqy9gFmjrpuK2TmnYPoDHUlsx\r\n9joTsBTtzNRqGRV5i7J+oQSWmUgpB+LmAF2J6g4IFDCGi6cjnjcQD6Mleilz\r\nraqhZfrf4Bw0RLGqFexYILyocFxfZM34sHQh2KtauWllCLEyALvERQmwvwk6\r\no4s/3AF1Ko4p1We0jrTmEv4dNFGD/mWWX4sQKqRqWVl6OtGToEDJwXsvR+pL\r\ndAIB6Gepr9Qmp5tA+lDp3aR6jzICFV94mptQ+boKCVyPE2oqXCiePF8z68WB\r\nZ7pFNtkSifMlO0s58BBQYHp3puYD1WnesgYygQ0vA0aSfhRkhI8d5zV3FD1/\r\nzr5JOmg/QYspFJiNW2fBVBEmCYxI/0/tyEANAOeoWJ5XLOpwdpdgZTrinUqf\r\nfTakDIM1DVNGTUwVv7rSiBPytpc8YFi4KDrcnz52nRCCvULpbhlkRWT0G+iC\r\nPwGSJZZHrYGlX7VCIf7fy0CNzZsC2l1Hi/X2ztOI7+XQ1gQ/XjO0Q6Dvn4KE\r\n0qUFOAmmTIIZJMnUqeudrUdcNVZTX8B6bKG+5hQTEAHnkTJuIA4f+vEVhqwf\r\ndwDms++VZ5M4btqXgmLq+/nuwTWG9hPPAZQ=\r\n=FQ96\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"carlhopf","email":"carlhopf.com@gmail.com"},"directories":{},"maintainers":[{"name":"carlhopf","email":"carlhopf.com@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/iti_0.6.1_1674123818316_0.6204716304093632"},"_hasShrinkwrap":false},"0.6.2":{"name":"@carlhopf/iti","version":"0.6.2","description":"~1kB Dependency Injection Library for Typescript and React with a unique async flow support","type":"module","sideEffects":false,"source":"src/index.ts","exports":{"require":"./dist/iti.cjs","default":"./dist/iti.modern.js","types":"./dist/src/index.d.ts"},"main":"./dist/iti.cjs","module":"./dist/iti.module.js","typings":"./dist/src/index.d.ts","scripts":{"_build":"rm -rf ./dist && microbundle build -o dist/ && cp -R src/* dist/src","build":"rm -rf ./dist && microbundle build -o dist/","jest":"jest","stryker":"stryker","stryker:run":"stryker run","test":"yarn jest && yarn tsd","jestWatch":"jest --watch --verbose","tsd":"tsd tsd_project"},"dependencies":{"utility-types":"^3.10.0"},"devDependencies":{"@stryker-mutator/core":"^6.1.2","@stryker-mutator/jest-runner":"^6.1.2","@stryker-mutator/typescript-checker":"^6.1.2","@types/jest":"^27.4.1","@types/react":"^18.0.15","jest":"^27.4.7","stryker-cli":"^1.0.2","microbundle":"^0.15.0","nodemon":"^2.0.19","ts-jest":"^27.1.3","tsd":"^0.22.0","typescript":"^4.7.4"},"engines":{"node":">=12"},"license":"MIT","authors":["Nick Olszanski <nick@dinosaurs-with-jetpacks.com>"],"repository":{"type":"git","url":"https://github.com/molszanski/iti.git"},"keywords":["ioc","di","inversion of control","dependency injection","dependency inversion","inversion of control container","container","javascript","typescript","type-safe"],"homepage":"https://itijs.org/","prettier":{"semi":false,"singleQuote":false,"arrowParens":"always","trailingComma":"all"},"licenseText":"MIT License\n\nCopyright (c) 2022 Nick Olszanski\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@carlhopf/iti@0.6.2","dist":{"shasum":"347518f3f03578cf251822529d1c2ef533b65353","integrity":"sha512-eYG8MORaTmZENBgs+tneoQPKFSxSxdC2seS6X2ldmbDGWj1W80vaIIkUDzZb3Vsnz3NCe9SkQ3WR9mko9Sru5A==","tarball":"https://registry.npmjs.org/@carlhopf/iti/-/iti-0.6.2.tgz","fileCount":40,"unpackedSize":141873,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDjLTvL9kV6ZhYOAL82nRwQ+j40tbDZPfg/amjurrYh3AIhALhaaVOw0pOcjQ2/jvcMPq5rtw1uoEoPlm3TUwdJdtXM"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjyRseACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp3Bw/+LN7xiokiohAgFTBMC9cUdE84ZmL4PI3byWrJ1rWxjeQLsdj1\r\n0xrRq/Ziu6hJkiffTPuAdlfNi9zVHMhAwMb+o+CLv1lm1zpNc5hSBNgwDHvq\r\nIhwEtp81+RQmYCzB62jdQacDaHEsdG0gfAjHM6zp0Ltp7oVpxmAwh6qRk8Wo\r\na96Wiuh7iUW4Q6TGhMO3BTXM+6adx/MixiKjepTQcHQHnzfuqEmcN+8TVAN8\r\nvflhzvw7WNelWOm9Xo9J8MjHoiF8W0uXcevtdaOhaU7oratwDmNK32p6p177\r\nA0bXlCEhTbZT3javWysZMazMDEEJ81H5ISzU1xK08oTvSzzdWIxJJzzVXTeT\r\nyDBZG+RowFfLLIOlQ56LPV8A7N1d4u7Pl8VBsGsKiLjkaSioDM0mr4L/f5gh\r\nciZyQ/rhFY39wpDOC23nDeO7TP6ulknne7L1HuH5/BM4RaSB0TTMbdMaxMRZ\r\nQZq74qLEf49QqjI+HdQ5VWvAfJbbChl4RPkrAAkIUVlEq2POZuJ0LkSA/hy2\r\n+1+q9gEtyTZ8/3eKKpgNcdS+hG9fY9RBWac3wYRv7FcF5XyzAfQ5i+0vHLXH\r\n1Puv28iMbVsUUt9vGeyyYt9orYWM7BB0n2Rh3zJ2q5iWYLHoabwqc4wnVpsC\r\no0CM3MCjy810mKUS3jlapChDPMMciCLKjSE=\r\n=83EF\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"carlhopf","email":"carlhopf.com@gmail.com"},"directories":{},"maintainers":[{"name":"carlhopf","email":"carlhopf.com@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/iti_0.6.2_1674124061855_0.0167371082419685"},"_hasShrinkwrap":false}},"maintainers":[{"name":"carlhopf","email":"carlhopf.com@gmail.com"}],"description":"~1kB Dependency Injection Library for Typescript and React with a unique async flow support","homepage":"https://itijs.org/","keywords":["ioc","di","inversion of control","dependency injection","dependency inversion","inversion of control container","container","javascript","typescript","type-safe"],"repository":{"type":"git","url":"https://github.com/molszanski/iti.git"},"license":"MIT","readme":"<p align=\"center\">\n  <a href=\"https://itijs.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n    <img width=\"180\" src=\"./docs/logo.svg\" alt=\"ITI Logo\">\n  </a>\n</p>\n\n<div align=\"center\">\n\n# Iti\n\n<h4>~1kB Dependency Injection Library for Typescript and React with a unique <strong>async flow</strong> support</h4>\n\n<p align=\"center\">\n  <a href=\"https://github.com/molszanski/iti/actions?query=branch%3Amaster\"><img src=\"https://github.com/molszanski/iti/actions/workflows/lib-test.yml/badge.svg\" alt=\"CI Status\"></a>\n  <a href=\"https://www.npmjs.org/package/iti\"><img src=\"https://img.shields.io/npm/v/iti.svg\" alt=\"npm version\"></a>\n  <a href=\"https://unpkg.com/iti/dist/iti.modern.js\"><img src=\"https://img.badgesize.io/https://unpkg.com/iti/dist/iti.modern.js?compression=gzip\" alt=\"gzip\"></a>\n  <!-- Manually checked at b1683832 on OCT 8 2022-->\n  <a href=\"https://dashboard.stryker-mutator.io/reports/github.com/molszanski/iti/master\"><img src=\"https://img.shields.io/badge/coverage-98.6%25-brightgreen\" alt=\"Coverage\"></a>\n  <a href=\"https://dashboard.stryker-mutator.io/reports/github.com/molszanski/iti/master\"><img src=\"https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fmolszanski%2Fiti%2Fmaster\" alt=\"Mutation Score\"></a>\n</p>\n\n</div>\n\n- **supports async(!):** merges async code and constructor injection via plain **async** functions\n- **non-invasive:** does not require imported `@decorators` or framework `extends` in your application business logic\n- **strongly typed:** has great IDE autocomplete and compile time check. Without any [manual type casting](https://github.com/inversify/InversifyJS/blob/master/wiki/container_api.md#containergettserviceidentifier-interfacesserviceidentifiert-t)\n- **lazy:** initializes your app modules and containers on demand\n- **split chunks:** enables **[dynamic imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports)** via a [one liner](#dynamic-imports) thanks to a fully async core\n- **React friendly:** has useful **[React](https://github.com/molszanski/iti/tree/master/iti-react)** bindings to help you separate application business logic and a React view layer\n- **starter friendly:** works with starters like [Create React App](https://create-React-app.dev/) or [Next.js](https://nextjs.org/docs/getting-started) unlike existing libraries\n- **no Babel config:** doesn't require `reflect-metadata` or decorators so there is no need to hack in decorator and `\"decoratorMetadata\"` support in to your build configs\n- **tiny:** less than 1kB\n\nIoC is an amazing pattern and it should **easy to adopt**, fully support async and without hard to learn APIs or complex tooling requirements.\n\nIti relies on plain JS functions, objects and familiar patterns. API is simple so you can make a **proof of concept integration in minutes**.\n\nIt is an alternative to [InversifyJS](https://github.com/inversify/InversifyJS) and [microsoft/tsyringe](https://github.com/microsoft/tsyringe) for constructor injection.\n\n> _At [Packhelp](https://unpacked.packhelp.com) we’ve refactored most of our 65K SLOC Editor app, that didn't have any IoC, to Iti in under 5 hours_\n\n## Usage\n\n```ts\n// kitchen.ts\nexport class Oven {\n  public pizzasInOven() {\n    return 7\n  }\n  public async preheat() {}\n}\nexport class Kitchen {\n  constructor(public oven: Oven, public userManual: string) {}\n}\n// Application code is free of framework dependencies of decorators\n```\n\n```tsx\n// app.ts\nimport { createContainer } from \"iti\"\nimport { Oven, Kitchen } from \"./kitchen\"\n\nconst container = createContainer()\n  .add({\n    key: () => new Item(),\n    oven: () => new Oven(),\n    userManual: async () => \"Please preheat before use\",\n  })\n  .add((items) => ({\n    kitchen: async () => new Kitchen(items.oven, await items.userManual),\n  }))\n\nawait container.get(\"kitchen\") // Kitchen\n```\n\n```tsx\n// MyPizzaComponent.tsx\nexport const PizzaData = () => {\n  const kitchen = useContainer().kitchen\n  return <>Pizzas In Oven: {kitchen.oven.pizzasInOven()}</>\n}\n```\n\n## Why another library?\n\nThe main reason is that existing libraries don’t support **asynchronous code**. Iti brings hassle free and fully typed way to use async code.\n\nSecondly, existing libraries rely on decorators and `reflect-metadata`[^1]. They **couple your application business logic with a single framework** and they tend to become unnecessarily complex. Also existing implementations will likely be incompatible with a [TC39 proposal](https://github.com/tc39/proposal-decorators).\n\nAlso it is hard to use `reflect-metadata` with starters like CRA, Next.js etc. You need to `eject` or hack starters and it is far from ideal.\n\n## Short Manual\n\n**Reading**\n\n```ts\n// Get a single instance\ncontainer.get(\"oven\") // Creates a new Oven instance\ncontainer.get(\"oven\") // Gets a cached Oven instance\n\nawait container.get(\"kitchen\") // { kitchen: Kitchen } also cached\nawait container.items.kitchen // same as above\n\n// Get multiple instances at once\nawait container.getContainerSet([\"oven\", \"userManual\"]) // { userManual: '...', oven: Oven }\nawait container.getContainerSet((c) => [c.userManual, c.oven]) // same as above\n\n// Plain deletion\ncontainer.delete(\"kitchen\")\n\n// Subscribe to container changes\ncontainer.subscribeToContainer(\"oven\", (oven) => {})\ncontainer.subscribeToContainerSet(\n  [\"oven\", \"kitchen\"],\n  ({ oven, kitchen }) => {},\n)\n// prettier-ignore\ncontainer.subscribeToContainerSet((c) => [c.kitchen], ({ oven, kitchen }) => {})\ncontainer.on(\"containerUpdated\", ({ key, newItem }) => {})\ncontainer.on(\"containerUpserted\", ({ key, newItem }) => {})\ncontainer.on(\"containerDeleted\", ({ key, newItem }) => {})\n\n// Disposing\ncontainer\n  .add({ dbConnection: () => connectToDb(process.env.dbUrl) })\n  .addDisposer({ dbConnection: (db) => db.disconnect() }) // waits for promise\nawait container.dispose(\"dbConnection\")\nawait container.disposeAll()\n```\n\n**Writing**\n\n```ts\nlet container = createContainer()\n  .add({\n    userManual: \"Please preheat before use\",\n    oven: () => new Oven(),\n  })\n  .upsert((items, cont) => ({\n    userManual: \"Works better when hot\",\n    preheatedOven: async () => {\n      await items.oven.preheat()\n      return items.oven\n    },\n  }))\n\n// `add` is typesafe and a runtime safe method. Hence we've used `upsert`\ntry {\n  container.add({\n    // @ts-expect-error\n    userManual: \"You shall not pass\",\n    // Type Error: (property) userManual: \"You are overwriting this token. It is not safe. Use an unsafe `upsert` method\"\n  })\n} catch (err) {\n  err.message // Error Tokens already exist: ['userManual']\n}\n```\n\n## Patterns and tips\n\n### Lifecycle\n\n**Single Instance (a.k.a. Singleton)**\n\n```ts\nlet cont = createContainer().add({\n  oven: () => new Oven(),\n})\ncont.get(\"oven\") === cont.get(\"oven\") // true\n```\n\n**Transient**\n\n```ts\nlet cont = createContainer().add({\n  oven: () => () => new Oven(),\n})\ncont.get(\"oven\") === cont.get(\"oven\") // false\n```\n\n### Dynamic Imports\n\n```ts\n// ./kitchen/index.ts\nexport async function provideKitchenContainer() {\n  const { Kitchen } = await import(\"./kitchen/kitchen\")\n  return {\n    kitchen: () => new Kitchen(),\n    oven: async () => {\n      const { Oven } = await import(\"./kitchen/oven\")\n      const oven = new Oven()\n      await oven.preheat()\n      return oven\n    },\n  }\n}\n```\n\n```ts\n// ./index.ts\nimport { createContainer } from \"iti\"\nimport { provideKitchenContainer } from \"./kitchen\"\nlet cont = createContainer().add({\n  kitchen: async () => provideKitchenContainer(),\n})\n\n// Next line will load `./kitchen/kitchen` module\nawait cont.items.kitchen\n\n// Next line will load `./kitchen/oven` module\nawait cont.items.kitchen.oven\n```\n\n## Getting Started\n\nThe best way to get started is to check [a CRA Pizza example](https://github.com/molszanski/iti/tree/master/examples/cra/src/containers)\n\n## Typescript\n\nIti has a great typescript support. All types are resolved automatically and checked at compile time.\n\n![Autocomplete](./docs/1.png)\n![Autocomplete](./docs/2.png)\n![Autocomplete](./docs/3.png)\n![Autocomplete](./docs/4.png)\n\n## Docs\n\nRead more at [itijs.org/docs/api](https://itijs.org/docs/api#api-documentation-js--ts)\n\n**Notable inspiration**\n\n- https://github.com/nicojs/typed-inject\n- https://github.com/microsoft/tsyringe\n- https://github.com/asvetliakov/Huject\n  https://github.com/jeffijoe/awilix\n- https://github.com/typestack/typedi\n- https://github.com/inversify/InversifyJS\n","readmeFilename":"README.md"}