{"id":28487184,"url":"https://github.com/maks11060/typescript-libs","last_synced_at":"2026-05-10T11:49:37.122Z","repository":{"id":204572810,"uuid":"712141831","full_name":"MAKS11060/typescript-libs","owner":"MAKS11060","description":"Useful TypeScript utilities","archived":false,"fork":false,"pushed_at":"2026-01-27T22:24:54.000Z","size":1726,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-28T06:36:58.128Z","etag":null,"topics":["deno","openapi","typescript","typescript-library","utilities","web","webapi","webauthn"],"latest_commit_sha":null,"homepage":"https://jsr.io/@maks11060","language":"TypeScript","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/MAKS11060.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-10-30T21:55:38.000Z","updated_at":"2026-01-27T20:28:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"7e857bc4-8da1-491f-be20-85239cecaeea","html_url":"https://github.com/MAKS11060/typescript-libs","commit_stats":null,"previous_names":["maks11060/deno-libs","maks11060/typescript-libs"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/MAKS11060/typescript-libs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MAKS11060%2Ftypescript-libs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MAKS11060%2Ftypescript-libs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MAKS11060%2Ftypescript-libs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MAKS11060%2Ftypescript-libs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MAKS11060","download_url":"https://codeload.github.com/MAKS11060/typescript-libs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MAKS11060%2Ftypescript-libs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29490360,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T19:29:10.908Z","status":"ssl_error","status_checked_at":"2026-02-15T19:29:10.419Z","response_time":118,"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":["deno","openapi","typescript","typescript-library","utilities","web","webapi","webauthn"],"created_at":"2025-06-08T04:12:06.834Z","updated_at":"2026-02-15T22:06:46.228Z","avatar_url":"https://github.com/MAKS11060.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Typescript libs\n\n[![JSR Score](https://jsr.io/badges/@maks11060)](https://jsr.io/@maks11060)\n[![CI](https://github.com/MAKS11060/typescript-libs/actions/workflows/ci.yml/badge.svg)](https://github.com/MAKS11060/typescript-libs/actions/workflows/ci.yml)\n\n| Packages                                   |             [JSR](https://jsr.io/@maks11060)             |\n| ------------------------------------------ | :------------------------------------------------------: |\n| [@maks11060/kv][@maks11060/kv]             |       [![JSR][@maks11060/kv badge]][@maks11060/kv]       |\n| [@maks11060/web][@maks11060/web]           |      [![JSR][@maks11060/web badge]][@maks11060/web]      |\n| [@maks11060/oauth2][@maks11060/oauth2]     |   [![JSR][@maks11060/oauth2 badge]][@maks11060/oauth2]   |\n| [@maks11060/openapi][@maks11060/openapi]   |  [![JSR][@maks11060/openapi badge]][@maks11060/openapi]  |\n| [@maks11060/webauthn][@maks11060/webauthn] | [![JSR][@maks11060/webauthn badge]][@maks11060/webauthn] |\n\n| Packages                               |           [JSR](https://jsr.io/@maks11060)           | Repo                                          |\n| -------------------------------------- | :--------------------------------------------------: | --------------------------------------------- |\n| [@maks11060/crypto][@maks11060/crypto] | [![JSR][@maks11060/crypto badge]][@maks11060/crypto] | [github](https://github.com/MAKS11060/crypto) |\n| [@maks11060/bits][@maks11060/bits]     |   [![JSR][@maks11060/bits badge]][@maks11060/bits]   | [github](https://github.com/MAKS11060/bits)   |\n| [@maks11060/otp][@maks11060/otp]       |    [![JSR][@maks11060/otp badge]][@maks11060/otp]    | [github](https://github.com/MAKS11060/otp)    |\n\n[@maks11060/kv]: https://jsr.io/@maks11060/kv\n[@maks11060/kv badge]: https://jsr.io/badges/@maks11060/kv\n[@maks11060/web]: https://jsr.io/@maks11060/web\n[@maks11060/web badge]: https://jsr.io/badges/@maks11060/web\n[@maks11060/oauth2]: https://jsr.io/@maks11060/oauth2\n[@maks11060/oauth2 badge]: https://jsr.io/badges/@maks11060/oauth2\n[@maks11060/openapi]: https://jsr.io/@maks11060/openapi\n[@maks11060/openapi badge]: https://jsr.io/badges/@maks11060/openapi\n[@maks11060/webauthn]: https://jsr.io/@maks11060/webauthn\n[@maks11060/webauthn badge]: https://jsr.io/badges/@maks11060/webauthn\n[@maks11060/crypto]: https://jsr.io/@maks11060/crypto\n[@maks11060/crypto badge]: https://jsr.io/badges/@maks11060/crypto\n[@maks11060/otp]: https://jsr.io/@maks11060/otp\n[@maks11060/otp badge]: https://jsr.io/badges/@maks11060/otp\n[@maks11060/bits]: https://jsr.io/@maks11060/bits\n[@maks11060/bits badge]: https://jsr.io/badges/@maks11060/bits\n\n## Install\n\n```ps\ndeno add jsr:@maks11060/web\n```\n\n```ps\npnpm jsr:@maks11060/web\n```\n\n```ps\nnpx jsr add @maks11060/web\n```\n\n\u003c/details\u003e\n\n## Web\n\n**Features:**\n\n- [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) with middleware\n- [BroadcastChannel](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API) with types\n- [URLPattern](https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API) with typed exec (WIP)\n\n\u003cdetails\u003e\n\u003csummary\u003eUsage example\u003c/summary\u003e\n\n#### Fetch with middleware\n\n```ts\nimport {Fetch} from '@maks11060/web/fetch'\n\nconst api = Fetch({baseUrl: 'https://api.myip.com/'})\n  .use({\n    onRequest({request, options}) {\n      // Add authorization header\n      const headers = new Headers(request.headers)\n      headers.set('Authorization', 'Bearer token')\n      return new Request(request, {headers})\n    },\n    onResponse({response}) {\n      // Log response status\n      console.log(`Response: ${response.status}`)\n    },\n  })\n\nconst response = await api.fetch('/')\nconsole.log(await response.json())\n```\n\n#### BroadcastChannel with types\n\n```ts\nimport {BroadcastChannelTyped} from '@maks11060/web/broadcast-channel'\n\ntype BcType =\n  | {type: 'req'}\n  | {type: 'res'; value: number}\n\nconst bc = new BroadcastChannelTyped\u003cBcType\u003e('bc-test')\n\nbc.addEventListener('message', (e) =\u003e {\n  console.log(e.data)\n  if (e.data.type === 'req') bc.postMessage({type: 'res', value: Date.now()})\n})\n```\n\n#### URLPattern with typed exec (WIP)\n\n```ts\nimport {URLPatternTyped} from '@maks11060/web/url-pattern'\n\nconst p = new URLPatternTyped({\n  pathname: '/users/:userId{/posts/:postId}?',\n})\nconst res = p.exec({pathname: '/users/123'})!\nconsole.log(\n  res.pathname.groups satisfies {userId: string; postId?: string},\n)\n```\n\n\u003c/details\u003e\n\n## Webauthn\n\nimplementation of the `Webauthn` api for a server with a browser-based api\n\n## Openapi\n\nOpenapi 3.1 Schema builder.\n\n- [Usage example (github.com/maks11060/openapi)](https://github.com/MAKS11060/openapi)\n\n## Kv. Based on [Deno.Kv](https://docs.deno.com/api/deno/~/Deno.Kv)\n\n\u003cdetails\u003e\n\u003csummary\u003eUsage example\u003c/summary\u003e\n\n```jsonc\n// deno.json\n{\n  \"unstable\": [\n    \"kv\"\n  ]\n}\n```\n\n```ts\nimport {kvModel} from '@maks11060/kv'\nimport {z} from 'zod'\n\nusing kv = await Deno.openKv(':memory:')\n\nconst userSchema = z.object({\n  id: z.string(),\n  username: z.string().min(2).max(50),\n})\nconst passwdSchema = z.object({\n  id: z.string(),\n  passwd: z.string().min(4).max(60),\n})\nconst userRegisterSchema = z.object({\n  username: userSchema.shape.username,\n  password: passwdSchema.shape.passwd,\n})\nconst userLoginSchema = userRegisterSchema.pick({username: true, password: true})\n\nconst userModel = kvModel(kv, userSchema, {\n  prefix: 'user',\n  primaryKey: 'id',\n  index: {\n    username: {key: (user) =\u003e user.username.toLowerCase()},\n  },\n})\nconst passwdModel = kvModel(kv, passwdSchema, {\n  prefix: 'passwd',\n  primaryKey: 'id',\n})\n\nconst isUsernameAvailable = async (username: string) =\u003e {\n  return !await userModel.findByIndex('username', username)\n}\n\nconst registerUser = async (data: z.input\u003ctypeof userRegisterSchema\u003e) =\u003e {\n  const op = userModel.atomic()\n  const user = await userModel.create({username: data.username}, {op, transaction: true})\n  const passwd = await passwdModel.create({passwd: data.password}, {op, key: user.id})\n\n  return user\n}\n\nconst loginUser = async (data: z.input\u003ctypeof userLoginSchema\u003e) =\u003e {\n  const user = await userModel.findByIndex('username', data.username, {resolve: true})\n  if (!user) throw new Error('User not found')\n\n  const passwd = await passwdModel.find(user.id)\n  if (!passwd || passwd.passwd !== data.password) throw new Error('Password invalid')\n\n  return user\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaks11060%2Ftypescript-libs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaks11060%2Ftypescript-libs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaks11060%2Ftypescript-libs/lists"}