{"id":44080188,"url":"https://github.com/alextremp/brusc","last_synced_at":"2026-02-08T08:36:16.556Z","repository":{"id":51197019,"uuid":"229852502","full_name":"alextremp/brusc","owner":"alextremp","description":"brusc is a lightweight but powerful Inversion of Control Container for Javascript projects (Node/Browser)","archived":false,"fork":false,"pushed_at":"2021-05-20T10:25:00.000Z","size":64,"stargazers_count":9,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-05T22:21:44.475Z","etag":null,"topics":["aop","aspect-oriented-programming","dependency-injection","dependency-injection-container","inversion-of-control","ioc","ioc-container","javascript-library"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alextremp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-24T02:05:25.000Z","updated_at":"2025-01-03T12:23:30.000Z","dependencies_parsed_at":"2022-09-13T01:20:50.995Z","dependency_job_id":null,"html_url":"https://github.com/alextremp/brusc","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/alextremp/brusc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alextremp%2Fbrusc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alextremp%2Fbrusc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alextremp%2Fbrusc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alextremp%2Fbrusc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alextremp","download_url":"https://codeload.github.com/alextremp/brusc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alextremp%2Fbrusc/sbom","scorecard":{"id":182721,"data":{"date":"2025-08-11","repo":{"name":"github.com/alextremp/brusc","commit":"5a9499a12ba2eeed78d490298e4c2a374bbeab18"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 2/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 5 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-16T19:09:29.829Z","repository_id":51197019,"created_at":"2025-08-16T19:09:29.829Z","updated_at":"2025-08-16T19:09:29.829Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29225483,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T06:05:31.539Z","status":"ssl_error","status_checked_at":"2026-02-08T05:58:33.853Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aop","aspect-oriented-programming","dependency-injection","dependency-injection-container","inversion-of-control","ioc","ioc-container","javascript-library"],"created_at":"2026-02-08T08:36:15.837Z","updated_at":"2026-02-08T08:36:16.548Z","avatar_url":"https://github.com/alextremp.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg alt=\"brusc logo\" src=\"https://repository-images.githubusercontent.com/229852502/a3866d00-2cff-11ea-9ac7-ece7762a2853\" align=\"center\" width=\"300\"\u003e\n\n[![NPM Module](https://img.shields.io/npm/v/brusc.svg)](https://www.npmjs.com/package/brusc)\n[![Build Status](https://travis-ci.org/alextremp/brusc.svg?branch=master)](https://travis-ci.org/alextremp/brusc)\n[![codecov](https://codecov.io/gh/alextremp/brusc/branch/master/graph/badge.svg)](https://codecov.io/gh/alextremp/brusc)\n[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/alextremp/brusc.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/alextremp/brusc/context:javascript)\n[![Maintainability](https://api.codeclimate.com/v1/badges/82646b2e45f3f84bf903/maintainability)](https://codeclimate.com/github/alextremp/brusc/maintainability)\n\n\n# brusc \n\n**brusc** is a lightweight but powerful Dependency Container to enable Inversion Of Control for Javascript projects (Node/Browser).\n\n* :rocket: Zero dependencies, No extra requirements\n* :zap: Lightweight\n* :fast_forward: Easy to use\n* :factory: No proxies, your provided instances will stay the same that you instantiate \n* :muscle: Improve your project's architecture writing less code\n\n# Features\n* :white_check_mark: Support for declaring singletons\n* :white_check_mark: Support for declaring prototypes\n* :white_check_mark: Support for cross-cutting actions over registered instances \n* :white_check_mark: Does not require declaring instances in any specific order\n* :white_check_mark: Inject your instances where you need them\n* :white_check_mark: Easy integration testing with mocked instances support\n\n**Index**\n\n* [Usage](#usage)\n* [Examples](#examples)\n* [API Reference](#api-reference)\n* [Contributing](#contributing)\n\n# Usage\n\nStart using Brusc:\n- [Install](#install)\n- [Creating an inject function](#creating-an-inject-function)\n- [Defining the Brusc Container](#defining-the-brusc-container)\n- [Using the inject function](#using-the-inject-function)\n- [Integration testing](#integration-testing)\n\nAlso: \n- [Full Brusc API](#full-brusc-api)\n- [Contributing](#contributing)\n\n## Install\n\n```\nnpm install brusc --save\n```\n\n## Creating an inject function\n\nCreate an `inject` function shared across your context to be used in the classes / functions / wherever declaring dependencies to inject:\n\n`inject.js`\n```ecmascript 6\nconst inject = key =\u003e inject.provide(key)\nexport default inject\n```\n\n\u003e The `provide` function will be added by Brusc in next step. This is needed to be created this way in order to enable any class/function to use it like `aProperty=inject('aPropertyKey'')`.\n\n## Defining the Brusc Container\n\nDefine your `inject` bindings to a Brusc Container:\n\n`MovieApplicationInitializer.js`\n```ecmascript 6\n// imports...\nimport Brusc from 'brusc'\nimport inject from './inject'\n\nexport class MovieApplicationInitializer {\n  static init() {\n    Brusc.define(inject)\n      .singleton('getMoviesUseCase', () =\u003e new GetMoviesUseCase())\n      .singleton('saveMovieUseCase', () =\u003e new SaveMovieUseCase())\n      .singleton('movieRepository', () =\u003e new MovieRepositoryHttpImpl())\n      .singleton('httpClient', () =\u003e new AxiosHttpClient())\n      .create()\n      \n    return new MovieApplication()\n  } \n}\n```\n\n## Using the inject function\n\nUse the inject function to assign the instances where they're needed.\n\nIn the last snippet, suppose that the `MovieApplication` is the library facade, which uses the Use Cases, and each one need the `MovieRepository` which also will need a Http Client to perform the actions.\n\nAfter defining the `inject` function in Brusc and creating the container with instance provider declarations like `.singleton(key =\u003e instance_provider_function)` you'll be able to create each application component (use case, service, repository, ...) assigning its dependencies in the constructor (preferably) like:\n\n`GetMoviesUseCase.js`\n```ecmascript 6\nimport inject from './inject'\n\nexport class GetMoviesUseCase {\n  constructor({movieRepository = inject('movieRepository')} = {}) {\n    // ...  \n  }\n}\n```\n\n`MovieApplication.js`\n```ecmascript 6\nimport inject from './inject'\n\nexport class MovieApplication {\n  constructor({getMoviesUseCase = inject('getMoviesUseCase'), saveMovieUseCase = inject('saveMovieUseCase')} = {}) {\n    // ...  \n  }\n}\n```\n\nAnd so on, easy like that :)\n\n## Integration testing\n\nYou'll be able to test the your full application's facade API the same way it'll be used, allowing instance mocks replacing defined instance providers if needed:\n\n```ecmascript 6\n// ...\nimport inject from './inject'\n\ndescribe('MovieApplication', () =\u003e {\n  it('should request the movies collection', async () =\u003e {\n    const httpClientMock = {\n      fetch: (url) =\u003e Promise.resolve(...)\n    }\n    const fetchSpy = sinon.spy(httpClientMock, 'fetch')\n\n    // this instance providers will be used by the Brusc Container instead of defined ones,\n    // and defaults are cleared after container creation to avoid being used in next creations \n    // of another tests, so instance providers can be specified for each test and also be declared in a beforeEach. \n    inject.defaults = {\n      httpClient: () =\u003e httpClientMock\n    }\n\n    // assuming the example of MovieApplicationInitializer in the \"Defining the Brusc Container\" section, \n    // init will create the container to be used in the real Movie Application \n    const movieApplication = MovieApplicationInitializer.init()\n    await movieApplication.getMovies({title: 'robocop'})\n    \n    expect(fetchSpy.getCall(0).args[0]).to.include('title=%robocop%')\n  })\n})\n```\n\n# Full Brusc API\n\nBrusc acts as a Container builder exposing the methods:\n\n## .define\n\n`.define(injectFunction)`\n\nReceives an `injectFunction` to which the Container's instance provider will be assigned in the `injectFunction.provide(key)` function.\n\u003e Should be called only once in the Brusc definition chain.\n\nSee [Creating an inject function](#creating-an-inject-function)\n\n## .singleton\n\n`.singleton(key, instanceProviderFunction, isEager)`\n\nBinds a `key` to an instance provider function to declare a singleton instance in the Container.\n\u003e A singleton is an instance which after first instantiation will be kept in the container and any further requests to the container for the same key will be resolved with that first instantiated instance.\n\u003e\n\u003e This method can be called from zero times to each key/singleton instance provider binding.\n\n- `key` _(required)_ must be any value assignable to a Map key (p.ex. a string like `'userRepository'`, but also a class declaration like `UserRepository` if using class as interface declarations would be accepted).\n- `instanceProviderFunction` _(required)_ must be a function which must return a value when called, no matter if it's a constant, a function or a new class instantiation.\n- `isEager` _(optional, defaults to false)_ indicates if an instance must be loaded just when the Brusc container ends with its declaration (eager), or will be instantiated on the first `inject(key)` usage (lazy).\n\n## .prototype\n\n`.prototype(key, instanceProviderFunction)`\n\nBinds a `key` to an instance provider function to declare prototype instances in the Container.\n\u003e A prototype will be instantiated for each `inject(key)` usage, returning a fresh value for the injection.\n\u003e\n\u003e In most situations, singletons are preferrable over prototypes, but if a component must have a mutable state consider using prototypes.\n\u003e\n\u003e This method can be called from zero times to each key/prototype instance provider binding.\n\n- `key` _(required)_ must be any value assignable to a Map key.\n- `instanceProviderFunction` _(required)_ must be a function which must return a value when called, no matter if it's a constant, a function or a new class instantiation.\n\n## .adapter\n\n`.adapter({name, match, adapt})`\n\nAllow instances to be decorated / proxied / adapted to any custom need, based on key matching, when instances are instantiated in the Container and before they are injected.\n\n\u003e This method can be called from zero times to each instance adapter requirement\n\n- `name` _(optional, but defaults to UnnamedAdapter)_ the name of the adapter, only for debug / error trace intentions.\n- `match(key)` _(required)_ is a function that will be used to detect instances to which apply the modification if returns `true`.\n- `adapt(instance, key)` _(required)_ is a function that must return an instance which can be the original one, but also a decorated one, proxied, ... \n\n```ecmascript 6\n.adapter({\n  name: 'UseCaseTimeLogger',\n  match: key =\u003e key.endsWith('UseCase'),\n  adapt: (instance, key) =\u003e ({ // just for the sample, a specific class would be better :)\n    execute: async params =\u003e {\n      const start = Date.now()\n      try {\n        const result = await instance.execute(params)\n        return result\n      } finally {\n        console.log(`${key} spent ${Date.now() - start}ms to execute`)\n      }\n    }\n  })\n})\n```\n\nIn this case, instead of injecting the original instance defined with p.ex. `.singleton('getMoviesUseCase')`, the injected use case will be a decorated instance to measure the time spent in the use case's `execute` method.\n\n## .create\n\n`.create`\n\nEnds with the Brusc Container declaration for the `inject` method and assigns a `provide` function to it.\n\nSo, after this, the given `inject` function will be enabled for dependency injection, using it like:\n```\nconst anInstance = inject('anInstanceKey')\n```\n\n\u003e Remember that to allow this, the inject function should be declared like `export const inject = key =\u003e inject.provide(key)` \n\n- Trying to inject a dependency before the `create` method is called on Brusc declaration will cause an exception. \n- Trying to inject a dependency that is not declared in the container as singleton or prototype will cause an exception.\n- If any given instance provider function fails on instantiation or an adapter fails to do its job, the thrown error will be raised. \n\n\n# Contributing\n\n:wrench: Maintenance info\n\n## Available Scripts\n\n_npm run_...\n* **phoenix** to reset the project reinstalling its dependencies\n* **lint** to check the code format\n* **test** to run the project tests\n* **check** to run both lint\u0026test\n* **coverage** to get an html test coverage report\n* **build** to build the project\n* **versiona** to publish a new version of the library (in Travis CI)\n\n## Create a PR\n\nUse the PR template to explain:\n* Why the PR should be merged\n* How can be checked\n\n## Deploying\n\nThis project uses Travis CI for:\n* PR validation\n* Merge to master validation\n* NPM publications on Release tag creation\n\nTo create a new Release, take in mind:\n* The Release Tag must be named *vX.Y.Z* where X.Y.Z are the _semver_ numbers that will correspond to the published package's version.\n* Travis CI will launch [versiona](https://www.npmjs.com/package/versiona) which will:\n  * Update \u0026 commit to master the package.json to the X.Y.Z version set in the Release Tag\n  * Publish the NPM package with the X.Y.Z version\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falextremp%2Fbrusc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falextremp%2Fbrusc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falextremp%2Fbrusc/lists"}