{"id":13722361,"url":"https://github.com/simylein/fluxify","last_synced_at":"2026-02-02T17:52:00.973Z","repository":{"id":169877194,"uuid":"617201903","full_name":"simylein/fluxify","owner":"simylein","description":"a neat little http server library powered by bun for building apis","archived":false,"fork":false,"pushed_at":"2024-09-08T19:16:20.000Z","size":408,"stargazers_count":43,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-07T15:47:47.604Z","etag":null,"topics":["api","bun","http","logger","repository","rest","router","seed","service","sqlite"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simylein.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-21T22:32:21.000Z","updated_at":"2025-04-07T17:06:26.000Z","dependencies_parsed_at":"2023-12-29T13:25:23.185Z","dependency_job_id":"eac885e1-9b33-4915-ab47-a308dfc8220c","html_url":"https://github.com/simylein/fluxify","commit_stats":null,"previous_names":["simylein/fluxify"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/simylein/fluxify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simylein%2Ffluxify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simylein%2Ffluxify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simylein%2Ffluxify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simylein%2Ffluxify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simylein","download_url":"https://codeload.github.com/simylein/fluxify/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simylein%2Ffluxify/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29016533,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-02T16:17:30.374Z","status":"ssl_error","status_checked_at":"2026-02-02T15:58:50.469Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["api","bun","http","logger","repository","rest","router","seed","service","sqlite"],"created_at":"2024-08-03T01:01:27.800Z","updated_at":"2026-02-02T17:52:00.921Z","avatar_url":"https://github.com/simylein.png","language":"TypeScript","readme":"# fluxify\n\n## a neat little library powered by bun for building apis.\n\n## learning by doing\n\n- [scripts](#scripts)\n- [bootstrap](#bootstrap)\n- [entities](#entities)\n- [services](#services)\n- [controllers](#controllers)\n- [authentication](#authentication)\n- [logging](#logging)\n- [seeding](#seeding)\n- [documentation](#documentation)\n\n## api reference\n\n- [lib/auth](#auth)\n- [lib/config](#config)\n- [lib/core](#core)\n- [lib/database](#database)\n- [lib/docs](#docs)\n- [lib/event](#event)\n- [lib/exception](#exception)\n- [lib/fake](#fake)\n- [lib/logger](#logger)\n- [lib/repository](#repository)\n- [lib/router](#router)\n- [lib/validation](#validation)\n\n## learning by doing section\n\n### create a new fluxify project\n\n```sh\nbun create simylein/fluxify\n```\n\nPlease take a look at the little todo app example in the src directory for some basic examples on usage. If you would like to start fresh delete everything in the `src` directory and make sure to keep the `lib` one which is the library. Then create a `main.ts` file inside the `src` directory which will become your entrypoint.\n\n### scripts\n\n- `bun fmt` formats your code using prettier\n- `bun lint` lints your code using eslint\n- `bun check` type checks your code using tsc\n- `bun bundle` bundles your code for portability\n- `bun test:dev` runs your tests with hot reload\n- `bun test:prod` runs your tests for production\n- `bun start:dev` starts your http server with hot reload\n- `bun start:prod` starts your http server for production\n- `bun schema:init` initializes an new empty database\n- `bun schema:drop` drops all registered tables\n- `bun schema:sync` syncs all registered tables\n- `bun schema:seed` runs all registered seeds\n\n### config\n\nconfiguration is done by environment variables in the `.env` file.\nyou can find an example in the `example.env` file.\ndefault values are given below and will be used if none are provided.\n\n`PORT=4000` the server will run on this port, the port must not be occupied \u003cbr\u003e\n`NAME=fluxify` the name of you app, put anything you like, this will show in logs\n\n`ALLOW_ORIGIN=*` used for cors, put your frontend address there, the star is a wildcard \u003cbr\u003e\n`GLOBAL_PREFIX=` if you would like to prefix all your routes, should start with a slash \u003cbr\u003e\n`DEFAULT_VERSION=0` used when no version was provided in the router nor endpoint, 0 means disabled\n\n`JWT_SECRET=random` keep this secret, use a strong random value \u003cbr\u003e\n`JWT_EXPIRY=1600` after that many seconds your token will expire\n\n`CACHE_TTL=0` your cache's time to live in seconds, 0 means disabled \u003cbr\u003e\n`CACHE_LIMIT=0` the maximum amount of items in the cache, 0 means disabled\n\n`THROTTLE_TTL=0` your throttle's time to live in seconds, 0 means disabled \u003cbr\u003e\n`THROTTLE_LIMIT=0` how many requests a single ip may do in the given ttl, 0 means disabled \u003cbr\u003e\n`THROTTLE_REGROW=0` amount of requests which regrow in the given ttl, 0 means disabled\n\n`DATABASE_PATH=:memory:` provide a file path to a database on your system \u003cbr\u003e\n`DATABASE_MODE=readwrite` can either be readwrite or readonly\n\n`LOG_LEVEL=info` can be one of trace debug info warn error, trace will log the most info \u003cbr\u003e\n`LOG_REQUESTS=false` set to true for logging incoming requests, useful in development \u003cbr\u003e\n`LOG_RESPONSES=false` set to true for logging outgoing responses, useful in development\n\n### bootstrap\n\nto start up a fluxify http server use\n\n`main.ts`\n\n```ts\nimport { bootstrap } from 'lib/core';\n// import any controllers you plan on using\n// import './auth/auth.controller.ts';\n\nbootstrap();\n```\n\n`bootstrap` returns a `FluxifyServer` object which enables you to build custom logging\n\n`main.ts`\n\n```ts\nimport { bootstrap } from 'lib/core';\n\nconst server = bootstrap();\nserver.logger({\n\tres: ({ id, timestamp, status, time }) =\u003e {\n\t\tconsole.log('fires on response', { id, timestamp, status, time });\n\t},\n\tinfo: ({ timestamp, message, context }) =\u003e {\n\t\tconsole.log('fires on info', { timestamp, message, context });\n\t},\n});\n```\n\nyou can also register global headers which will be sent in every response\n\n`main.ts`\n\n```ts\nimport { bootstrap } from 'lib/core';\n\nconst server = bootstrap();\nserver.header({ 'cache-control': 'no-cache' });\n```\n\nfor those who do not like json feel free to override request and response serialization\n\n`main.ts`\n\n```ts\nimport { bootstrap } from 'lib/core';\n\nconst server = bootstrap();\nserver.serialize({ req: (request) =\u003e 'hello', res: (body) =\u003e 'world' });\n```\n\n### entities\n\nevery entity has to have an `id: primary()` column\n\n`user.entity.ts`\n\n```ts\nimport { Infer, column, entity, primary } from 'lib/database';\n\nexport const userEntity = entity('user', {\n\tid: primary('uuid'),\n\tusername: column('varchar').length(16),\n\tpassword: column('varchar').length(64),\n});\n\nexport type User = Infer\u003ctypeof userEntity\u003e;\n```\n\n### services\n\nuse the repository to work with entities\n\n`auth.service.ts`\n\n```ts\nimport { repository } from 'lib/repository';\nimport { userEntity } from '../user/user.entity';\nimport { SignUpDto } from './dto/sign-up.dto';\n\nconst userRepository = repository(userEntity);\n\nexport const signUp = async (body: SignUpDto): Promise\u003cvoid\u003e =\u003e {\n\tawait userRepository.insert(body);\n};\n```\n\n### controllers\n\nregister routes\n\n`auth.controller.ts`\n\n```ts\nimport { router } from 'lib/router';\n\nconst app = router();\n\napp.get('/hello', null, () =\u003e {\n\treturn 'hello world'; // will become the response body\n\treturn new Response(); // you can also directly control it\n});\n```\n\nvalidate request bodies\n\n`sign-up.dto.ts`\n\n```ts\nimport { Infer, object, string } from 'lib/validation';\n\nexport const signUpDto = object({\n\tusername: string().max(16),\n\tpassword: string().max(64),\n});\n\nexport type SignUpDto = Infer\u003ctypeof signUpDto\u003e;\n```\n\n`auth.controller.ts`\n\n```ts\nimport { router } from 'lib/router';\nimport { signUp } from './auth.service';\nimport { signUpDto } from './dto/sign-up.dto';\n\nconst app = router('/auth');\n\napp.post('/sign-up', { body: signUpDto }, ({ body }) =\u003e {\n\treturn signUp(body); // enjoy the validated request body\n});\n```\n\nvalidate query params\n\n`user-query.dto.ts`\n\n```ts\nimport { Infer, object, string } from 'lib/validation';\n\nexport const userQueryDto = object({\n\tusername: string().optional().max(16),\n});\n\nexport type UserQueryDto = Infer\u003ctypeof userQueryDto\u003e;\n```\n\n`user.controller.ts`\n\n```ts\nimport { router } from 'lib/router';\nimport { userQueryDto } from './dto/user-query.dto';\nimport { findUsers } from './user.service';\n\nconst app = router('/user');\n\napp.get('', { query: userQueryDto }, ({ query }) =\u003e {\n\treturn findUsers(query); // enjoy the validated query params\n});\n```\n\n### authentication\n\nrequire auth by adding the `jwt: jwtDto` in the schema\n\n```ts\nimport { jwtDto } from 'lib/auth';\nimport { router } from 'lib/router';\nimport { findMe } from './auth.service';\n\nconst app = router('/auth');\n\napp.get('/me', { jwt: jwtDto }, ({ jwt }) =\u003e {\n\treturn findMe(jwt.id);\n});\n```\n\n### logging\n\nuse the built in logger which also calls your custom logger\n\n`any-service.service.ts`\n\n```ts\nimport { debug, info, warn } from 'lib/logger';\n\ndebug('print a debug message');\ninfo('print a info message');\nwarn('print a warn message');\n```\n\n### seeding\n\nyou can register seeds by naming a file `anything.seed.ts`\n\n`user.seed.ts`\n\n```ts\nimport { word, words } from 'lib/fake';\nimport { repository } from 'lib/repository';\nimport { userEntity } from '../user/user.entity';\n\nconst userRepository = repository(userEntity);\n\nexport const users = async (): Promise\u003cvoid\u003e =\u003e {\n\tawait Promise.all(\n\t\t[\n\t\t\t...new Set(\n\t\t\t\tArray(8)\n\t\t\t\t\t.fill(null)\n\t\t\t\t\t.map(() =\u003e word(4)),\n\t\t\t),\n\t\t].map((username) =\u003e userRepository.insert({ username, password: words(4).split(' ').join('-') })),\n\t);\n};\n```\n\n### documentation\n\nyou can return the openapi 3 standard in json\n\n`docs.controller.ts`\n\n```ts\nimport { generateDocs } from 'lib/docs';\nimport { router } from 'lib/router';\n\nconst app = router();\n\napp.get('/docs', null, () =\u003e {\n\treturn generateDocs();\n});\n```\n\n## api reference section\n\n### auth\n\n`hash()` useful for hashing passwords. uses `createHash` from crypto under the hood\n\n`signJwt()` signs json web tokens using the sha256 algorithm. depends on the configured `jwtSecret` and `jwtExpiry` from config. uses `createHmac` from crypto under the hood\n\n`verifyJwt()` verifies json web tokens using the sha256 algorithm. depends on the configured `jwtSecret` and `jwtExpiry` from config. uses `createHmac` from crypto under the hood\n\n`jwtDto` useful for marking a route with authentication. also performs validation to ensure proper content in jwt payload\n\n### config\n\n`config` holds the global configuration state of the application. change properties only if you know what you are doing\n\n### core\n\n`bootstrap()` used for bootstrapping the application\n\n`FluxifyServer` the returned type from bootstrap\n\n### database\n\n`entity()` create entities by providing an table name and some columns. every entity needs at least an `id: primary()` column. pass the return to the `repository` for easy data manipulation\n\n`primary()` this marks your id column as the primary key. uses non nullable uuids version 4 or auto incrementing integers\n\n`column()` create database columns inside the `entity` function\n\n`relation()` this marks a column as a foreign key. provide the entity you would like to relate against\n\n`created()` creates a column which holds the date of creation of said row\n\n`updated()` creates a column which holds the date of last update to said row\n\n`deleted()` creates a column which holds the date on which the entity was soft deleted\n\n`runQuery()` `selectMany()` `selectOne()` `insertOne()` `insertMany()` raw methods in which you may write your sql directly. only use them if you cannot fulfill you needs using the `repository`\n\n`Entity` the return type of the `entity` function\n\n`Infer` provide any entity as the type argument for getting a inferred type which is bound to that entity. works like magic\n\n### docs\n\n`generateDocs()` returns a openapi v3 compliant spec of your api routes. return this from any route handler\n\n### event\n\n`subscribe()` used for server sent events. return this from a get route handler and provide a channel for listening\n\n`emit()` emits an event with some optional data to the specified channel\n\n### exception\n\n`Accepted() NoContent() BadRequest() Unauthorized() Forbidden() NotFound() MethodNotAllowed() Conflict() Gone() IamTeapot() Locked() TooManyRequests() InternalServerError()` throw those for returning the corresponding http status codes. they accept an optional message which will override the default one\n\n### fake\n\n`adjective() adjectives()` returns one or many random adjectives\n\n`color() colors()` returns one or many random colors\n\n`element() elements()` returns one or many random periodic elements\n\n`email() emails()` returns one or many random email addresses\n\n`excuse() excuses()` returns one or many random developer excuses\n\n`material() materials()` returns one or many random materials\n\n`product() products()` returns one or many random products\n\n`quote() quotes()` returns one or many random famous quotes\n\n`sentence() sentences()` returns one or many random conversational sentences\n\n`username() usernames()` returns one or many random usernames\n\n### logger\n\n`trace() debug() info() warn() error()` they all call their console equivalent function internally. also call custom logger functions registered on bootstrap. they only fire if the log level matches or is higher than the specific function\n\n### repository\n\n`repository()` provide an entity and get access to rich data manipulation. use functions like `find()` `insert()` `update()` and `delete()` to work with the chosen entity\n\n`IdEntity` the most basic entity possible. all entities must correspond to this type\n\n`FindOptions FindOneOptions` the types used in `find` and `findOne` from repository. they require generics to work\n\n`InsertData` all keys of an entity which need to be present at insert. requires generics to work\n\n`UpdateData` all keys of an entity which need to be present at update. requires generics to work\n\n### router\n\n`router()` returns access to `get` `post` `put` `patch` `delete` and `all` route handlers. accepts an optional prefix which will affect all routes. you can also override the global prefix or version to be used by its routes\n\n`get() post() put() patch() delete() all()` route handlers used to map http routes in your application. they accept an endpoint and optional schema for validation and a handler which will be called when a request hits said endpoint\n\n### validation\n\n`string() number() boolean() object() uuid() date() union() array() blob()` they all validate types on the runtime while providing awesome intellisense in development\n\n`Infer` provide any dto as the type argument for getting a inferred type which is bound to that dto. works like magic\n","funding_links":[],"categories":["Extensions"],"sub_categories":["Libraries"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimylein%2Ffluxify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimylein%2Ffluxify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimylein%2Ffluxify/lists"}