{"id":15572952,"url":"https://github.com/dkh-dev/app","last_synced_at":"2026-05-01T15:34:38.797Z","repository":{"id":57108741,"uuid":"210254884","full_name":"dkh-dev/app","owner":"dkh-dev","description":"Simple server app","archived":false,"fork":false,"pushed_at":"2021-04-27T03:19:01.000Z","size":165,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-28T11:23:46.644Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dkh-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2019-09-23T03:13:16.000Z","updated_at":"2021-04-27T03:19:03.000Z","dependencies_parsed_at":"2022-08-21T05:00:35.550Z","dependency_job_id":null,"html_url":"https://github.com/dkh-dev/app","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dkh-dev/app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkh-dev%2Fapp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkh-dev%2Fapp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkh-dev%2Fapp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkh-dev%2Fapp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dkh-dev","download_url":"https://codeload.github.com/dkh-dev/app/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkh-dev%2Fapp/sbom","scorecard":{"id":346665,"data":{"date":"2025-08-11","repo":{"name":"github.com/dkh-dev/app","commit":"afd07ec2532407e414aed9fce181c945f54a0772"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/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":"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":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"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":"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":"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":"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":"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":"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":"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":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: ISC 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":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"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"}}]},"last_synced_at":"2025-08-18T07:12:31.252Z","repository_id":57108741,"created_at":"2025-08-18T07:12:31.252Z","updated_at":"2025-08-18T07:12:31.252Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32503197,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"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":[],"created_at":"2024-10-02T18:09:01.981Z","updated_at":"2026-05-01T15:34:38.774Z","avatar_url":"https://github.com/dkh-dev.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @dkh-dev/app\n\n_Simple server app_\n\n## Example\n\n```javascript\n'use strict'\n\nconst App = require('@dkh-dev/app')\n\n\nconst app = new App()\n\napp.get({\n    '/': () =\u003e 'Hello from @dkh-dev/app',\n    '/about': () =\u003e 'Copyright (c) 2019, dangkyokhoang',\n})\n\napp.start()\n```\n\n## Reference\n\n### Configurations\n\n\u003e Note: The default app is shipped with default configurations to make it work out of the box.\n\n`app.yaml`\n\n```dart\nserver:\n    port: \u003cint\u003e [8080]\n\n    keep_alive_timeout: \u003cint\u003e [5000]\n    max_body_size: \u003cint\u003e [1000]\n\nlogger:\n    info: \u003cString\u003e [production ? data/info.log : stdout] // info log\n    error: \u003cString\u003e [production ? data/error.log : stderr] // error log\n    debug: \u003cString\u003e [production ? null : stdout] // debug log\n    \u003cname\u003e: \u003cString\u003e // logger.\u003cname\u003e()\n    // request: data/request.log\n    // database: data/database.log\n\ndatabase:\n    hostname: \u003cString\u003e [localhost]\n    port: \u003cint\u003e [27017]\n\n    name: \u003cString\u003e\n\n    user: \u003cString\u003e\n    password: \u003cString\u003e\n\n    pool_size: \u003cint\u003e [1]\n    ignore_undefined: \u003cbool\u003e [true]\n\nvalidator:\n    strict: \u003cbool\u003e [true]\n    remove_additional: \u003cbool\u003e [true]\n\nkey:\n    size: \u003cint\u003e [64] // must be equal or greater than id size\n    encoding: \u003cString\u003e [base64]\n    collection_name: \u003cString\u003e [keys]\n```\n\n### App\n\n- `app.db: \u003cDb\u003e`\n\n    ```typescript\n    class Db {\n      Promise\u003cvoid\u003e connect() // connects to MongoDB\n\n      Collection get \u003ccollection\u003e() // returns a MongoDB Collection\n      // db.users.find()\n      // db.products.insertOne()\n\n      void close() // closes the database client\n    }\n    ```\n\n- `app.logger: \u003cLogger\u003e`\n\n    ```typescript\n    class Logger {\n      void info() // logs to info log file in production environment\n                  //   or to console in development environment\n\n      void error()\n\n      void debug() // logs to console in development enviroment;\n                    //   does nothing in production environment\n\n      void \u003cname\u003e() // user-defined log stream\n      // logger.request(`requesting ${ url }`)\n      // logger.database(`querying ${ collection }`)\n    }\n    ```\n\n- `app.lock()` — locks paths; requires `authorization: \u003ckey\u003e` to unlock\n\n    ```javascript\n    app.lock([\n      '/admin',\n    ])\n    ```\n\n- `app.use()` — applies middlewares\n\n    ```javascript\n    app.use({\n      '/': log,\n\n      // middlewares are fail-safe\n      // feel free to throw an error from inside\n      '/error': () =\u003e {\n        throw Error('user wants me to fail')\n      },\n    })\n    ```\n\n- `app.schema` — defines schemas or registers validator middlewares\n\n    ```javascript\n    app.schema({\n      // definition schemas\n\n      story: {\n        definitions: {\n          id: { type: 'string', maxLength: 20 },\n          contents: { type: 'string', maxLength: 1000 },\n        },\n      },\n\n      // validator middlewares\n      // keys starting with '/' are paths\n\n      '/duplicate': {\n        type: 'array',\n        items: { type: 'integer' },\n      },\n\n      '/stories/create': {\n        type: 'object',\n        properties: {\n          contents: { $ref: 'story#/definitions/contents' },\n        },\n        additionalProperties: false,\n      },\n    })\n    ```\n\n- `app.get()` — registers `GET` handlers\n\n    ```javascript\n    app.get({\n      '/': home,\n\n      // the return value will be used as the response\n      '/random': () =\u003e Math.random(),\n\n      // async values work\n      '/hello': () =\u003e Promise.resolve('hello'),\n\n      // and so do streams\n      '/data': () =\u003e fs.createReadStream('data.txt'),\n\n      // still you can send response explicitly\n      '/write': (request, response) =\u003e {\n        response.write('text')\n      },\n\n      // handlers are fail-safe\n      // feel free to throw an error from inside\n      '/error': () =\u003e {\n        throw Error('user has requested an error')\n      },\n    })\n    ```\n\n- `app.post()` — registers `POST` handlers\n\n    ```javascript\n    const { HttpError } = require('@dkh-dev/app')\n\n    app.post({\n      '/unlock': () =\u003e true,\n\n      // what you post is what you get\n      '/duplicate' ({ body }) =\u003e duplicate(body),\n\n      // handlers are fail-safe\n      '/error': ({ body: { code } }) =\u003e {\n        throw new HttpError(code, `http error`)\n      }\n    })\n    ```\n\n### Commands\n\n- `npx keygen` — generates a key to unlock locked paths\n\n    ```bash\n    $ npx keygen --scope '/root /admin' --comment 'root'\n    $ npx keygen -s /admin -m admin\n    ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdkh-dev%2Fapp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdkh-dev%2Fapp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdkh-dev%2Fapp/lists"}