{"id":23120812,"url":"https://github.com/bvalosek/billy","last_synced_at":"2025-09-05T01:45:28.360Z","repository":{"id":16264654,"uuid":"19012803","full_name":"bvalosek/billy","owner":"bvalosek","description":"🐐 A minimal Javascript application harness that stays out of your way and out of your code.","archived":false,"fork":false,"pushed_at":"2018-10-24T20:28:33.000Z","size":147,"stargazers_count":15,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-09-05T01:45:19.068Z","etag":null,"topics":["billy","javascript"],"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/bvalosek.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-04-22T01:23:43.000Z","updated_at":"2023-12-22T01:37:23.000Z","dependencies_parsed_at":"2022-08-04T08:45:13.127Z","dependency_job_id":null,"html_url":"https://github.com/bvalosek/billy","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"purl":"pkg:github/bvalosek/billy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bvalosek%2Fbilly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bvalosek%2Fbilly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bvalosek%2Fbilly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bvalosek%2Fbilly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bvalosek","download_url":"https://codeload.github.com/bvalosek/billy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bvalosek%2Fbilly/sbom","scorecard":{"id":259442,"data":{"date":"2025-08-11","repo":{"name":"github.com/bvalosek/billy","commit":"cb0d103dd5001f9cd4400f91f681c3c4f100f0ad"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.1,"checks":[{"name":"Code-Review","score":1,"reason":"Found 3/29 approved changesets -- score normalized to 1","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":"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":"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":"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":"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":"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":"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":"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":"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 4 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"}},{"name":"Vulnerabilities","score":0,"reason":"32 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-c6rq-rjc2-86v2","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3","Warn: Project is vulnerable to: MAL-2023-462","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-fhjf-83wg-r2j9","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-4g88-fppr-53pp","Warn: Project is vulnerable to: GHSA-4jqc-8m5r-9rpr","Warn: Project is vulnerable to: GHSA-j44m-qm6p-hp7m","Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9","Warn: Project is vulnerable to: GHSA-r628-mhmh-qjhw","Warn: Project is vulnerable to: GHSA-9r2w-394v-53qc","Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh","Warn: Project is vulnerable to: GHSA-qq89-hq3f-393p","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-17T10:29:30.523Z","repository_id":16264654,"created_at":"2025-08-17T10:29:30.523Z","updated_at":"2025-08-17T10:29:30.523Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273699722,"owners_count":25152285,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-04T02:00:08.968Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["billy","javascript"],"created_at":"2024-12-17T06:14:05.261Z","updated_at":"2025-09-05T01:45:23.349Z","avatar_url":"https://github.com/bvalosek.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# billy\n\n[![CircleCI](https://circleci.com/gh/bvalosek/billy/tree/master.svg?style=svg)](https://circleci.com/gh/bvalosek/billy/tree/master)\n\nA minimal application harness that stays out of your way and out of your code.\n\n\u003e This is the v2 branch, which has back-compat breaking changes from v1, see\n\u003e [billy v1.7.3](https://github.com/bvalosek/billy/tree/v1.7.3) for the old\n\u003e version.\n\n## Installation\n\n```\n$ npm install billy\n```\n\n## Overview\n\nThe primary goal and driving philosophy of Billy is to provide a cohesive and\nuseful set of utilities for building an complex application, without creeping\nits way into your business logic and domain code.\n\nBilly is not an opinionated framework that permeates all parts of your\ncodebase, but rather the simple scaffolding that allows you to roll your own\napplication architecture stack, your way.\n\n### The `Application` instance and the Service Stack\n\nThe root of your application is a single instance of the `Application` class:\n\n```javascript\nconst Application = require('billy');\n\nconst app = new Application();\n```\n\nAn application is composed of several **services**. A service is a class that\nsets up and starts the various dependencies in your application. Services\nshould be free of all business logic, and should be the only parts of the\napplication that are aware of Billy.\n\n```javascript\napp.service(AppConfigService);\n\napp.service(PostgresDatabaseService);\n\napp.service(SQSQueueService);\n\napp.service(AuthAPIComponent);\n```\n\nIf a service implements a `start()` method, it will be called (and `await`-ed)\nwhen you call `app.start()` to boot the application.\n\n```javascript\n(async () =\u003e {\n\n  await app.start();\n\n  console.log('all services succesfully instantiated and started -- nice!');\n\n})();\n```\n\nAll services registered (via `Application#service`) will be instantiated (with\ninjected constructors, see below) **in the order in which they were\nregistered**. After all services have been successfully (and synchronously)\ninstantiated, the `start` method will be called on each one (again, in the\norder registered) if implemented. If `start` returns a `Promise`, the app will\nwait for it to resolve before continuing.\n\nIf any service `throw`s during instantiation or during the `start` method (or\nthe `Promise` returned is rejected), then the application will abort its\nstartup.\n\n### The `Container` instance and Dependency Injection\n\n\u003e Philosophy behind the IoC container\n\n#### Registering Dependencies\n\n\u003e The various `container.register*` methods\n\n#### Resolving Dependencies\n\n\u003e Overview of `new` and `call` on the container, and locals\n\n## Environments\n\nBilly is written to run in modern Javascript environments (ES2017) that support\nthe CommonJS module system and the latest ES2017 Spec (e.g, Node 7.10+). It\nuses `async` / `await` from the ES2017 spec, as well as features introduced in\nES2015 (ES6) such as `Promise`, iterables, and `WeakMap`.\n\n### Older JS Runtimes\n\nIf you are not on the absolute cutting edge, you'll want to use a transpiled\nversion of the library.\n\n```javascript\n\n// Transpiled down to ES5 (pre-ES2015 / pre-ES6)\nconst Application = require('billy/es5');\n\n// Targeting Node v6+\nconst Application = require('billy/node6');\n```\n\nSome notes:\n\n* Even when compiling down to ES5, keep in the mind the code still retains the\n  CommonJS module syntax (i.e `require` calls)\n* There are no polyfills for the new global classes like `Promise`, `Map`,\n  `WeakMap`. If these are not available in your environment, you will need to\n  include them first before Billy\n* The `es5` target is dependent on a globally-available regenerator polyfill.\n* For more information on polyfills and regenerator, see [the official Babel\n  docs](http://babeljs.io/docs/usage/polyfill/)\n\n## API\n\n### `Application()`\n\nRoot application class.\n\n```javascript\nconst app = new Application();\n```\n\n#### `Application#service(T)`\n\nRegister a service class with the application.\n\n```javascript\napp.service(PostgresDatabaseService);\n```\n\n#### `Application#start()`\n\nInstantiate and start all services in the order they were registered.\n\n```javascript\nawait app.start();\n```\n\n#### `Application#stop()`\n\nGive each service a chance to shut down in reverse order they were started.\n\n```javascript\nawait app.stop();\n```\n\n#### `Application#container`\n\nReference to the dependency injection container for the application.\n\n### `Container`\n\nThe dependency injection container. There is no need to instantiate this\ndirectly as a reference to the application's container is exposed as a property\non the `Application` instance:\n\n```javascript\nconst container = app.container;\n```\n\n#### `Container#registerValue(tag, thing)`\n\nStore a simple value in the container. Every time the `tag` dependency is\nresolved, the same value is returned.\n\n```javascript\napp.container.registerValue('config', require('./config.json'));\n```\n\n#### `Container#registerFactory(tag, factory)`\n\nStore a factory function in the container. Every time the `tag` dependency is\nresolved, the factory function will be called with its parameters injected.\n\n```javascript\napp.container.registerFactory('currentTime', () =\u003e new Date());\n```\n\n#### `Container#registerClass(tag, T)`\n\nStore a class in the container. Every time the `tag` dependency is resolved, a\nfresh instance of the class is instantiated, with its constructor parameters\ninjected.\n\n```javascript\napp.container.registerClass('logger', ElasticSearchLogger);\n```\n\n#### `Container#registerSingleton(tag, T)`\n\nStore a **singleton** class in the container. The first time `tag` dependency\nis resolved, the class will be instantiated and cached. Each subsequent\nresolution of `tag` will return the original instance after that.\n\n```javascript\napp.container.registerSingleton('db', PostgresDatabaseDriver);\n```\n\n#### `Container#resolve(tag)`\n\nResolve a dependency from the container via its string tag. Typically this\nmethod shouldn't be used directly, but rather rely on automatic injection to\nget a hold of registered dependencies.\n\n```javascript\nconst db = app.container.resolve('db');\n```\n\n## Contributors\n\n* [Brandon Valosek](https://github.com/bvalosek)\n* [Zak Angelle](https://github.com/zakangelle)\n* [Dillon Shook](https://github.com/dshook)\n\n## Testing\n\n```\n$ npm test\n```\n\n## License\n\n[MIT](https://github.com/bvalosek/billy/blob/master/LICENSE)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbvalosek%2Fbilly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbvalosek%2Fbilly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbvalosek%2Fbilly/lists"}