void 0.1.6 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. package/AGENT_PROMPT.md +15 -0
  2. package/README.md +62 -123
  3. package/dist/auth-BdsJ0Aff.d.mts +43 -0
  4. package/dist/auth-cmd-Dx8oPKZC.mjs +43 -0
  5. package/dist/auth-migrations-BAtAck2g.mjs +117 -0
  6. package/dist/better-auth-shared-C9_GHSkR.d.mts +71 -0
  7. package/dist/better-auth-shared-CdYmQGry.mjs +163 -0
  8. package/dist/cache-W82I8ihI.mjs +47 -0
  9. package/dist/cancel-deploy-BOBTqqh0.mjs +59 -0
  10. package/dist/cf-access-Dee5cXxL.mjs +22 -0
  11. package/dist/chunk-DJd-R1mw.mjs +34 -0
  12. package/dist/cli/cli.d.mts +1 -0
  13. package/dist/cli/cli.mjs +1807 -0
  14. package/dist/client-snXOjrp1.mjs +565 -0
  15. package/dist/collect-CjeZgz5D.mjs +55 -0
  16. package/dist/config-BIa9HwVX.mjs +573 -0
  17. package/dist/config-BzM9Dy7T.mjs +37 -0
  18. package/dist/config-CvHtTM0q.mjs +30 -0
  19. package/dist/create-project-BIA15W7z.mjs +90 -0
  20. package/dist/db-DsRoMcfN.mjs +895 -0
  21. package/dist/defer-DcxEsVH1.mjs +49 -0
  22. package/dist/delete-DAP6yDc7.mjs +64 -0
  23. package/dist/deploy-BPKblFx6.mjs +2424 -0
  24. package/dist/discover-B7FkXBLB.mjs +40 -0
  25. package/dist/dist-DUyXJLkq.mjs +2667 -0
  26. package/dist/dist-Dayj3gCK.mjs +1287 -0
  27. package/dist/domain-BGofcQ6I.mjs +79 -0
  28. package/dist/dotenv-DwO4ti0Z.mjs +173 -0
  29. package/dist/drizzle-NnudE_UN.mjs +232 -0
  30. package/dist/env-CyG3tvU0.mjs +301 -0
  31. package/dist/env-helpers-Dr9Y7RnE.d.mts +52 -0
  32. package/dist/env-raw-BDL4TvdN.mjs +32 -0
  33. package/dist/env-types-DknSA4SO.mjs +64 -0
  34. package/dist/env-validation-DJKjR_8q.mjs +163 -0
  35. package/dist/fetch-error-BQ8sZ5Nd.mjs +266 -0
  36. package/dist/fetch-error-CVZ5CGA-.d.mts +20 -0
  37. package/dist/gen-U0Ktr4Zd.mjs +761 -0
  38. package/dist/handler-B0ds0OHJ.d.mts +269 -0
  39. package/dist/head-P-egrtFE.d.mts +45 -0
  40. package/dist/headers-DCXc7mDs.mjs +279 -0
  41. package/dist/index.d.mts +32 -0
  42. package/dist/index.mjs +4695 -0
  43. package/dist/init-C7wS5iGP.mjs +2625 -0
  44. package/dist/link-p2R6NbgN.mjs +49 -0
  45. package/dist/list-Bfel-QLc.mjs +113 -0
  46. package/dist/log-DXdqnmhF.mjs +26 -0
  47. package/dist/login-CkcXUiIu.mjs +72 -0
  48. package/dist/logs-DmkrRvx6.mjs +98 -0
  49. package/dist/magic-string.es-D6g9UnIy.mjs +1011 -0
  50. package/dist/mcp-CaQzfeUi.mjs +373 -0
  51. package/dist/node-DDfXj10V.mjs +54 -0
  52. package/dist/output-BwlcIYSR.mjs +139 -0
  53. package/dist/pages/client.d.mts +198 -0
  54. package/dist/pages/client.mjs +980 -0
  55. package/dist/pages/head-client.d.mts +15 -0
  56. package/dist/pages/head-client.mjs +90 -0
  57. package/dist/pages/head.d.mts +2 -0
  58. package/dist/pages/head.mjs +112 -0
  59. package/dist/pages/index.d.mts +38 -0
  60. package/dist/pages/index.mjs +76 -0
  61. package/dist/pages/islands-plugin.d.mts +50 -0
  62. package/dist/pages/islands-plugin.mjs +195 -0
  63. package/dist/pages/prefetch.d.mts +31 -0
  64. package/dist/pages/prefetch.mjs +90 -0
  65. package/dist/pages/protocol.d.mts +3 -0
  66. package/dist/pages/protocol.mjs +193 -0
  67. package/dist/pages/serialize.d.mts +10 -0
  68. package/dist/pages/serialize.mjs +14 -0
  69. package/dist/pathe.M-eThtNZ-D-kmWkCS.mjs +150 -0
  70. package/dist/plugin-inference-oZ6Ybu2_.mjs +2447 -0
  71. package/dist/prepare-BAtWufvm.mjs +99 -0
  72. package/dist/preset-D4I73kT4.mjs +221 -0
  73. package/dist/project-TqORyHn8.mjs +72 -0
  74. package/dist/project-cmd-B7lQp3F3.mjs +67 -0
  75. package/dist/project-slug-CKam8lF9.mjs +11 -0
  76. package/dist/project-tsconfig-DfkESbDL.mjs +63 -0
  77. package/dist/protocol-BWzXs2A2.d.mts +34 -0
  78. package/dist/providers-B3aMxWzP.mjs +67 -0
  79. package/dist/resolve-project-Br5BR03U.mjs +29 -0
  80. package/dist/rollback-gyC59l7U.mjs +92 -0
  81. package/dist/route-types-DReF1gUY.mjs +255 -0
  82. package/dist/routes-stub.d.mts +55 -0
  83. package/dist/routes-stub.mjs +1 -0
  84. package/dist/runner-6Ep3fNQu.mjs +123 -0
  85. package/dist/runner-pg-D0wWHYnr.mjs +57 -0
  86. package/dist/runtime/ai.d.mts +127 -0
  87. package/dist/runtime/ai.mjs +348 -0
  88. package/dist/runtime/auth-client-react.d.mts +8 -0
  89. package/dist/runtime/auth-client-react.mjs +6 -0
  90. package/dist/runtime/auth-client-solid.d.mts +8 -0
  91. package/dist/runtime/auth-client-solid.mjs +6 -0
  92. package/dist/runtime/auth-client-svelte.d.mts +8 -0
  93. package/dist/runtime/auth-client-svelte.mjs +6 -0
  94. package/dist/runtime/auth-client-vue.d.mts +8 -0
  95. package/dist/runtime/auth-client-vue.mjs +6 -0
  96. package/dist/runtime/auth-client.d.mts +8 -0
  97. package/dist/runtime/auth-client.mjs +6 -0
  98. package/dist/runtime/auth.d.mts +2 -0
  99. package/dist/runtime/auth.mjs +22 -0
  100. package/dist/runtime/better-auth-pg.d.mts +11 -0
  101. package/dist/runtime/better-auth-pg.mjs +51 -0
  102. package/dist/runtime/better-auth.d.mts +11 -0
  103. package/dist/runtime/better-auth.mjs +33 -0
  104. package/dist/runtime/client.d.mts +6 -0
  105. package/dist/runtime/client.mjs +5 -0
  106. package/dist/runtime/db-pg.d.mts +2 -0
  107. package/dist/runtime/db-pg.mjs +1 -0
  108. package/dist/runtime/db.d.mts +17 -0
  109. package/dist/runtime/db.mjs +30 -0
  110. package/dist/runtime/drizzle-arktype.d.mts +1 -0
  111. package/dist/runtime/drizzle-arktype.mjs +2 -0
  112. package/dist/runtime/drizzle-valibot.d.mts +1 -0
  113. package/dist/runtime/drizzle-valibot.mjs +2 -0
  114. package/dist/runtime/drizzle-zod.d.mts +1 -0
  115. package/dist/runtime/drizzle-zod.mjs +2 -0
  116. package/dist/runtime/env-helpers.d.mts +2 -0
  117. package/dist/runtime/env-helpers.mjs +173 -0
  118. package/dist/runtime/env-public-client.d.mts +22 -0
  119. package/dist/runtime/env-public-client.mjs +54 -0
  120. package/dist/runtime/env-public.d.mts +143 -0
  121. package/dist/runtime/env-public.mjs +366 -0
  122. package/dist/runtime/env.d.mts +13 -0
  123. package/dist/runtime/env.mjs +51 -0
  124. package/dist/runtime/fetch-stream.d.mts +51 -0
  125. package/dist/runtime/fetch-stream.mjs +81 -0
  126. package/dist/runtime/fetch.d.mts +59 -0
  127. package/dist/runtime/fetch.mjs +18 -0
  128. package/dist/runtime/handler.d.mts +3 -0
  129. package/dist/runtime/handler.mjs +85 -0
  130. package/dist/runtime/isr.d.mts +26 -0
  131. package/dist/runtime/isr.mjs +43 -0
  132. package/dist/runtime/kv.d.mts +48 -0
  133. package/dist/runtime/kv.mjs +106 -0
  134. package/dist/runtime/log.d.mts +24 -0
  135. package/dist/runtime/log.mjs +31 -0
  136. package/dist/runtime/migration-handler-pg.d.mts +6 -0
  137. package/dist/runtime/migration-handler-pg.mjs +85 -0
  138. package/dist/runtime/migration-handler.d.mts +19 -0
  139. package/dist/runtime/migration-handler.mjs +92 -0
  140. package/dist/runtime/queues.d.mts +7 -0
  141. package/dist/runtime/queues.mjs +8 -0
  142. package/dist/runtime/remote/binding-handler.d.mts +15 -0
  143. package/dist/runtime/remote/binding-handler.mjs +208 -0
  144. package/dist/runtime/remote/index.d.mts +8 -0
  145. package/dist/runtime/remote/index.mjs +461 -0
  146. package/dist/runtime/response.d.mts +14 -0
  147. package/dist/runtime/response.mjs +30 -0
  148. package/dist/runtime/sandbox.d.mts +17 -0
  149. package/dist/runtime/sandbox.mjs +19 -0
  150. package/dist/runtime/schema-d1.d.mts +1 -0
  151. package/dist/runtime/schema-d1.mjs +2 -0
  152. package/dist/runtime/schema-pg.d.mts +1 -0
  153. package/dist/runtime/schema-pg.mjs +2 -0
  154. package/dist/runtime/seed.d.mts +30 -0
  155. package/dist/runtime/seed.mjs +6 -0
  156. package/dist/runtime/storage.d.mts +7 -0
  157. package/dist/runtime/storage.mjs +14 -0
  158. package/dist/runtime/validator.d.mts +2 -0
  159. package/dist/runtime/validator.mjs +72 -0
  160. package/dist/runtime/ws-server.d.mts +26 -0
  161. package/dist/runtime/ws-server.mjs +296 -0
  162. package/dist/runtime/ws.d.mts +123 -0
  163. package/dist/runtime/ws.mjs +103 -0
  164. package/dist/scan-Ba4hFwlH.mjs +324 -0
  165. package/dist/scan-C6HMEIdW.mjs +318 -0
  166. package/dist/secret-CeRSukgM.mjs +109 -0
  167. package/dist/skills-ipldjlKE.mjs +62 -0
  168. package/dist/standard-schema-9CRjx-uR.d.mts +42 -0
  169. package/dist/subcommand-prompt-BKjuNAPb.mjs +349 -0
  170. package/dist/sveltekit.d.mts +20 -0
  171. package/dist/sveltekit.mjs +61 -0
  172. package/dist/types-mHOEwpW4.d.mts +57 -0
  173. package/dist/validate-CaMavMxu.mjs +146 -0
  174. package/dist/yarn-pnp-BFqMV_bl.mjs +196 -0
  175. package/getting-started-prompt.txt +26 -0
  176. package/package.json +322 -30
  177. package/schema.json +364 -0
  178. package/skills/migrate-vite-cloudflare-to-void/SKILL.md +175 -0
  179. package/skills/void/SKILL.md +75 -0
  180. package/skills/void/command/void.md +7 -0
  181. package/skills/void/docs/guide/ai.md +235 -0
  182. package/skills/void/docs/guide/app-types.md +103 -0
  183. package/skills/void/docs/guide/auth.md +257 -0
  184. package/skills/void/docs/guide/database/d1.md +106 -0
  185. package/skills/void/docs/guide/database/postgresql.md +106 -0
  186. package/skills/void/docs/guide/database.md +418 -0
  187. package/skills/void/docs/guide/deployment.md +98 -0
  188. package/skills/void/docs/guide/edge/headers.md +79 -0
  189. package/skills/void/docs/guide/edge/prerendering.md +83 -0
  190. package/skills/void/docs/guide/edge/redirects.md +116 -0
  191. package/skills/void/docs/guide/edge/revalidation.md +131 -0
  192. package/skills/void/docs/guide/edge/rewrites.md +354 -0
  193. package/skills/void/docs/guide/edge/static-assets.md +72 -0
  194. package/skills/void/docs/guide/env-vars.md +298 -0
  195. package/skills/void/docs/guide/index.md +80 -0
  196. package/skills/void/docs/guide/jobs.md +91 -0
  197. package/skills/void/docs/guide/kv.md +107 -0
  198. package/skills/void/docs/guide/pages-routing/actions-and-forms.md +419 -0
  199. package/skills/void/docs/guide/pages-routing/head.md +130 -0
  200. package/skills/void/docs/guide/pages-routing/islands.md +405 -0
  201. package/skills/void/docs/guide/pages-routing/layouts.md +362 -0
  202. package/skills/void/docs/guide/pages-routing/loaders.md +267 -0
  203. package/skills/void/docs/guide/pages-routing/markdown.md +625 -0
  204. package/skills/void/docs/guide/pages-routing/overview.md +236 -0
  205. package/skills/void/docs/guide/pages-routing/view-transitions.md +140 -0
  206. package/skills/void/docs/guide/queues.md +140 -0
  207. package/skills/void/docs/guide/quickstart.md +233 -0
  208. package/skills/void/docs/guide/remote-dev.md +67 -0
  209. package/skills/void/docs/guide/sandboxes.md +82 -0
  210. package/skills/void/docs/guide/server-routing.md +246 -0
  211. package/skills/void/docs/guide/ssg.md +74 -0
  212. package/skills/void/docs/guide/ssr.md +105 -0
  213. package/skills/void/docs/guide/storage.md +67 -0
  214. package/skills/void/docs/guide/type-safety.md +179 -0
  215. package/skills/void/docs/guide/typed-fetch.md +113 -0
  216. package/skills/void/docs/guide/websockets.md +190 -0
  217. package/skills/void/docs/index.md +48 -0
  218. package/skills/void/docs/integrations/agents.md +84 -0
  219. package/skills/void/docs/integrations/cloudflare.md +284 -0
  220. package/skills/void/docs/integrations/frameworks/analog.md +182 -0
  221. package/skills/void/docs/integrations/frameworks/astro.md +197 -0
  222. package/skills/void/docs/integrations/frameworks/nuxt.md +164 -0
  223. package/skills/void/docs/integrations/frameworks/overview.md +136 -0
  224. package/skills/void/docs/integrations/frameworks/react-router.md +137 -0
  225. package/skills/void/docs/integrations/frameworks/sveltekit.md +191 -0
  226. package/skills/void/docs/integrations/frameworks/tanstack-start.md +140 -0
  227. package/skills/void/docs/integrations/hono.md +97 -0
  228. package/skills/void/docs/integrations/nodejs-bun-deno.md +210 -0
  229. package/skills/void/docs/node_modules/@iconify/vue/README.md +408 -0
  230. package/skills/void/docs/node_modules/@iconify/vue/offline/readme.md +5 -0
  231. package/skills/void/docs/node_modules/@voidzero-dev/vitepress-theme/README.md +103 -0
  232. package/skills/void/docs/node_modules/oxc-minify/README.md +78 -0
  233. package/skills/void/docs/node_modules/reka-ui/README.md +80 -0
  234. package/skills/void/docs/node_modules/vitepress/README.md +28 -0
  235. package/skills/void/docs/node_modules/vitepress/template/api-examples.md +49 -0
  236. package/skills/void/docs/node_modules/vitepress/template/index.md +28 -0
  237. package/skills/void/docs/node_modules/vitepress/template/markdown-examples.md +85 -0
  238. package/skills/void/docs/node_modules/vitepress-plugin-group-icons/README.md +101 -0
  239. package/skills/void/docs/node_modules/void/AGENTS.md +204 -0
  240. package/skills/void/docs/node_modules/void/AGENT_PROMPT.md +15 -0
  241. package/skills/void/docs/node_modules/void/README.md +89 -0
  242. package/skills/void/docs/node_modules/void/node_modules/@clack/prompts/CHANGELOG.md +591 -0
  243. package/skills/void/docs/node_modules/void/node_modules/@clack/prompts/README.md +375 -0
  244. package/skills/void/docs/node_modules/void/node_modules/@cloudflare/sandbox/README.md +174 -0
  245. package/skills/void/docs/node_modules/void/node_modules/@cloudflare/vite-plugin/README.md +37 -0
  246. package/skills/void/docs/node_modules/void/node_modules/@cloudflare/workers-types/README.md +135 -0
  247. package/skills/void/docs/node_modules/void/node_modules/@electric-sql/pglite/README.md +189 -0
  248. package/skills/void/docs/node_modules/void/node_modules/@hono/oauth-providers/CHANGELOG.md +143 -0
  249. package/skills/void/docs/node_modules/void/node_modules/@hono/oauth-providers/README.md +1272 -0
  250. package/skills/void/docs/node_modules/void/node_modules/@napi-rs/keyring/README.md +19 -0
  251. package/skills/void/docs/node_modules/void/node_modules/@types/better-sqlite3/README.md +15 -0
  252. package/skills/void/docs/node_modules/void/node_modules/@types/node/README.md +15 -0
  253. package/skills/void/docs/node_modules/void/node_modules/@types/pg/README.md +15 -0
  254. package/skills/void/docs/node_modules/void/node_modules/@typescript/native-preview/README.md +22 -0
  255. package/skills/void/docs/node_modules/void/node_modules/@typescript/native-preview/vendor/vscode-jsonrpc/README.md +69 -0
  256. package/skills/void/docs/node_modules/void/node_modules/@void/md/README.md +152 -0
  257. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@shikijs/engine-javascript/README.md +9 -0
  258. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@shikijs/transformers/README.md +9 -0
  259. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@types/node/README.md +15 -0
  260. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/gray-matter/CHANGELOG.md +24 -0
  261. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/gray-matter/README.md +565 -0
  262. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-exit/README.md +124 -0
  263. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-anchor/README.md +600 -0
  264. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-attrs/README.md +386 -0
  265. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-container/README.md +95 -0
  266. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-emoji/README.md +101 -0
  267. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/pathe/README.md +73 -0
  268. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/shiki/README.md +15 -0
  269. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/tinyglobby/README.md +25 -0
  270. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/tsdown/README.md +55 -0
  271. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite/LICENSE.md +2230 -0
  272. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite/README.md +20 -0
  273. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vue/README.md +58 -0
  274. package/skills/void/docs/node_modules/void/node_modules/arktype/README.md +165 -0
  275. package/skills/void/docs/node_modules/void/node_modules/better-auth/LICENSE.md +20 -0
  276. package/skills/void/docs/node_modules/void/node_modules/better-auth/README.md +32 -0
  277. package/skills/void/docs/node_modules/void/node_modules/better-sqlite3/README.md +99 -0
  278. package/skills/void/docs/node_modules/void/node_modules/blake3-jit/README.md +108 -0
  279. package/skills/void/docs/node_modules/void/node_modules/drizzle-arktype/README.md +51 -0
  280. package/skills/void/docs/node_modules/void/node_modules/drizzle-kit/README.md +79 -0
  281. package/skills/void/docs/node_modules/void/node_modules/drizzle-orm/README.md +44 -0
  282. package/skills/void/docs/node_modules/void/node_modules/drizzle-valibot/README.md +51 -0
  283. package/skills/void/docs/node_modules/void/node_modules/drizzle-zod/README.md +65 -0
  284. package/skills/void/docs/node_modules/void/node_modules/es-module-lexer/README.md +390 -0
  285. package/skills/void/docs/node_modules/void/node_modules/estree-walker/README.md +48 -0
  286. package/skills/void/docs/node_modules/void/node_modules/hono/README.md +85 -0
  287. package/skills/void/docs/node_modules/void/node_modules/ignore/README.md +452 -0
  288. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/CHANGELOG.md +76 -0
  289. package/{LICENSE → skills/void/docs/node_modules/void/node_modules/jsonc-parser/LICENSE.md} +21 -21
  290. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/README.md +364 -0
  291. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/SECURITY.md +41 -0
  292. package/skills/void/docs/node_modules/void/node_modules/magic-string/README.md +325 -0
  293. package/skills/void/docs/node_modules/void/node_modules/ofetch/README.md +398 -0
  294. package/skills/void/docs/node_modules/void/node_modules/pathe/README.md +73 -0
  295. package/skills/void/docs/node_modules/void/node_modules/pg/README.md +95 -0
  296. package/skills/void/docs/node_modules/void/node_modules/pglite-server/LICENSE.md +21 -0
  297. package/skills/void/docs/node_modules/void/node_modules/pglite-server/README.md +135 -0
  298. package/skills/void/docs/node_modules/void/node_modules/picocolors/README.md +21 -0
  299. package/skills/void/docs/node_modules/void/node_modules/tinyglobby/README.md +25 -0
  300. package/skills/void/docs/node_modules/void/node_modules/tsdown/README.md +55 -0
  301. package/skills/void/docs/node_modules/void/node_modules/valibot/LICENSE.md +9 -0
  302. package/skills/void/docs/node_modules/void/node_modules/valibot/README.md +94 -0
  303. package/skills/void/docs/node_modules/void/node_modules/vite/LICENSE.md +2230 -0
  304. package/skills/void/docs/node_modules/void/node_modules/vite/README.md +20 -0
  305. package/skills/void/docs/node_modules/void/node_modules/wrangler/README.md +63 -0
  306. package/skills/void/docs/node_modules/void/node_modules/zod/README.md +191 -0
  307. package/skills/void/docs/node_modules/void/skills/migrate-vite-cloudflare-to-void/SKILL.md +175 -0
  308. package/skills/void/docs/node_modules/void/skills/void/SKILL.md +75 -0
  309. package/skills/void/docs/node_modules/void/skills/void/command/void.md +7 -0
  310. package/skills/void/docs/reference/api.md +917 -0
  311. package/skills/void/docs/reference/cli.md +561 -0
  312. package/skills/void/docs/reference/config.md +408 -0
  313. package/skills/void/docs/reference/resource-inference.md +149 -0
  314. package/skills/void/docs/reference/structure.md +176 -0
  315. package/.npmignore +0 -29
  316. package/.travis.yml +0 -9
  317. package/favicon.ico +0 -0
  318. package/index.js +0 -14
  319. package/lib/Job.js +0 -150
  320. package/lib/Void.js +0 -99
  321. package/lib/scan.js +0 -19
  322. package/test/credentials.js +0 -20
  323. package/test/job.js +0 -64
  324. package/test/static/dir1/test6.html +0 -0
  325. package/test/static/dir2/test7.html +0 -0
  326. package/test/static/dir2/test8.html +0 -0
  327. package/test/static/dir2/test9.html +0 -0
  328. package/test/static/test1.html +0 -0
  329. package/test/static/test2.html +0 -0
  330. package/test/static/test3.html +0 -0
  331. package/test/void.js +0 -31
  332. /package/{test/static/dir1/test4.html → skills/void/docs/integrations/auth-providers.md} +0 -0
  333. /package/{test/static/dir1/test5.html → skills/void/docs/integrations/payment-processors.md} +0 -0
@@ -0,0 +1,1272 @@
1
+ # OAuth Providers Middleware
2
+
3
+ [![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=oauth-providers)](https://codecov.io/github/honojs/middleware)
4
+
5
+ Authentication middleware for [Hono](https://github.com/honojs/hono). This package offers a straightforward API for social login with platforms such as Facebook, GitHub, Google, LinkedIn and X(Twitter).
6
+
7
+ ## Installation
8
+
9
+ You can install `hono` and `@hono/oauth-providers` via npm.
10
+
11
+ ```txt
12
+ npm i hono @hono/oauth-providers
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ Open Auth simplifies the OAuth2 flow, enabling you to utilize social login with just a single method.
18
+ On every platform you choose to add to your project you have to add on its platform the **callback uri** or **redirect uri**. Open Auth handles the redirect uri internally as the route you are using the middleware on, so if you decide to use the google auth on the route `/api/v1/auth/google/` the redirect uri will be `DOMAIN/api/v1/auth/google`.
19
+
20
+ ```ts
21
+ app.use(
22
+ "api/v1/auth/google", // -> redirect_uri by default
23
+ googleAuth({ ... })
24
+ )
25
+ ```
26
+
27
+ Also, there is two ways to use this middleware:
28
+
29
+ ```ts
30
+ app.use(
31
+ '/google',
32
+ googleAuth({
33
+ client_id: Bun.env.GOOGLE_ID,
34
+ client_secret: Bun.env.GOOGLE_SECRET,
35
+ scope: ['openid', 'email', 'profile'],
36
+ })
37
+ )
38
+
39
+ app.get('/google', (c) => {
40
+ const token = c.get('token')
41
+ const grantedScopes = c.get('granted-scopes')
42
+ const user = c.get('user-google')
43
+
44
+ return c.json({
45
+ token,
46
+ grantedScopes,
47
+ user,
48
+ })
49
+ })
50
+
51
+ export default app
52
+ ```
53
+
54
+ Or
55
+
56
+ ```ts
57
+ app.get(
58
+ '/google',
59
+ googleAuth({
60
+ client_id: Bun.env.GOOGLE_ID,
61
+ client_secret: Bun.env.GOOGLE_SECRET,
62
+ scope: ['openid', 'email', 'profile'],
63
+ }),
64
+ (c) => {
65
+ const token = c.get('token')
66
+ const grantedScopes = c.get('granted-scopes')
67
+ const user = c.get('user-google')
68
+
69
+ return c.json({
70
+ token,
71
+ grantedScopes,
72
+ user,
73
+ })
74
+ }
75
+ )
76
+
77
+ export default app
78
+ ```
79
+
80
+ ### Google
81
+
82
+ ```ts
83
+ import { Hono } from 'hono'
84
+ import { googleAuth } from '@hono/oauth-providers/google'
85
+
86
+ const app = new Hono()
87
+
88
+ app.use(
89
+ '/google',
90
+ googleAuth({
91
+ client_id: Bun.env.GOOGLE_ID,
92
+ client_secret: Bun.env.GOOGLE_SECRET,
93
+ scope: ['openid', 'email', 'profile'],
94
+ })
95
+ )
96
+
97
+ export default app
98
+ ```
99
+
100
+ #### Parameters
101
+
102
+ - `client_id`:
103
+ - Type: `string`.
104
+ - `Required`.
105
+ - Your app client ID. You can find this value in the API Console [Credentials page](https://console.developers.google.com/apis/credentials). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `GOOGLE_ID=`.
106
+ - `client_secret`:
107
+ - Type: `string`.
108
+ - `Required`.
109
+ - Your app client secret. You can find this value in the API Console [Credentials page](https://console.developers.google.com/apis/credentials). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `GOOGLE_SECRET=`.
110
+ > ⚠️ Do **not** share your **client secret** to ensure the security of your app.
111
+ - `scope`:
112
+ - Type: `string[]`.
113
+ - `Required`.
114
+ - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.<br /> Review all the scopes Google offers for utilizing their API on the [OAuth 2.0 Scopes page](https://developers.google.com/identity/protocols/oauth2/scopes).
115
+ > If your app is not **verified** by Google, the accessible scopes for your app are significantly **limited**.
116
+ - `login_hint`:
117
+ - Type: `string`.
118
+ - `Optional`.
119
+ - Set the parameter value to an email address or `sub` identifier to provide a hint to the Google Authentication Server who is asking for authentication.
120
+ - `prompt`:
121
+ - Type: `string`.
122
+ - `Optional`.
123
+ - Define the prompt the user will receive when logging into their Google account. If not sent, the user will only be prompted the first time your project requests access. <br />Choose one of the following options:
124
+ - `none`: Do not display any authentication or consent screens. Must not be specified with other values.
125
+ - `consent`: Prompt the user for consent.
126
+ - `select_account`: Prompt the user to select an account.
127
+
128
+ #### Authentication Flow
129
+
130
+ After the completion of the Google OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.
131
+
132
+ `googleAuth` method provides 3 set key data:
133
+
134
+ - `token`:
135
+ - Access token to make requests to the google API for retrieving user information and performing actions on their behalf.
136
+ - Type:
137
+ ```
138
+ {
139
+ token: string
140
+ expires_in: number
141
+ }
142
+ ```
143
+ - `granted-scopes`:
144
+ - If the `include_granted_scopes` parameter was set to `true`, you can find here the scopes for which the user has granted permissions.
145
+ - Type: `string[]`.
146
+ - `user-google`:
147
+ - User basic info retrieved from Google
148
+ - Type:
149
+ ```
150
+ {
151
+ id: string
152
+ email: string
153
+ verified_email: boolean
154
+ name: string
155
+ given_name: string
156
+ family_name: string
157
+ picture: string
158
+ locale: string
159
+ }
160
+ ```
161
+
162
+ To access this data, utilize the `c.get` method within the callback of the upcoming HTTP request handler.
163
+
164
+ ```ts
165
+ app.get('/google', (c) => {
166
+ const token = c.get('token')
167
+ const grantedScopes = c.get('granted-scopes')
168
+ const user = c.get('user-google')
169
+
170
+ return c.json({
171
+ token,
172
+ grantedScopes,
173
+ user,
174
+ })
175
+ })
176
+ ```
177
+
178
+ #### Revoke Token
179
+
180
+ In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the `revokeToken` method, which accepts the `token` to be revoked as its unique parameter.
181
+
182
+ ```ts
183
+ import { googleAuth, revokeToken } from '@hono/oauth-providers/google'
184
+
185
+ app.post('/remove-user', async (c, next) => {
186
+ await revokeToken(USER_TOKEN)
187
+
188
+ // ...
189
+ })
190
+ ```
191
+
192
+ ### Facebook
193
+
194
+ ```ts
195
+ import { Hono } from 'hono'
196
+ import { facebookAuth } from '@hono/oauth-providers/facebook'
197
+
198
+ const app = new Hono()
199
+
200
+ app.use(
201
+ '/facebook',
202
+ facebookAuth({
203
+ client_id: Bun.env.FACEBOOK_ID,
204
+ client_secret: Bun.env.FACEBOOK_SECRET,
205
+ scope: ['email', 'public_profile'],
206
+ fields: [
207
+ 'email',
208
+ 'id',
209
+ 'first_name',
210
+ 'last_name',
211
+ 'middle_name',
212
+ 'name',
213
+ 'picture',
214
+ 'short_name',
215
+ ],
216
+ })
217
+ )
218
+
219
+ export default app
220
+ ```
221
+
222
+ #### Parameters
223
+
224
+ - `client_id`:
225
+ - Type: `string`.
226
+ - `Required`.
227
+ - Your app client ID. You can find this value in the App Dashboard [Dashboard page](https://developers.facebook.com/apps). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `FACEBOOK_ID=`.
228
+ - `client_secret`:
229
+ - Type: `string`.
230
+ - `Required`.
231
+ - Your app client secret. You can find this value in the App Dashboard [Dashboard page](https://developers.facebook.com/apps). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `FACEBOOK_SECRET=`.
232
+ > ⚠️ Do **not** share your **client secret** to ensure the security of your app.
233
+ - `scope`:
234
+ - Type: `string[]`.
235
+ - `Required`.
236
+ - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.<br /> Review all the scopes Facebook offers for utilizing their API on the [Permissions page](https://developers.facebook.com/docs/permissions/).
237
+ > If your app is not **verified** by Facebook, the accessible scopes for your app are significantly **limited**.
238
+ - `fields`:
239
+ - Type: `string[]`.
240
+ - Fields you request from the Facebook API to be sent once the user has logged in. You can find a comprehensive reference for all the fields you can request on the [Facebook User Reference page](https://developers.facebook.com/docs/graph-api/reference/user/#fields).
241
+
242
+ #### Authentication Flow
243
+
244
+ After the completion of the Facebook OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.
245
+
246
+ `facebookAuth` method provides 3 set key data:
247
+
248
+ - `token`:
249
+ - Access token to make requests to the Facebook API for retrieving user information and performing actions on their behalf. It has a duration of 60 days.
250
+ - Type:
251
+ ```
252
+ {
253
+ token: string
254
+ expires_in: number
255
+ }
256
+ ```
257
+ - `granted-scopes`:
258
+ - If the `include_granted_scopes` parameter was set to `true`, you can find here the scopes for which the user has granted permissions.
259
+ - Type: `string[]`.
260
+ - `user-facebook`:
261
+ - User basic info retrieved from Facebook
262
+ - Type:
263
+ ```
264
+ {
265
+ id: string
266
+ name: string
267
+ email: string
268
+ picture: {
269
+ data: {
270
+ height: number
271
+ is_silhouette: boolean
272
+ url: string
273
+ width: number
274
+ }
275
+ }
276
+ first_name: string
277
+ last_name: string
278
+ short_name: string
279
+ }
280
+ ```
281
+
282
+ To access this data, utilize the `c.get` method within the callback of the upcoming HTTP request handler.
283
+
284
+ ```ts
285
+ app.get('/facebook', (c) => {
286
+ const token = c.get('token')
287
+ const grantedScopes = c.get('granted-scopes')
288
+ const user = c.get('user-facebook')
289
+
290
+ return c.json({
291
+ token,
292
+ grantedScopes,
293
+ user,
294
+ })
295
+ })
296
+ ```
297
+
298
+ ### GitHub
299
+
300
+ GitHub provides two types of Apps to utilize its API: the `GitHub App` and the `OAuth App`. To understand the differences between these apps, you can read this [article](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/deciding-when-to-build-a-github-app) from GitHub, helping you determine the type of App you should select.
301
+
302
+ #### Parameters
303
+
304
+ - `client_id`:
305
+ - Type: `string`.
306
+ - `Required`.
307
+ - `Github App` and `Oauth App`.
308
+ - Your app client ID. You can find this value in the [GitHub App settings](https://github.com/settings/apps) or the [OAuth App settings](https://github.com/settings/developers) based on your App type. <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `GITHUB_ID=`.
309
+ - `client_secret`:
310
+ - Type: `string`.
311
+ - `Required`.
312
+ - `Github App` and `Oauth App`.
313
+ - Your app client secret. You can find this value in the [GitHub App settings](https://github.com/settings/apps) or the [OAuth App settings](https://github.com/settings/developers) based on your App type. <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `GITHUB_SECRET=`.
314
+ > ⚠️ Do **not** share your **client secret** to ensure the security of your app.
315
+ - `scope`:
316
+ - Type: `string[]`.
317
+ - `Required`.
318
+ - `Oauth App`.
319
+ - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.<br /> Review all the scopes Github offers for utilizing their API on the [Permissions page](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps). <br />For `GitHub Apps`, you select the scopes during the App creation process or in the [settings](https://github.com/settings/apps).
320
+ - `oauthApp`:
321
+ - Type: `boolean`.
322
+ - `Required`.
323
+ - `Oauth App`.
324
+ - Set this value to `true` if your App is of the OAuth App type. Defaults to `false`.
325
+
326
+ #### Authentication Flow
327
+
328
+ After the completion of the Github Auth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.
329
+
330
+ `githubAuth` method provides 4 set key data:
331
+
332
+ - `token`:
333
+ - Access token to make requests to the Github API for retrieving user information and performing actions on their behalf.
334
+ - Type:
335
+ ```
336
+ {
337
+ token: string
338
+ expires_in: number // -> only available for Oauth Apps
339
+ }
340
+ ```
341
+ - `refresh-token`:
342
+ - You can refresh new tokens using this token, which has a longer lifespan. Only available for Oauth Apps.
343
+ - Type:
344
+ ```
345
+ {
346
+ token: string
347
+ expires_in: number
348
+ }
349
+ ```
350
+ - `user-github`:
351
+ - User basic info retrieved from Github
352
+ - Type:
353
+ ```
354
+ {
355
+ login: string
356
+ id: number
357
+ node_id: string
358
+ avatar_url: string
359
+ gravatar_id: string
360
+ url: string
361
+ html_url: string
362
+ followers_url: string
363
+ following_url: string
364
+ gists_url: string
365
+ starred_url: string
366
+ subscriptions_url: string
367
+ organizations_url: string
368
+ repos_url: string
369
+ events_url: string
370
+ received_events_url: string
371
+ type: string
372
+ site_admin: boolean
373
+ name: string
374
+ company: string
375
+ blog: string
376
+ location: string
377
+ email: string | null
378
+ hireable: boolean | null
379
+ bio: string
380
+ twitter_username: string
381
+ public_repos: number
382
+ public_gists: number
383
+ followers: number
384
+ following: number
385
+ created_at: string
386
+ updated_at: string
387
+ private_gists: number, // -> Github App
388
+ total_private_repos: number, // -> Github App
389
+ owned_private_repos: number, // -> Github App
390
+ disk_usage: number, // -> Github App
391
+ collaborators: number, // -> Github App
392
+ two_factor_authentication: boolean, // -> Github App
393
+ plan: {
394
+ name: string,
395
+ space: number,
396
+ collaborators: number,
397
+ private_repos: number
398
+ } // -> Github App
399
+ }
400
+ ```
401
+ - `granted-scopes`:
402
+ - If the `include_granted_scopes` parameter was set to `true`, you can find here the scopes for which the user has granted permissions.
403
+
404
+ #### Github App Example
405
+
406
+ ```ts
407
+ import { Hono } from 'hono'
408
+ import { githubAuth } from '@hono/oauth-providers/github'
409
+
410
+ const app = new Hono()
411
+
412
+ app.use(
413
+ '/github',
414
+ githubAuth({
415
+ client_id: Bun.env.GITHUB_ID,
416
+ client_secret: Bun.env.GITHUB_SECRET,
417
+ })
418
+ )
419
+
420
+ app.get('/github', (c) => {
421
+ const token = c.get('token')
422
+ const user = c.get('user-github')
423
+
424
+ return c.json({
425
+ token,
426
+ user,
427
+ })
428
+ })
429
+
430
+ export default app
431
+ ```
432
+
433
+ #### OAuth App Example
434
+
435
+ ```ts
436
+ import { Hono } from 'hono'
437
+ import { githubAuth } from '@hono/oauth-providers/github'
438
+
439
+ const app = new Hono()
440
+
441
+ app.use(
442
+ '/github',
443
+ githubAuth({
444
+ client_id: Bun.env.GITHUB_ID,
445
+ client_secret: Bun.env.GITHUB_SECRET,
446
+ scope: ['public_repo', 'read:user', 'user', 'user:email', 'user:follow'],
447
+ oauthApp: true,
448
+ })
449
+ )
450
+
451
+ app.get('/github', (c) => {
452
+ const token = c.get('token')
453
+ const refreshToken = c.get('refresh-token')
454
+ const user = c.get('user-github')
455
+
456
+ return c.json({
457
+ token,
458
+ refreshToken,
459
+ user,
460
+ })
461
+ })
462
+
463
+ export default app
464
+ ```
465
+
466
+ ### LinkedIn
467
+
468
+ LinkedIn provides two types of Authorization to utilize its API: the `Member Authotization` and the `Application Authorization`. To understand the differences between these authorization methods, you can read this [article](https://learn.microsoft.com/en-us/linkedin/shared/authentication/authentication?context=linkedin%2Fcontext) from LinkedIn, helping you determine the type of Authorization your app should use.
469
+
470
+ #### Parameters
471
+
472
+ - `client_id`:
473
+ - Type: `string`.
474
+ - `Required`.
475
+ - `Member` and `Application` authorization.
476
+ - Your app client ID. You can find this value in the [LinkedIn Developer Portal](https://www.linkedin.com/developers/apps). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `LINKEDIN_ID=`.
477
+ - `client_secret`:
478
+ - Type: `string`.
479
+ - `Required`.
480
+ - `Member` and `Application` authorization.
481
+ - Your app client secret. You can find this value in the [LinkedIn Developer Portal](https://www.linkedin.com/developers/apps). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `LINKEDIN_SECRET=`.
482
+ > ⚠️ Do **not** share your **client secret** to ensure the security of your app.
483
+ - `scope`:
484
+ - Type: `string[]`.
485
+ - `Required`.
486
+ - `Member Authorization`.
487
+ - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.<br /> Review all the scopes LinkedIn offers for utilizing their API on the [Getting Access docs page](https://learn.microsoft.com/en-us/linkedin/shared/authentication/getting-access).
488
+ - `appAuth`: - Type: `boolean`. - `Required`. - `Application Authorization`. - Set this value to `true` if your App uses the App Authorization method. Defaults to `false`.
489
+ > To access the Application Authorization method you have to ask LinkedIn for It. Apparently you have to verify your app then ask for access.
490
+
491
+ #### Authentication Flow
492
+
493
+ After the completion of the LinkedIn Auth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.
494
+
495
+ `linkedinAuth` method provides 4 set key data:
496
+
497
+ - `token`:
498
+ - Access token to make requests to the LinkedIn API for retrieving user information and performing actions on their behalf.
499
+ - Type:
500
+ ```
501
+ {
502
+ token: string
503
+ expires_in: number
504
+ }
505
+ ```
506
+ - `refresh-token`:
507
+ - You can refresh new tokens using this token, which has a longer lifespan. Only available for Member Authorization.
508
+ - Type:
509
+ ```
510
+ {
511
+ token: string
512
+ expires_in: number
513
+ }
514
+ ```
515
+ - `user-linkedin`:
516
+ - User basic info retrieved from LinkedIn.
517
+ - Type:
518
+ ```
519
+ {
520
+ sub: string
521
+ email_verified: boolean
522
+ name: string
523
+ locale: {
524
+ country: string
525
+ language: string
526
+ },
527
+ given_name: string
528
+ family_name: string
529
+ email: string
530
+ picture: string
531
+ }
532
+ ```
533
+ > Only available for Member Authorization.
534
+ - `granted-scopes`:
535
+ - If the `include_granted_scopes` parameter was set to `true`, you can find here the scopes for which the user has granted permissions.
536
+
537
+ #### Member Authentication Example
538
+
539
+ ```ts
540
+ import { Hono } from 'hono'
541
+ import { linkedinAuth } from '@hono/oauth-providers/linkedin'
542
+
543
+ const app = new Hono()
544
+
545
+ app.use(
546
+ '/linkedin',
547
+ linkedinAuth({
548
+ client_id: Bun.env.LINKEDIN_ID,
549
+ client_secret: Bun.env.LINKEDIN_SECRET,
550
+ scope: ['email', 'openid', 'profile'],
551
+ })
552
+ )
553
+
554
+ app.get('/linkedin', (c) => {
555
+ const token = c.get('token')
556
+ const user = c.get('user-linkedin')
557
+
558
+ return c.json({
559
+ token,
560
+ user,
561
+ })
562
+ })
563
+
564
+ export default app
565
+ ```
566
+
567
+ #### Application Example
568
+
569
+ ```ts
570
+ import { Hono } from 'hono'
571
+ import { linkedinAuth } from '@hono/oauth-providers/linkedin'
572
+
573
+ const app = new Hono()
574
+
575
+ app.use(
576
+ '/linkedin',
577
+ linkedinAuth({
578
+ client_id: Bun.env.LINKEDIN_ID,
579
+ client_secret: Bun.env.LINKEDIN_SECRET,
580
+ appAuth: true,
581
+ })
582
+ )
583
+
584
+ app.get('/linkedin', (c) => {
585
+ const token = c.get('token')
586
+
587
+ return c.json(token)
588
+ })
589
+
590
+ export default app
591
+ ```
592
+
593
+ #### Revoke Token
594
+
595
+ In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the `revokeToken` method.
596
+
597
+ **Parameters**:
598
+
599
+ - `client_id`:
600
+ - `string`.
601
+ - client_secret:
602
+ - `string`.
603
+ - `refresh_token`:
604
+ - `string`.
605
+
606
+ **Return Value**:
607
+
608
+ - `token`:
609
+ - `string`.
610
+
611
+ ```ts
612
+ import { linkedinAuth, refreshToken } from '@hono/oauth-providers/linkedin'
613
+
614
+ app.post('linkedin/refresh-token', async (c, next) => {
615
+ const token = await refreshToken(LINKEDIN_ID, LINKEDIN_SECRET, USER_REFRESH_TOKEN)
616
+
617
+ // ...
618
+ })
619
+ ```
620
+
621
+ ### X (Twitter)
622
+
623
+ ```ts
624
+ import { Hono } from 'hono'
625
+ import { xAuth } from '@hono/oauth-providers/x'
626
+
627
+ const app = new Hono()
628
+
629
+ app.use(
630
+ '/x',
631
+ xAuth({
632
+ client_id: Bun.env.X_ID,
633
+ client_secret: Bun.env.X_SECRET,
634
+ scope: ['tweet.read', 'users.read', 'offline.access'],
635
+ fields: ['profile_image_url', 'url'],
636
+ })
637
+ )
638
+
639
+ export default app
640
+ ```
641
+
642
+ #### Parameters
643
+
644
+ - `client_id`:
645
+ - Type: `string`.
646
+ - `Required`.
647
+ - Your app client ID. You can find this value in the [Developer Portal](https://developer.twitter.com/en/portal/dashboard). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `X_ID=`.
648
+ - `client_secret`:
649
+ - Type: `string`.
650
+ - `Required`.
651
+ - Your app client secret. You can find this value in the [Developer Portal](https://developer.twitter.com/en/portal/dashboard). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `X_SECRET=`.
652
+ > ⚠️ Do **not** share your **client secret** to ensure the security of your app.
653
+ - `scope`:
654
+ - Type: `string[]`.
655
+ - `Required`.
656
+ - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.<br /> Review all the scopes X(Twitter) offers for utilizing their API on the [Documentation](https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code). <br />If not sent the default fields x set are `id`, `name` and `username.`
657
+ - `fields`:
658
+ - Type: `string[]`.
659
+ - `Optional`.
660
+ - Set of **fields** of the user information that can be retreived from X. Check All the fields available on the [get user me reference](https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me).
661
+
662
+ #### Authentication Flow
663
+
664
+ After the completion of the X OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.
665
+
666
+ `xAuth` method provides 4 set key data:
667
+
668
+ - `token`:
669
+ - Access token to make requests to the x API for retrieving user information and performing actions on their behalf.
670
+ - Type:
671
+ ```
672
+ {
673
+ token: string
674
+ expires_in: number
675
+ }
676
+ ```
677
+ - `refresh-token`:
678
+ - You can refresh new tokens using this token. The duration of this token is not specified on the X docs.
679
+ - Type:
680
+ ```
681
+ {
682
+ token: string
683
+ expires_in: number
684
+ }
685
+ ```
686
+ - `granted-scopes`:
687
+ - Scopes for which the user has granted permissions.
688
+ - Type: `string[]`.
689
+ - `user-x`:
690
+ - User basic info retrieved from X
691
+ - Type:
692
+ ```
693
+ {
694
+ created_at: string
695
+ description: string
696
+ entities: {
697
+ url: {
698
+ urls: {
699
+ start: number
700
+ end: number
701
+ url: string
702
+ expanded_url: string
703
+ display_url: string
704
+ }
705
+ }
706
+ }
707
+ id: string
708
+ location: string
709
+ most_recent_tweet_id: string
710
+ name: string
711
+ profile_image_url: string
712
+ protected: boolean
713
+ public_metrics: {
714
+ followers_count: number
715
+ following_count: number
716
+ tweet_count: number
717
+ listed_count: number
718
+ like_count: number
719
+ }
720
+ url: string
721
+ username: string
722
+ verified_type: string
723
+ verified: boolean
724
+ }
725
+ ```
726
+
727
+ > If you want to receive the **refresh token** you must add the `offline.access` in the scopes parameter.
728
+ > To access this data, utilize the `c.get` method within the callback of the upcoming HTTP request handler.
729
+
730
+ ```ts
731
+ app.get('/x', (c) => {
732
+ const token = c.get('token')
733
+ const refreshToken = c.get('refresh-token')
734
+ const grantedScopes = c.get('granted-scopes')
735
+ const user = c.get('user-x')
736
+
737
+ return c.json({
738
+ token,
739
+ refreshToken
740
+ grantedScopes,
741
+ user,
742
+ })
743
+ })
744
+ ```
745
+
746
+ #### Refresh Token
747
+
748
+ Once the user token expires you can refresh their token wihtout the need to prompt the user again for access. In such scenario, you can utilize the `refreshToken` method, which accepts the `client_id`, `client_secret` and `refresh_token` as parameters.
749
+
750
+ > The `refresh_token` can be used once. Once the token is refreshed X gives you a new `refresh_token` along with the new token.
751
+
752
+ ```ts
753
+ import { xAuth, refreshToken } from '@hono/oauth-providers/x'
754
+
755
+ app.post('/x/refresh', async (c, next) => {
756
+ await refreshToken(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN)
757
+
758
+ // ...
759
+ })
760
+ ```
761
+
762
+ #### Revoke Token
763
+
764
+ In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the `revokeToken` method, the `client_id`, `client_secret` and the `token` to be revoked as parameters.
765
+
766
+ It returns a `boolean` to tell whether the token was revoked or not.
767
+
768
+ ```ts
769
+ import { xAuth, revokeToken } from '@hono/oauth-providers/x'
770
+
771
+ app.post('/remove-user', async (c, next) => {
772
+ await revokeToken(CLIENT_ID, CLIENT_SECRET, USER_TOKEN)
773
+
774
+ // ...
775
+ })
776
+ ```
777
+
778
+ ### Discord
779
+
780
+ ```ts
781
+ import { Hono } from 'hono'
782
+ import { discordAuth } from '@hono/oauth-providers/discord'
783
+
784
+ const app = new Hono()
785
+
786
+ app.use(
787
+ '/discord',
788
+ discordAuth({
789
+ client_id: Bun.env.DISCORD_ID,
790
+ client_secret: Bun.env.DISCORD_SECRET,
791
+ scope: ['identify', 'email'],
792
+ })
793
+ )
794
+
795
+ export default app
796
+ ```
797
+
798
+ #### Parameters
799
+
800
+ - `client_id`:
801
+ - Type: `string`.
802
+ - `Required`.
803
+ - Your app client ID. You can find this value in the [Developer Portal](https://discord.com/developers/applications). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `DISCORD_ID=`.
804
+ - `client_secret`:
805
+ - Type: `string`.
806
+ - `Required`.
807
+ - Your app client secret. You can find this value in the [Developer Portal](https://discord.com/developers/applications). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `DISCORD_SECRET=`.
808
+ > ⚠️ Do **not** share your **client secret** to ensure the security of your app.
809
+ - `scope`:
810
+ - Type: `string[]`.
811
+ - `Required`.
812
+ - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.<br /> Review all the scopes Discord offers for utilizing their API on the [Documentation](https://discord.com/developers/docs/reference#api-reference).
813
+
814
+ #### Authentication Flow
815
+
816
+ After the completion of the Discord OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.
817
+
818
+ `discordAuth` method provides 4 set key data:
819
+
820
+ - `token`:
821
+ - Access token to make requests to the Discord API for retrieving user information and performing actions on their behalf.
822
+ - Type:
823
+ ```
824
+ {
825
+ token: string
826
+ expires_in: number
827
+ }
828
+ ```
829
+ - `refresh-token`:
830
+ - You can refresh new tokens using this token. The duration of this token is not specified on the Discord docs.
831
+ - Type:
832
+ ```
833
+ {
834
+ token: string
835
+ expires_in: number
836
+ }
837
+ ```
838
+ > [!NOTE]
839
+ > The refresh token Discord retrieves no implicit expiration
840
+ - `granted-scopes`:
841
+ - Scopes for which the user has granted permissions.
842
+ - Type: `string[]`.
843
+ - `user-discord`:
844
+ - User basic info retrieved from Discord
845
+ - Type:
846
+ ```
847
+ {
848
+ id: string
849
+ username: string
850
+ avatar: string
851
+ discriminator: string
852
+ public_flags: number
853
+ premium_type: number
854
+ flags: number
855
+ banner: string | null
856
+ accent_color: string | null
857
+ global_name: string
858
+ avatar_decoration_data: string | null
859
+ banner_color: string | null
860
+ }
861
+ ```
862
+
863
+ > [!NOTE]
864
+ > To access this data, utilize the `c.get` method within the callback of the upcoming HTTP request handler.
865
+
866
+ ```ts
867
+ app.get('/discord', (c) => {
868
+ const token = c.get('token')
869
+ const refreshToken = c.get('refresh-token')
870
+ const grantedScopes = c.get('granted-scopes')
871
+ const user = c.get('user-discord')
872
+
873
+ return c.json({
874
+ token,
875
+ refreshToken
876
+ grantedScopes,
877
+ user,
878
+ })
879
+ })
880
+ ```
881
+
882
+ #### Refresh Token
883
+
884
+ Once the user token expires you can refresh their token wihtout the need to prompt the user again for access. In such scenario, you can utilize the `refreshToken` method, which accepts the `client_id`, `client_secret` and `refresh_token` as parameters.
885
+
886
+ > [!NOTE]
887
+ > The `refresh_token` can be used once. Once the token is refreshed Discord gives you a new `refresh_token` along with the new token.
888
+
889
+ ```ts
890
+ import { discordAuth, refreshToken } from '@hono/oauth-providers/discord'
891
+
892
+ app.post('/discord/refresh', async (c, next) => {
893
+ const newTokens = await refreshToken(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN)
894
+
895
+ // newTokenes = {
896
+ // token_type: 'bear',
897
+ // access_token: 'skbjbfhj3b4348wdvbwje239'
898
+ // expires_in: 60000
899
+ // refresh_token: 'sfcb0dwd0hdeh29db'
900
+ // scope: "identify email"
901
+ // }
902
+ // ...
903
+ })
904
+ ```
905
+
906
+ #### Revoke Token
907
+
908
+ In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the `revokeToken` method, the `client_id`, `client_secret` and the `token` to be revoked as parameters.
909
+
910
+ It returns a `boolean` to tell whether the token was revoked or not.
911
+
912
+ ```ts
913
+ import { discordAuth, revokeToken } from '@hono/oauth-providers/discord'
914
+
915
+ app.post('/remove-user', async (c, next) => {
916
+ const revoked = await revokeToken(CLIENT_ID, CLIENT_SECRET, USER_TOKEN)
917
+
918
+ // revoked = true | false
919
+ // ...
920
+ })
921
+ ```
922
+
923
+ ### Twitch
924
+
925
+ ```ts
926
+ import { Hono } from 'hono'
927
+ import { twitchAuth } from '@hono/oauth-providers/twitch'
928
+
929
+ const app = new Hono()
930
+
931
+ app.use(
932
+ '/twitch',
933
+ twitchAuth({
934
+ client_id: Bun.env.TWITCH_ID,
935
+ client_secret: Bun.env.TWITCH_SECRET,
936
+ scope: ['user:read:email', 'channel:read:subscriptions', 'bits:read'],
937
+ redirect_uri: 'http://localhost:3000/twitch',
938
+ })
939
+ )
940
+
941
+ export default app
942
+ ```
943
+
944
+ #### Parameters
945
+
946
+ - `client_id`:
947
+ - Type: `string`.
948
+ - `Required`.
949
+ - Your app client ID. You can find this value in the [Twitch Developer Portal](https://dev.twitch.tv/console/apps). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `TWITCH_ID=`.
950
+ - `client_secret`:
951
+ - Type: `string`.
952
+ - `Required`.
953
+ - Your app client secret. You can find this value in the [Twitch Developer Portal](https://dev.twitch.tv/console/apps). <br />When developing **Cloudflare Workers**, there's no need to send this parameter. Just declare it in the `wrangler.toml` file as `TWITCH_SECRET=`.
954
+ > ⚠️ Do **not** share your **client secret** to ensure the security of your app.
955
+ - `scope`:
956
+ - Type: `string[]`.
957
+ - `Required`.
958
+ - Set of **permissions** to request the user's authorization to access your app for retrieving user information and performing actions on their behalf.<br /> Review all the scopes Twitch offers for utilizing their API on the [Twitch API Reference](https://dev.twitch.tv/docs/authentication/scopes).
959
+ - `redirect_uri`:
960
+ - Type: `string`.
961
+ - `Required`.
962
+ - The URI to which the user will be redirected after authentication.
963
+ - `state`:
964
+ - Type: `string`.
965
+ - `Optional`.
966
+ - A unique string to protect against Cross-Site Request Forgery (CSRF) attacks. The state is passed back to your redirect URI after the user has authenticated. You should verify that the state matches the one you provided in the initial request.
967
+ - `force_verify`:
968
+ - Type: `boolean`.
969
+ - `Optional`.
970
+ - Set this value to `true` if you want to force the user to verify their account. Defaults to `false`.
971
+
972
+ #### Authentication Flow
973
+
974
+ After the completion of the Twitch OAuth flow, essential data has been prepared for use in the subsequent steps that your app needs to take.
975
+
976
+ `twitchAuth` method provides 4 set key data:
977
+
978
+ - `token`:
979
+ - Access token to make requests to the Twitch API for retrieving user information and performing actions on their behalf.
980
+ - Type:
981
+ ```
982
+ {
983
+ token: string
984
+ expires_in: number
985
+ }
986
+ ```
987
+ - `refresh-token`:
988
+ - You can refresh new tokens using this token. The duration of this token is not specified on the Twitch docs.
989
+ - Type:
990
+ ```
991
+ {
992
+ token: string
993
+ expires_in: number
994
+ }
995
+ ```
996
+ - `granted-scopes`:
997
+ - Scopes for which the user has granted permissions.
998
+ - Type: `string[]`.
999
+ - `user-twitch`:
1000
+ - User basic info retrieved from Twitch
1001
+ - Type:
1002
+ ```
1003
+ {
1004
+ id: string
1005
+ login: string
1006
+ display_name: string
1007
+ type: string
1008
+ broadcaster_type: string
1009
+ description: string
1010
+ profile_image_url: string
1011
+ offline_image_url: string
1012
+ view_count: number
1013
+ email: string
1014
+ created_at: string
1015
+ }
1016
+ ```
1017
+
1018
+ > [!NOTE]
1019
+ > To access this data, utilize the `c.get` method within the callback of the upcoming HTTP request handler.
1020
+
1021
+ ```ts
1022
+ app.get('/twitch', (c) => {
1023
+ const token = c.get('token')
1024
+ const refreshToken = c.get('refresh-token')
1025
+ const grantedScopes = c.get('granted-scopes')
1026
+ const user = c.get('user-twitch')
1027
+
1028
+ return c.json({
1029
+ token,
1030
+ refreshToken,
1031
+ grantedScopes,
1032
+ user,
1033
+ })
1034
+ })
1035
+ ```
1036
+
1037
+ #### Refresh Token
1038
+
1039
+ Once the user token expires you can refresh their token without the need to prompt the user again for access. In such scenario, you can utilize the `refreshToken` method, which accepts the `client_id`, `client_secret` and `refresh_token` as parameters.
1040
+
1041
+ > [!NOTE]
1042
+ > The `refresh_token` can be used once. Once the token is refreshed Twitch gives you a new `refresh_token` along with the new token.
1043
+
1044
+ ```ts
1045
+ import { twitchAuth, refreshToken } from '@hono/oauth-providers/twitch'
1046
+
1047
+ app.post('/twitch/refresh', async (c, next) => {
1048
+ const newTokens = await refreshToken(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN)
1049
+
1050
+ // newTokens = {
1051
+ // token_type: 'bearer',
1052
+ // access_token: 'new-access-token',
1053
+ // expires_in: 60000,
1054
+ // refresh_token: 'new-refresh-token',
1055
+ // scope: ['user:read:email', 'channel:read:subscriptions', 'bits:read']
1056
+ // }
1057
+ // ...
1058
+ })
1059
+ ```
1060
+
1061
+ #### Revoke Token
1062
+
1063
+ In certain use cases, you may need to programmatically revoke a user's access token. In such scenarios, you can utilize the `revokeToken` method, the `client_id` and the `token` to be revoked as parameters.
1064
+
1065
+ It returns a `boolean` to tell whether the token was revoked or not.
1066
+
1067
+ ```ts
1068
+ import { twitchAuth, revokeToken } from '@hono/oauth-providers/twitch'
1069
+
1070
+ app.post('/remove-user', async (c, next) => {
1071
+ const revoked = await revokeToken(CLIENT_ID, USER_TOKEN)
1072
+
1073
+ // revoked = true | false
1074
+ // ...
1075
+ })
1076
+ ```
1077
+
1078
+ #### Validate Token
1079
+
1080
+ You can validate a Twitch access token to verify it's still valid or to obtain information about the token, such as its expiration date, scopes, and the associated user.
1081
+
1082
+ You can use `validateToken` method, which accepts the `token` to be validated as parameter and returns `TwitchValidateSuccess` if valid or throws `HTTPException` upon failure.
1083
+
1084
+ > **IMPORTANT:** Twitch requires applications to validate OAuth tokens when they start and on an hourly basis thereafter. Failure to validate tokens may result in Twitch taking punitive action, such as revoking API keys or throttling performance. When a token becomes invalid, your app should terminate all sessions using that token immediately. [Read more](https://dev.twitch.tv/docs/authentication/validate-tokens)
1085
+
1086
+ The validation endpoint helps your application detect when tokens become invalid for reasons other than expiration, such as when users disconnect your integration from their Twitch account. When a token becomes invalid, your app should terminate all sessions using that token.
1087
+
1088
+ > For security and compliance, make sure to implement regular token validation in your application. If a token becomes invalid, promptly sign out the user and terminate their OAuth session.
1089
+
1090
+ ### MSEntra
1091
+
1092
+ ```ts
1093
+ import { Hono } from 'hono'
1094
+ import { msentraAuth } from '@hono/oauth-providers/msentra'
1095
+
1096
+ const app = new Hono()
1097
+
1098
+ app.use(
1099
+ '/msentra',
1100
+ msentraAuth({
1101
+ client_id: process.env.MSENTRA_ID,
1102
+ client_secret: process.env.MSENTRA_SECRET,
1103
+ tenant_id: process.env.MSENTRA_TENANT_ID
1104
+ scope: [
1105
+ 'openid',
1106
+ 'profile',
1107
+ 'email',
1108
+ 'https;//graph.microsoft.com/.default',
1109
+ ]
1110
+ })
1111
+ )
1112
+
1113
+ export default app
1114
+ ```
1115
+
1116
+ ### Parameters
1117
+
1118
+ - `client_id`:
1119
+ - Type: `string`.
1120
+ - `Required`.
1121
+ - Your app client Id. You can find this in your Azure Portal.
1122
+ - `client_secret`:
1123
+ - Type: `string`.
1124
+ - `Required`.
1125
+ - Your app client secret. You can find this in your Azure Portal.
1126
+ > ⚠️ Do **not** share your **client secret** to ensure the security of your app.
1127
+ - `tenant_id`:
1128
+ - Type: `string`
1129
+ - `Required`.
1130
+ - Your Microsoft Tenant's Id. You can find this in your Azure Portal.
1131
+ - `scope`:
1132
+ - Type: `string[]`.
1133
+ - `Required`.
1134
+ - Set of **permissions** to request the user's authorization to access your app for retrieving
1135
+ user information and performing actions on their behalf.
1136
+
1137
+ #### Authentication Flow
1138
+
1139
+ After the completion of the MSEntra OAuth flow, essential data has been prepared for use in the
1140
+ subsequent steps that your app needs to take.
1141
+
1142
+ `msentraAuth` method provides 4 set key data:
1143
+
1144
+ - `token`:
1145
+ - Access token to make requests to the MSEntra API for retrieving user information and
1146
+ performing actions on their behalf.
1147
+ - Type:
1148
+ ```
1149
+ {
1150
+ token: string
1151
+ expires_in: number
1152
+ refresh_token: string
1153
+ }
1154
+ ```
1155
+ - `granted-scopes`:
1156
+ - Scopes for which the user has granted permissions.
1157
+ - Type: `string[]`.
1158
+ - `user-msentra`:
1159
+ - User basic info retrieved from MSEntra
1160
+ - Type:
1161
+ ```
1162
+ {
1163
+ businessPhones: string[],
1164
+ displayName: string
1165
+ givenName: string
1166
+ jobTitle: string
1167
+ mail: string
1168
+ mobilePhone: string
1169
+ officeLocation: string
1170
+ surname: string
1171
+ userPrincipalName: string
1172
+ id: string
1173
+ }
1174
+ ```
1175
+
1176
+ > [!NOTE]
1177
+ > To access this data, utilize the `c.get` method within the callback of the upcoming HTTP request
1178
+ > handler.
1179
+
1180
+ ```ts
1181
+ app.get('/msentra', (c) => {
1182
+ const token = c.get('token')
1183
+ const grantedScopes = c.get('granted-scopes')
1184
+ const user = c.get('user-msentra')
1185
+
1186
+ return c.json({
1187
+ token,
1188
+ grantedScopes,
1189
+ user,
1190
+ })
1191
+ })
1192
+ ```
1193
+
1194
+ #### Refresh Token
1195
+
1196
+ Once the user token expires you can refresh their token without the need to prompt the user again
1197
+ for access. In such scenario, you can utilize the `refreshToken` method, which accepts the
1198
+ `client_id`, `client_secret`, `tenant_id`, and `refresh_token` as parameters.
1199
+
1200
+ > [!NOTE]
1201
+ > The `refresh_token` can be used once. Once the token is refreshed MSEntra gives you a new
1202
+ > `refresh_token` along with the new token.
1203
+
1204
+ ```ts
1205
+ import { msentraAuth, refreshToken } from '@hono/oauth-providers/msentra'
1206
+
1207
+ app.get('/msentra/refresh', (c, next) => {
1208
+ const newTokens = await refreshToken({ client_id, client_secret, tenant_id, refresh_token })
1209
+ })
1210
+ ```
1211
+
1212
+ ## Advance Usage
1213
+
1214
+ ### Customize `redirect_uri`
1215
+
1216
+ All the provider middlewares also accept a `redirect_uri` parameter that overrides the default `redirect_uri = c.req.url` behavior.
1217
+
1218
+ This parameters can be useful if
1219
+
1220
+ 1. `hono` process cannot infer correct redirect_uri from the request. For example, when the server runs behind a reverse proxy and have no access to its internet hostname.
1221
+ 2. Or, in need to start oauth flow from a different route.
1222
+ 3. Or, in need to encode more info into `redirect_uri`.
1223
+
1224
+ ```ts
1225
+ const app = new Hono()
1226
+
1227
+ const SITE_ORIGIN = `https://my-site.com`
1228
+ const OAUTH_CALLBACK_PATH = `/oauth/google`
1229
+
1230
+ app.get(
1231
+ '/*',
1232
+ async (c, next) => {
1233
+ const session = readSession(c)
1234
+ if (!session) {
1235
+ // start oauth flow
1236
+ const redirectUri = `${SITE_ORIGIN}${OAUTH_CALLBACK_PATH}?redirect=${encodeURIComponent(
1237
+ c.req.path
1238
+ )}`
1239
+ const oauth = googleAuth({ redirect_uri: redirectUri, ...more })
1240
+ return await oauth(c, next)
1241
+ }
1242
+ },
1243
+ async (c, next) => {
1244
+ // if we are here, the req should contain either a valid session or a valid auth code
1245
+ const session = readSession(c)
1246
+ const authedGoogleUser = c.get('user-google')
1247
+ if (authedGoogleUser) {
1248
+ await saveSession(c, authedGoogleUser)
1249
+ } else if (!session) {
1250
+ throw new HttpException(401)
1251
+ }
1252
+ return next()
1253
+ },
1254
+ async (c, next) => {
1255
+ // serve protected content
1256
+ }
1257
+ )
1258
+ ```
1259
+
1260
+ ## Author
1261
+
1262
+ monoald https://github.com/monoald
1263
+
1264
+ ## License
1265
+
1266
+ MIT
1267
+
1268
+ ## Contribute
1269
+
1270
+ If you want to add new providers, features or solve some bugs don't doubt to create an issue or make a PR.
1271
+
1272
+ For testing purposes run the following code in the parent folder (`middleware/`):