├── .github └── workflows │ ├── playwright.yml │ └── publish.yml ├── .gitignore ├── LICENSE ├── README.md ├── deno.json ├── deno.lock ├── deps.ts ├── extras └── .npmignore ├── mod.ts ├── playwright ├── .gitignore ├── package-lock.json ├── package.json ├── playwright.config.ts ├── test_setup.ts └── tests │ └── sessions.spec.ts ├── scripts └── build_npm.ts ├── src ├── Crypto.ts ├── Middleware.ts ├── Session.ts ├── SessionOptions.ts └── store │ ├── CookieStore.ts │ ├── MemoryStore.ts │ ├── Store.ts │ └── bun │ └── BunSqliteStore.ts └── test ├── bun ├── README.md ├── bun.lockb ├── package.json ├── src │ ├── test_cookie.ts │ └── test_sqlite.ts ├── tmp │ └── .gitkeep └── tsconfig.json ├── cloudflare_pages ├── .gitignore ├── README.md ├── package.json ├── src │ └── index.tsx ├── tsconfig.json ├── vite.config.ts └── wrangler.toml ├── cloudflare_workers ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── src │ └── index.ts └── tsconfig.json ├── deno ├── MakeStore.ts ├── server_deno.ts └── tmp │ └── .gitkeep └── node ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── src └── test_cookie.ts └── tsconfig.json /.github/workflows/playwright.yml: -------------------------------------------------------------------------------- 1 | name: Playwright Tests 2 | on: 3 | push: 4 | branches: [main, master] 5 | pull_request: 6 | branches: [main, master] 7 | 8 | jobs: 9 | test-deno-memory-store: 10 | timeout-minutes: 60 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: actions/setup-node@v4 15 | with: 16 | node-version: 20 17 | - uses: denoland/setup-deno@v2 18 | with: 19 | deno-version: "2.0.0" 20 | - name: Install dependencies 21 | working-directory: ./playwright 22 | run: npm ci 23 | - name: Install Playwright Browsers 24 | working-directory: ./playwright 25 | run: npx playwright install chromium 26 | - name: Run Playwright tests 27 | working-directory: ./playwright 28 | run: npx playwright test 29 | 30 | test-deno-cookie-store: 31 | timeout-minutes: 60 32 | runs-on: ubuntu-latest 33 | env: 34 | STORE: cookie 35 | ENCRYPTION_KEY: password_at_least_32_characters_long 36 | steps: 37 | - uses: actions/checkout@v4 38 | - uses: actions/setup-node@v4 39 | with: 40 | node-version: 20 41 | - uses: denoland/setup-deno@v2 42 | with: 43 | deno-version: "2.0.0" 44 | - name: Install dependencies 45 | working-directory: ./playwright 46 | run: npm ci 47 | - name: Install Playwright Browsers 48 | working-directory: ./playwright 49 | run: npx playwright install chromium 50 | - name: Run Playwright tests 51 | working-directory: ./playwright 52 | run: npx playwright test 53 | 54 | test-bun-cookie-store: 55 | timeout-minutes: 60 56 | runs-on: ubuntu-latest 57 | env: 58 | STORE: cookie 59 | JS_RUNTIME: bun 60 | steps: 61 | - uses: actions/checkout@v4 62 | - uses: actions/setup-node@v4 63 | with: 64 | node-version: 20 65 | - uses: denoland/setup-deno@v2 66 | with: 67 | deno-version: "2.0.0" 68 | - uses: oven-sh/setup-bun@v1 69 | with: 70 | bun-version: 1.0.2 71 | - name: Install dependencies 72 | working-directory: ./playwright 73 | run: npm ci 74 | - name: Install Playwright Browsers 75 | working-directory: ./playwright 76 | run: npx playwright install chromium 77 | - name: Build NPM package for library 78 | run: deno run -A scripts/build_npm.ts 79 | - name: Install bun example server 80 | working-directory: ./test/bun 81 | run: bun install 82 | - name: Run Playwright tests 83 | working-directory: ./playwright 84 | run: npx playwright test 85 | 86 | test-bun-sqlite-store: 87 | timeout-minutes: 60 88 | runs-on: ubuntu-latest 89 | env: 90 | STORE: sqlite 91 | JS_RUNTIME: bun 92 | steps: 93 | - uses: actions/checkout@v4 94 | - uses: actions/setup-node@v4 95 | with: 96 | node-version: 20 97 | - uses: denoland/setup-deno@v2 98 | with: 99 | deno-version: "2.0.0" 100 | - uses: oven-sh/setup-bun@v1 101 | with: 102 | bun-version: 1.0.2 103 | - name: Install dependencies 104 | working-directory: ./playwright 105 | run: npm ci 106 | - name: Install Playwright Browsers 107 | working-directory: ./playwright 108 | run: npx playwright install chromium 109 | - name: Build NPM package for library 110 | run: deno run -A scripts/build_npm.ts 111 | - name: Install bun example server 112 | working-directory: ./test/bun 113 | run: bun install 114 | - name: Run Playwright tests 115 | working-directory: ./playwright 116 | run: npx playwright test 117 | 118 | test-cf-workers-cookie-store: 119 | timeout-minutes: 60 120 | runs-on: ubuntu-latest 121 | env: 122 | JS_RUNTIME: cf_workers 123 | steps: 124 | - uses: actions/checkout@v4 125 | - uses: actions/setup-node@v4 126 | with: 127 | node-version: 20 128 | - uses: denoland/setup-deno@v2 129 | with: 130 | deno-version: "2.0.0" 131 | - name: Install dependencies 132 | working-directory: ./playwright 133 | run: npm ci 134 | - name: Install Playwright Browsers 135 | working-directory: ./playwright 136 | run: npx playwright install chromium 137 | - name: Build NPM package for library 138 | run: deno run -A scripts/build_npm.ts 139 | - name: Install CF Workers example server 140 | working-directory: ./test/cloudflare_workers 141 | run: npm install 142 | - name: Run Playwright tests 143 | working-directory: ./playwright 144 | run: npx playwright test 145 | 146 | test-cf-pages-cookie-store: 147 | timeout-minutes: 60 148 | runs-on: ubuntu-latest 149 | env: 150 | JS_RUNTIME: cf_pages 151 | steps: 152 | - uses: actions/checkout@v4 153 | - uses: actions/setup-node@v4 154 | with: 155 | node-version: 20 156 | - uses: denoland/setup-deno@v2 157 | with: 158 | deno-version: "2.0.0" 159 | - name: Install dependencies 160 | working-directory: ./playwright 161 | run: npm ci 162 | - name: Install Playwright Browsers 163 | working-directory: ./playwright 164 | run: npx playwright install chromium 165 | - name: Build NPM package for library 166 | run: deno run -A scripts/build_npm.ts 167 | - name: Install CF Pages example server 168 | working-directory: ./test/cloudflare_pages 169 | run: npm install 170 | - name: Build Pages for preview 171 | working-directory: ./test/cloudflare_pages 172 | run: npm run build 173 | - name: Run Playwright tests 174 | working-directory: ./playwright 175 | run: npx playwright test 176 | 177 | test-node-cookie-store: 178 | timeout-minutes: 60 179 | runs-on: ubuntu-latest 180 | env: 181 | JS_RUNTIME: node 182 | steps: 183 | - uses: actions/checkout@v4 184 | - uses: actions/setup-node@v4 185 | with: 186 | node-version: 20 187 | - uses: denoland/setup-deno@v2 188 | with: 189 | deno-version: "2.0.0" 190 | - name: Install dependencies 191 | working-directory: ./playwright 192 | run: npm ci 193 | - name: Install Playwright Browsers 194 | working-directory: ./playwright 195 | run: npx playwright install chromium 196 | - name: Build NPM package for library 197 | run: deno run -A scripts/build_npm.ts 198 | - name: Install node example server 199 | working-directory: ./test/node 200 | run: npm install 201 | - name: Run Playwright tests 202 | working-directory: ./playwright 203 | run: npx playwright test 204 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | on: 3 | release: 4 | types: [published] 5 | 6 | jobs: 7 | npm: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | contents: read 11 | id-token: write 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: actions/setup-node@v4 15 | with: 16 | node-version: 20 17 | registry-url: "https://registry.npmjs.org" 18 | - uses: denoland/setup-deno@v2 19 | with: 20 | deno-version: "2.0.0" 21 | - name: Build NPM Package 22 | run: deno run -A scripts/build_npm.ts 23 | - name: Publish to NPM 24 | run: cd npm && npm publish --provenance 25 | env: 26 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 27 | 28 | jsr: 29 | runs-on: ubuntu-latest 30 | permissions: 31 | contents: read 32 | id-token: write 33 | steps: 34 | - uses: actions/checkout@v4 35 | - uses: denoland/setup-deno@v2 36 | with: 37 | deno-version: "2.0.0" 38 | - name: Publish to JSR 39 | run: deno publish 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | /npm 3 | .env 4 | *.sqlite 5 | /tmp 6 | /test/deno/tmp/* 7 | !/test/deno/tmp/.gitkeep 8 | /test/bun/node_modules 9 | /test/bun/tmp/* 10 | !/test/bun/tmp/.gitkeep -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 Joe Sweeney 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hono Sessions Middleware 2 | Use cookie-based sessions with the [Hono](https://hono.dev/) framework. 3 | 4 | ### Supported runtimes 5 | 6 | Hono Sessions is currently tested on these runtimes: 7 | 8 | - Deno 9 | - Cloudflare Workers 10 | - Cloudflare Pages 11 | - Bun 12 | - Node (v20+) 13 | 14 | Other runtimes may work, but are untested. In addition to Hono's requirements, the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) is required for this library. 15 | 16 | ### 🛠️ Features 17 | - Flash messages — data that is deleted once it's read (one-off error messages, etc.) 18 | - Built-in Memory and Cookie storage drivers, as well as [community-supported drivers](https://github.com/jcs224/hono_sessions/wiki/Community-adapters) and the ability to [create your own storage driver](https://github.com/jcs224/hono_sessions/wiki/Creating-a-custom-storage-driver) 19 | - Encrypted cookies thanks to [iron-webcrypto](https://github.com/brc-dd/iron-webcrypto) 20 | - Session expiration after inactivity 21 | - Session key rotation* 22 | - Strong typing for session variables 23 | 24 | > *It is not necessary to rotate CookieStore sessions because of how a pure cookie session works (no server-side state). Therefore, using session key rotation will have no effect while using CookieStore. 25 | 26 | ## Installation and Usage 27 | 28 | ### Deno 29 | 30 | Simply include the package from [JSR](https://jsr.io/@jcs224/hono-sessions) or [NPM](https://www.npmjs.com/package/hono-sessions) 31 | 32 | ```ts 33 | // JSR 34 | import { sessionMiddleware } from 'jsr:@jcs224/hono-sessions' 35 | 36 | // NPM 37 | import { sessionMiddleware } from 'npm:hono-sessions' 38 | ``` 39 | 40 | You can also use `deno add` and not need the `jsr:` specifier. 41 | 42 | ### Node, Bun, Cloudflare Workers, etc. 43 | 44 | Install the NPM package 45 | ``` 46 | npm install hono-sessions 47 | ``` 48 | 49 | ## Examples 50 | 51 | ### Deno 52 | ```ts 53 | import { Hono } from 'npm:hono' 54 | import { 55 | Session, 56 | sessionMiddleware, 57 | CookieStore 58 | } from 'jsr:@jcs224/hono-sessions' 59 | 60 | // Add types to your session data (optional) 61 | type SessionDataTypes = { 62 | 'counter': number 63 | } 64 | 65 | // Set up your Hono instance, using your types 66 | const app = new Hono<{ 67 | Variables: { 68 | session: Session, 69 | session_key_rotation: boolean 70 | } 71 | }>() 72 | 73 | const store = new CookieStore() 74 | 75 | app.use('*', sessionMiddleware({ 76 | store, 77 | encryptionKey: 'password_at_least_32_characters_long', // Required for CookieStore, recommended for others 78 | expireAfterSeconds: 900, // Expire session after 15 minutes of inactivity 79 | cookieOptions: { 80 | sameSite: 'Lax', // Recommended for basic CSRF protection in modern browsers 81 | path: '/', // Required for this library to work properly 82 | httpOnly: true, // Recommended to avoid XSS attacks 83 | }, 84 | })) 85 | 86 | app.get('/', async (c, next) => { 87 | const session = c.get('session') 88 | 89 | session.set('counter', (session.get('counter') || 0) + 1) 90 | 91 | return c.html(`

You have visited this page ${ session.get('counter') } times

`) 92 | }) 93 | 94 | Deno.serve(app.fetch) 95 | ``` 96 | 97 | ### Bun 98 | 99 | ```ts 100 | import { Hono } from 'hono' 101 | import { sessionMiddleware, CookieStore, Session } from 'hono-sessions' 102 | 103 | // Same as Deno, however instead of: 104 | // Deno.serve(app.fetch) 105 | // use: 106 | 107 | export default { 108 | port: 3000, 109 | fetch: app.fetch 110 | } 111 | ``` 112 | 113 | #### Using Bun's SQLite storage driver 114 | 115 | This will automatically create a `database.sqlite` file and a `sessions` table in that sqlite database. 116 | 117 | ```ts 118 | import { Hono } from 'hono' 119 | import { sessionMiddleware } from 'hono-sessions' 120 | import { BunSqliteStore } from 'hono-sessions/bun-sqlite-store' 121 | import { Database } from 'bun:sqlite' 122 | 123 | const app = new Hono() 124 | 125 | const db = new Database('./database.sqlite') 126 | const store = new BunSqliteStore(db) 127 | 128 | app.use('*', sessionMiddleware({ 129 | store, 130 | // ... other session options 131 | })) 132 | 133 | // Other app code 134 | 135 | export default { 136 | port: 3000, 137 | fetch: app.fetch 138 | } 139 | ``` 140 | 141 | ### Cloudflare Workers / Pages 142 | 143 | ```ts 144 | import { Hono } from 'hono' 145 | import { sessionMiddleware, CookieStore, Session } from 'hono-sessions' 146 | 147 | // Same as Deno, however instead of: 148 | // Deno.serve(app.fetch) 149 | // use: 150 | 151 | export default app 152 | ``` 153 | 154 | ## API 155 | 156 | The `session` object returned from `c.get('session')` has several methods: 157 | 158 | - `get(id: string)`: Fetch the value from a given key. 159 | 160 | - `set(id: string, value: any)`: Set a value that can be serialized with `JSON.stringify()` 161 | 162 | - `flash(id: string, value: any)`: Similar to `set()`, however the value is deleted immediately after it's read once. Best used for one-off alerts or form validation messages (login failure, etc.) 163 | 164 | - `forget(id: string)`: Remove a value from the session based on its key 165 | 166 | ## Troubleshooting 167 | 168 | ### TypeScript errors 169 | 170 | Hono has a high upgrade frequency, but the API for middleware this library relies on remains largely unchanged between Hono releases. You may experience a TypeScript error if you use this library with the latest version of Hono. In that case, before you load the middleware into your Hono app, you might want to have TypeScript ignore this error: 171 | 172 | ```ts 173 | // @ts-ignore 174 | app.use('*', sessionMiddleware({ 175 | // ... 176 | })) 177 | ``` 178 | 179 | TypeScript should otherwise work normally. 180 | 181 | ## Contributing 182 | 183 | This package is built Deno-first, so you'll need to have Deno installed in your development environment. See their [website](https://deno.com/) for installation instructions specific to your platform. 184 | 185 | Once Deno is installed, there is a test server you can run a basic web server to check your changes: 186 | 187 | ``` 188 | deno run --allow-net --watch test/deno/server_deno.ts 189 | ``` 190 | 191 | There's also a [Playwright](https://playwright.dev/) test suite. By default, it is set up to run a Deno server with the MemoryStore driver. In Github actions, it runs through a series of runtimes and storage drivers when a pull request is made. 192 | 193 | ``` 194 | cd playwright 195 | npm install 196 | npx playwright test 197 | ``` 198 | -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jcs224/hono-sessions", 3 | "version": "0.7.2", 4 | "exports": "./mod.ts", 5 | "imports": { 6 | "@deno/dnt": "jsr:@deno/dnt@^0.41.3", 7 | "@std/path": "jsr:@std/path@^1.0.7" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4", 3 | "specifiers": { 4 | "jsr:@david/code-block-writer@^13.0.2": "13.0.3", 5 | "jsr:@deno/cache-dir@~0.10.3": "0.10.3", 6 | "jsr:@deno/dnt@~0.41.3": "0.41.3", 7 | "jsr:@std/assert@0.223": "0.223.0", 8 | "jsr:@std/assert@0.226": "0.226.0", 9 | "jsr:@std/bytes@0.223": "0.223.0", 10 | "jsr:@std/fmt@0.223": "0.223.0", 11 | "jsr:@std/fmt@1": "1.0.2", 12 | "jsr:@std/fs@0.223": "0.223.0", 13 | "jsr:@std/fs@1": "1.0.4", 14 | "jsr:@std/fs@~0.229.3": "0.229.3", 15 | "jsr:@std/io@0.223": "0.223.0", 16 | "jsr:@std/path@*": "1.0.6", 17 | "jsr:@std/path@0.223": "0.223.0", 18 | "jsr:@std/path@1": "1.0.7", 19 | "jsr:@std/path@1.0.0-rc.1": "1.0.0-rc.1", 20 | "jsr:@std/path@^1.0.6": "1.0.7", 21 | "jsr:@std/path@^1.0.7": "1.0.7", 22 | "jsr:@std/path@~0.225.2": "0.225.2", 23 | "jsr:@ts-morph/bootstrap@0.24": "0.24.0", 24 | "jsr:@ts-morph/common@0.24": "0.24.0", 25 | "npm:hono@3.12.8": "3.12.8", 26 | "npm:hono@4": "4.6.4", 27 | "npm:iron-webcrypto@0.10.1": "0.10.1", 28 | "npm:iron-webcrypto@^1.2.1": "1.2.1", 29 | "npm:nanoid@5.0.7": "5.0.7" 30 | }, 31 | "jsr": { 32 | "@david/code-block-writer@13.0.3": { 33 | "integrity": "f98c77d320f5957899a61bfb7a9bead7c6d83ad1515daee92dbacc861e13bb7f" 34 | }, 35 | "@deno/cache-dir@0.10.3": { 36 | "integrity": "eb022f84ecc49c91d9d98131c6e6b118ff63a29e343624d058646b9d50404776", 37 | "dependencies": [ 38 | "jsr:@std/fmt@0.223", 39 | "jsr:@std/fs@0.223", 40 | "jsr:@std/io", 41 | "jsr:@std/path@0.223" 42 | ] 43 | }, 44 | "@deno/dnt@0.41.3": { 45 | "integrity": "b2ef2c8a5111eef86cb5bfcae103d6a2938e8e649e2461634a7befb7fc59d6d2", 46 | "dependencies": [ 47 | "jsr:@david/code-block-writer", 48 | "jsr:@deno/cache-dir", 49 | "jsr:@std/fmt@1", 50 | "jsr:@std/fs@1", 51 | "jsr:@std/path@1", 52 | "jsr:@ts-morph/bootstrap" 53 | ] 54 | }, 55 | "@std/assert@0.223.0": { 56 | "integrity": "eb8d6d879d76e1cc431205bd346ed4d88dc051c6366365b1af47034b0670be24" 57 | }, 58 | "@std/assert@0.226.0": { 59 | "integrity": "0dfb5f7c7723c18cec118e080fec76ce15b4c31154b15ad2bd74822603ef75b3" 60 | }, 61 | "@std/bytes@0.223.0": { 62 | "integrity": "84b75052cd8680942c397c2631318772b295019098f40aac5c36cead4cba51a8" 63 | }, 64 | "@std/fmt@0.223.0": { 65 | "integrity": "6deb37794127dfc7d7bded2586b9fc6f5d50e62a8134846608baf71ffc1a5208" 66 | }, 67 | "@std/fmt@1.0.2": { 68 | "integrity": "87e9dfcdd3ca7c066e0c3c657c1f987c82888eb8103a3a3baa62684ffeb0f7a7" 69 | }, 70 | "@std/fs@0.223.0": { 71 | "integrity": "3b4b0550b2c524cbaaa5a9170c90e96cbb7354e837ad1bdaf15fc9df1ae9c31c" 72 | }, 73 | "@std/fs@0.229.3": { 74 | "integrity": "783bca21f24da92e04c3893c9e79653227ab016c48e96b3078377ebd5222e6eb", 75 | "dependencies": [ 76 | "jsr:@std/path@1.0.0-rc.1" 77 | ] 78 | }, 79 | "@std/fs@1.0.4": { 80 | "integrity": "2907d32d8d1d9e540588fd5fe0ec21ee638134bd51df327ad4e443aaef07123c", 81 | "dependencies": [ 82 | "jsr:@std/path@^1.0.6" 83 | ] 84 | }, 85 | "@std/io@0.223.0": { 86 | "integrity": "2d8c3c2ab3a515619b90da2c6ff5ea7b75a94383259ef4d02116b228393f84f1", 87 | "dependencies": [ 88 | "jsr:@std/assert@0.223", 89 | "jsr:@std/bytes" 90 | ] 91 | }, 92 | "@std/path@0.223.0": { 93 | "integrity": "593963402d7e6597f5a6e620931661053572c982fc014000459edc1f93cc3989", 94 | "dependencies": [ 95 | "jsr:@std/assert@0.223" 96 | ] 97 | }, 98 | "@std/path@0.225.2": { 99 | "integrity": "0f2db41d36b50ef048dcb0399aac720a5348638dd3cb5bf80685bf2a745aa506", 100 | "dependencies": [ 101 | "jsr:@std/assert@0.226" 102 | ] 103 | }, 104 | "@std/path@1.0.0-rc.1": { 105 | "integrity": "b8c00ae2f19106a6bb7cbf1ab9be52aa70de1605daeb2dbdc4f87a7cbaf10ff6" 106 | }, 107 | "@std/path@1.0.6": { 108 | "integrity": "ab2c55f902b380cf28e0eec501b4906e4c1960d13f00e11cfbcd21de15f18fed" 109 | }, 110 | "@std/path@1.0.7": { 111 | "integrity": "76a689e07f0e15dcc6002ec39d0866797e7156629212b28f27179b8a5c3b33a1" 112 | }, 113 | "@ts-morph/bootstrap@0.24.0": { 114 | "integrity": "a826a2ef7fa8a7c3f1042df2c034d20744d94da2ee32bf29275bcd4dffd3c060", 115 | "dependencies": [ 116 | "jsr:@ts-morph/common" 117 | ] 118 | }, 119 | "@ts-morph/common@0.24.0": { 120 | "integrity": "12b625b8e562446ba658cdbe9ad77774b4bd96b992ae8bd34c60dbf24d06c1f3", 121 | "dependencies": [ 122 | "jsr:@std/fs@~0.229.3", 123 | "jsr:@std/path@~0.225.2" 124 | ] 125 | } 126 | }, 127 | "npm": { 128 | "hono@3.12.8": { 129 | "integrity": "sha512-vnOEIRdqsp4uHE/dkOBr9EYmTsR86sD/FyG2xhfAQzR9udDRglN1nuO7SGc/7U3HfSorc6PSCNGN6upnVtCmfg==" 130 | }, 131 | "hono@4.6.4": { 132 | "integrity": "sha512-T5WqBkTOcIQblqBKB5mpzaH/A+dSpvVe938xZJCHOmOuYfF7DSwE/9/10+BMvwSPq9N/f6LiQ38HxrZSQOsXKw==" 133 | }, 134 | "iron-webcrypto@0.10.1": { 135 | "integrity": "sha512-QGOS8MRMnj/UiOa+aMIgfyHcvkhqNUsUxb1XzskENvbo+rEfp6TOwqd1KPuDzXC4OnGHcMSVxDGRoilqB8ViqA==" 136 | }, 137 | "iron-webcrypto@1.2.1": { 138 | "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==" 139 | }, 140 | "nanoid@5.0.7": { 141 | "integrity": "sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==" 142 | } 143 | }, 144 | "remote": { 145 | "https://deno.land/std@0.140.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", 146 | "https://deno.land/std@0.140.0/_util/os.ts": "3b4c6e27febd119d36a416d7a97bd3b0251b77c88942c8f16ee5953ea13e2e49", 147 | "https://deno.land/std@0.140.0/bytes/bytes_list.ts": "67eb118e0b7891d2f389dad4add35856f4ad5faab46318ff99653456c23b025d", 148 | "https://deno.land/std@0.140.0/bytes/equals.ts": "fc16dff2090cced02497f16483de123dfa91e591029f985029193dfaa9d894c9", 149 | "https://deno.land/std@0.140.0/bytes/mod.ts": "763f97d33051cc3f28af1a688dfe2830841192a9fea0cbaa55f927b49d49d0bf", 150 | "https://deno.land/std@0.140.0/fmt/colors.ts": "30455035d6d728394781c10755351742dd731e3db6771b1843f9b9e490104d37", 151 | "https://deno.land/std@0.140.0/fs/_util.ts": "0fb24eb4bfebc2c194fb1afdb42b9c3dda12e368f43e8f2321f84fc77d42cb0f", 152 | "https://deno.land/std@0.140.0/fs/ensure_dir.ts": "9dc109c27df4098b9fc12d949612ae5c9c7169507660dcf9ad90631833209d9d", 153 | "https://deno.land/std@0.140.0/io/buffer.ts": "bd0c4bf53db4b4be916ca5963e454bddfd3fcd45039041ea161dbf826817822b", 154 | "https://deno.land/std@0.140.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3", 155 | "https://deno.land/std@0.140.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09", 156 | "https://deno.land/std@0.140.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b", 157 | "https://deno.land/std@0.140.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633", 158 | "https://deno.land/std@0.140.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee", 159 | "https://deno.land/std@0.140.0/path/mod.ts": "d3e68d0abb393fb0bf94a6d07c46ec31dc755b544b13144dee931d8d5f06a52d", 160 | "https://deno.land/std@0.140.0/path/posix.ts": "293cdaec3ecccec0a9cc2b534302dfe308adb6f10861fa183275d6695faace44", 161 | "https://deno.land/std@0.140.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9", 162 | "https://deno.land/std@0.140.0/path/win32.ts": "31811536855e19ba37a999cd8d1b62078235548d67902ece4aa6b814596dd757", 163 | "https://deno.land/std@0.140.0/streams/conversion.ts": "712585bfa0172a97fb68dd46e784ae8ad59d11b88079d6a4ab098ff42e697d21", 164 | "https://deno.land/std@0.181.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", 165 | "https://deno.land/std@0.181.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", 166 | "https://deno.land/std@0.181.0/fs/_util.ts": "65381f341af1ff7f40198cee15c20f59951ac26e51ddc651c5293e24f9ce6f32", 167 | "https://deno.land/std@0.181.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40", 168 | "https://deno.land/std@0.181.0/fs/expand_glob.ts": "e4f56259a0a70fe23f05215b00de3ac5e6ba46646ab2a06ebbe9b010f81c972a", 169 | "https://deno.land/std@0.181.0/fs/walk.ts": "ea95ffa6500c1eda6b365be488c056edc7c883a1db41ef46ec3bf057b1c0fe32", 170 | "https://deno.land/std@0.181.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", 171 | "https://deno.land/std@0.181.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", 172 | "https://deno.land/std@0.181.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0", 173 | "https://deno.land/std@0.181.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", 174 | "https://deno.land/std@0.181.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1", 175 | "https://deno.land/std@0.181.0/path/mod.ts": "bf718f19a4fdd545aee1b06409ca0805bd1b68ecf876605ce632e932fe54510c", 176 | "https://deno.land/std@0.181.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d", 177 | "https://deno.land/std@0.181.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1", 178 | "https://deno.land/std@0.181.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba", 179 | "https://deno.land/std@0.182.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", 180 | "https://deno.land/std@0.182.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", 181 | "https://deno.land/std@0.182.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e", 182 | "https://deno.land/std@0.182.0/fs/_util.ts": "65381f341af1ff7f40198cee15c20f59951ac26e51ddc651c5293e24f9ce6f32", 183 | "https://deno.land/std@0.182.0/fs/empty_dir.ts": "c3d2da4c7352fab1cf144a1ecfef58090769e8af633678e0f3fabaef98594688", 184 | "https://deno.land/std@0.182.0/fs/expand_glob.ts": "e4f56259a0a70fe23f05215b00de3ac5e6ba46646ab2a06ebbe9b010f81c972a", 185 | "https://deno.land/std@0.182.0/fs/walk.ts": "920be35a7376db6c0b5b1caf1486fb962925e38c9825f90367f8f26b5e5d0897", 186 | "https://deno.land/std@0.182.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", 187 | "https://deno.land/std@0.182.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", 188 | "https://deno.land/std@0.182.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0", 189 | "https://deno.land/std@0.182.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", 190 | "https://deno.land/std@0.182.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1", 191 | "https://deno.land/std@0.182.0/path/mod.ts": "bf718f19a4fdd545aee1b06409ca0805bd1b68ecf876605ce632e932fe54510c", 192 | "https://deno.land/std@0.182.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d", 193 | "https://deno.land/std@0.182.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1", 194 | "https://deno.land/std@0.182.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba", 195 | "https://deno.land/std@0.198.0/collections/filter_values.ts": "16e1fc456a7969e770ec5b89edf5ac97b295ca534b47c1a83f061b409aad7814", 196 | "https://deno.land/std@0.198.0/collections/without_all.ts": "1e3cccb1ed0659455b473c0766d9414b7710d8cef48862c899f445178f66b779", 197 | "https://deno.land/std@0.198.0/dotenv/load.ts": "0636983549b98f29ab75c9a22a42d9723f0a389ece5498fe971e7bb2556a12e2", 198 | "https://deno.land/std@0.198.0/dotenv/mod.ts": "ff7acf1c97ba57af512ecb6f9094fa96e1f63cca1960a7687616fa86bab7e356", 199 | "https://deno.land/x/code_block_writer@12.0.0/mod.ts": "2c3448060e47c9d08604c8f40dee34343f553f33edcdfebbf648442be33205e5", 200 | "https://deno.land/x/code_block_writer@12.0.0/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff", 201 | "https://deno.land/x/deno_cache@0.5.2/auth_tokens.ts": "5d1d56474c54a9d152e44d43ea17c2e6a398dd1e9682c69811a313567c01ee1e", 202 | "https://deno.land/x/deno_cache@0.5.2/cache.ts": "92ce8511e1e5c00fdf53a41619aa77d632ea8e0fc711324322e4d5ebf8133911", 203 | "https://deno.land/x/deno_cache@0.5.2/deno_dir.ts": "1ea355b8ba11c630d076b222b197cfc937dd81e5a4a260938997da99e8ff93a0", 204 | "https://deno.land/x/deno_cache@0.5.2/deps.ts": "26a75905652510b76e54b6d5ef3cf824d1062031e00782efcd768978419224e7", 205 | "https://deno.land/x/deno_cache@0.5.2/dirs.ts": "009c6f54e0b610914d6ce9f72f6f6ccfffd2d47a79a19061e0a9eb4253836069", 206 | "https://deno.land/x/deno_cache@0.5.2/disk_cache.ts": "66a1e604a8d564b6dd0500326cac33d08b561d331036bf7272def80f2f7952aa", 207 | "https://deno.land/x/deno_cache@0.5.2/file_fetcher.ts": "89616c50b6df73fb04e73d0b7cd99e5f2ed7967386913d65b9e8baa4238501f7", 208 | "https://deno.land/x/deno_cache@0.5.2/http_cache.ts": "407135eaf2802809ed373c230d57da7ef8dff923c4abf205410b9b99886491fd", 209 | "https://deno.land/x/deno_cache@0.5.2/lib/deno_cache_dir.generated.js": "18b6526d0c50791a73dd0eb894e99de1ac05ee79dcbd53298ff5b5b6b0757fe6", 210 | "https://deno.land/x/deno_cache@0.5.2/lib/snippets/deno_cache_dir-77bed54ace8005e0/fs.js": "cbe3a976ed63c72c7cb34ef845c27013033a3b11f9d8d3e2c4aa5dda2c0c7af6", 211 | "https://deno.land/x/deno_cache@0.5.2/mod.ts": "0b4d071ad095128bdc2b1bc6e5d2095222dcbae08287261690ee9757e6300db6", 212 | "https://deno.land/x/deno_cache@0.5.2/util.ts": "f3f5a0cfc60051f09162942fb0ee87a0e27b11a12aec4c22076e3006be4cc1e2", 213 | "https://deno.land/x/dir@1.5.1/data_local_dir/mod.ts": "91eb1c4bfadfbeda30171007bac6d85aadacd43224a5ed721bbe56bc64e9eb66", 214 | "https://deno.land/x/dnt@0.38.1/lib/compiler.ts": "209ad2e1b294f93f87ec02ade9a0821f942d2e524104552d0aa8ff87021050a5", 215 | "https://deno.land/x/dnt@0.38.1/lib/compiler_transforms.ts": "f21aba052f5dcf0b0595c734450842855c7f572e96165d3d34f8fed2fc1f7ba1", 216 | "https://deno.land/x/dnt@0.38.1/lib/mod.deps.ts": "30367fc68bcd2acf3b7020cf5cdd26f817f7ac9ac35c4bfb6c4551475f91bc3e", 217 | "https://deno.land/x/dnt@0.38.1/lib/npm_ignore.ts": "57fbb7e7b935417d225eec586c6aa240288905eb095847d3f6a88e290209df4e", 218 | "https://deno.land/x/dnt@0.38.1/lib/package_json.ts": "61f35b06e374ed39ca776d29d67df4be7ee809d0bca29a8239687556c6d027c2", 219 | "https://deno.land/x/dnt@0.38.1/lib/pkg/dnt_wasm.generated.js": "cfb352ae839865f5698c9b35099d4c783510195a1e3c9f9b04d94fac86394ed9", 220 | "https://deno.land/x/dnt@0.38.1/lib/pkg/snippets/dnt-wasm-a15ef721fa5290c5/helpers.js": "45f74f00472b3a399bc16e5dc056966b55dcdd8fa2bd61505c6dfd2f5d33b9f4", 221 | "https://deno.land/x/dnt@0.38.1/lib/shims.ts": "df1bd4d9a196dca4b2d512b1564fff64ac6c945189a273d706391f87f210d7e6", 222 | "https://deno.land/x/dnt@0.38.1/lib/test_runner/get_test_runner_code.ts": "4dc7a73a13b027341c0688df2b29a4ef102f287c126f134c33f69f0339b46968", 223 | "https://deno.land/x/dnt@0.38.1/lib/test_runner/test_runner.ts": "4d0da0500ec427d5f390d9a8d42fb882fbeccc92c92d66b6f2e758606dbd40e6", 224 | "https://deno.land/x/dnt@0.38.1/lib/transform.deps.ts": "e42f2bdef46d098453bdba19261a67cf90b583f5d868f7fe83113c1380d9b85c", 225 | "https://deno.land/x/dnt@0.38.1/lib/types.ts": "b8e228b2fac44c2ae902fbb73b1689f6ab889915bd66486c8a85c0c24255f5fb", 226 | "https://deno.land/x/dnt@0.38.1/lib/utils.ts": "878b7ac7003a10c16e6061aa49dbef9b42bd43174853ebffc9b67ea47eeb11d8", 227 | "https://deno.land/x/dnt@0.38.1/mod.ts": "b13349fe77847cf58e26b40bcd58797a8cec5d71b31a1ca567071329c8489de1", 228 | "https://deno.land/x/dnt@0.38.1/transform.ts": "f68743a14cf9bf53bfc9c81073871d69d447a7f9e3453e0447ca2fb78926bb1d", 229 | "https://deno.land/x/hono@v3.12.8/client/client.ts": "9b3bddfd400d069d58320c3f475447d5e61f2c343adad402d5d36fa17f00b481", 230 | "https://deno.land/x/hono@v3.12.8/client/index.ts": "30def535310a37bede261f1b23d11a9758983b8e9d60a6c56309cee5f6746ab2", 231 | "https://deno.land/x/hono@v3.12.8/client/utils.ts": "053273c002963b549d38268a1b423ac8ca211a8028bdab1ed0b781a62aa5e661", 232 | "https://deno.land/x/hono@v3.12.8/compose.ts": "37d6e33b7db80e4c43a0629b12fd3a1e3406e7d9e62a4bfad4b30426ea7ae4f1", 233 | "https://deno.land/x/hono@v3.12.8/context.ts": "bb3309ea57fa617714a16a99ab4da02ee4e36419770da6cb0f581fbbef9f541d", 234 | "https://deno.land/x/hono@v3.12.8/helper.ts": "f3acfb2b30eb0bf854876173b62b3aade6c6c638dc242d4729752f68e9c0be45", 235 | "https://deno.land/x/hono@v3.12.8/helper/adapter/index.ts": "eea9b4caedbfa3a3b4a020bf46c88c0171a00008cd6c10708cd85a3e39d86e62", 236 | "https://deno.land/x/hono@v3.12.8/helper/cookie/index.ts": "a05ce7e3bafe1f8c7f45d04abf79822716011be75904fe1aad2e99126fd985b9", 237 | "https://deno.land/x/hono@v3.12.8/helper/css/index.ts": "e04e66a594f30b29ab721e7f078c06791edd23992cb2e0ace28c60ed6133be17", 238 | "https://deno.land/x/hono@v3.12.8/helper/dev/index.ts": "d8754792bc44418b78ccffebbc81b15ccbe088690c23a923281138633a746e3d", 239 | "https://deno.land/x/hono@v3.12.8/helper/factory/index.ts": "a560aa9c8f2cf2ef1041b65d4a6007076238479d76eb7970152b533546acab6c", 240 | "https://deno.land/x/hono@v3.12.8/helper/html/index.ts": "701ed12b808e8c253247edc02c2c4b32261ae899e9c98f1427f7f6eaa8b7d1ce", 241 | "https://deno.land/x/hono@v3.12.8/helper/streaming/index.ts": "e4955c04cb5fe4d65abec256ff3f598c87958a1cfd9eece1d6de1b56d16c7723", 242 | "https://deno.land/x/hono@v3.12.8/helper/streaming/sse.ts": "3a10d73592a3af1665b872fce6d8c0417e096703cfcd15f21da3bb357ee6ede4", 243 | "https://deno.land/x/hono@v3.12.8/helper/streaming/stream.ts": "bb8eee53fadf62fb9c4b4f3ffa2f23ee21bf2337121a6811a5fe18bbbcbe6564", 244 | "https://deno.land/x/hono@v3.12.8/helper/streaming/text.ts": "df8e941f8f1605b8ee74e7176fc013716203a6961c7b69dc304f5826dfb2383c", 245 | "https://deno.land/x/hono@v3.12.8/helper/testing/index.ts": "bc49c049aa0d6426417e3d1a2f52a471a09edb1fb8610b7545eae1968e7d7874", 246 | "https://deno.land/x/hono@v3.12.8/hono-base.ts": "9a0d2afd56c48eccf93cbe6fd6bb72b26ce4281f279a98f6fd76010dcd4001bf", 247 | "https://deno.land/x/hono@v3.12.8/hono.ts": "2cc4c292e541463a4d6f83edbcea58048d203e9564ae62ec430a3d466b49a865", 248 | "https://deno.land/x/hono@v3.12.8/http-exception.ts": "6071df078b5f76d279684d52fe82a590f447a64ffe1b75eb5064d0c8a8d2d676", 249 | "https://deno.land/x/hono@v3.12.8/mod.ts": "90114a97be9111b348129ad0143e764a64921f60dd03b8f3da529db98a0d3a82", 250 | "https://deno.land/x/hono@v3.12.8/request.ts": "5c2ab4b9961615afdc87e950ce16cc57e98f7849da56ea5fc1a828ef0dbb4aaf", 251 | "https://deno.land/x/hono@v3.12.8/router.ts": "880316f561918fc197481755aac2165fdbe2f530b925c5357a9f98d6e2cc85c7", 252 | "https://deno.land/x/hono@v3.12.8/router/linear-router/index.ts": "8a2a7144c50b1f4a92d9ee99c2c396716af144c868e10608255f969695efccd0", 253 | "https://deno.land/x/hono@v3.12.8/router/linear-router/router.ts": "1366b3fada26e33c96b0f228aa7962b9c9801c4f484b3991b256aed2c005c668", 254 | "https://deno.land/x/hono@v3.12.8/router/pattern-router/index.ts": "304a66c50e243872037ed41c7dd79ed0c89d815e17e172e7ad7cdc4bc07d3383", 255 | "https://deno.land/x/hono@v3.12.8/router/pattern-router/router.ts": "a9a5a2a182cce8c3ae82139892cc0502be7dd8f579f31e76d0302b19b338e548", 256 | "https://deno.land/x/hono@v3.12.8/router/reg-exp-router/index.ts": "52755829213941756159b7a963097bafde5cc4fc22b13b1c7c9184dc0512d1db", 257 | "https://deno.land/x/hono@v3.12.8/router/reg-exp-router/node.ts": "5b3fb80411db04c65df066e69fedb2c8c0844753c2633d703336de84d569252c", 258 | "https://deno.land/x/hono@v3.12.8/router/reg-exp-router/router.ts": "c89a37b14c64518256d2fc216d9db7645e658235648762c3ad6e3fc6872a941c", 259 | "https://deno.land/x/hono@v3.12.8/router/reg-exp-router/trie.ts": "852ce7207e6701e47fa30889a0d2b8bfcd56d8862c97e7bc9831e0a64bd8835f", 260 | "https://deno.land/x/hono@v3.12.8/router/smart-router/index.ts": "74f9b4fe15ea535900f2b9b048581915f12fe94e531dd2b0032f5610e61c3bef", 261 | "https://deno.land/x/hono@v3.12.8/router/smart-router/router.ts": "f1848a2a1eefa316a11853ae12e749552747771fb8a11fe713ae04ea6461140b", 262 | "https://deno.land/x/hono@v3.12.8/router/trie-router/index.ts": "3eb75e7f71ba81801631b30de6b1f5cefb2c7239c03797e2b2cbab5085911b41", 263 | "https://deno.land/x/hono@v3.12.8/router/trie-router/node.ts": "326830a78f3ba3f8a7171041c71d541b10fba2fb398067b09bcd35251bb9679f", 264 | "https://deno.land/x/hono@v3.12.8/router/trie-router/router.ts": "54ced78d35676302c8fcdda4204f7bdf5a7cc907fbf9967c75674b1e394f830d", 265 | "https://deno.land/x/hono@v3.12.8/utils/body.ts": "fe92c854fa0d1b36d1de3351a0041d06bd56c24a18778ae94511ccd9f806c0a2", 266 | "https://deno.land/x/hono@v3.12.8/utils/buffer.ts": "9066a973e64498cb262c7e932f47eed525a51677b17f90893862b7279dc0773e", 267 | "https://deno.land/x/hono@v3.12.8/utils/cookie.ts": "19920ba6756944aae1ad8585c3ddeaa9df479733f59d05359db096f7361e5e4b", 268 | "https://deno.land/x/hono@v3.12.8/utils/crypto.ts": "bda0e141bbe46d3a4a20f8fbcb6380d473b617123d9fdfa93e4499410b537acc", 269 | "https://deno.land/x/hono@v3.12.8/utils/html.ts": "e800e72e2940104e963707edb41a438937693dda8d21bd37a57620e35d36c647", 270 | "https://deno.land/x/hono@v3.12.8/utils/stream.ts": "fe5f539a79c476e6af39e2549fa06054ad3c7ff3cbfa2c4c752e879cdd3365d5", 271 | "https://deno.land/x/hono@v3.12.8/utils/url.ts": "71475d787e9919443837e0674bc623c2a683d0a7fc41fc1938ff47e1aa775de4", 272 | "https://deno.land/x/hono@v3.12.8/validator/index.ts": "6c986e8b91dcf857ecc8164a506ae8eea8665792a4ff7215471df669c632ae7c", 273 | "https://deno.land/x/hono@v3.12.8/validator/validator.ts": "97fead75b1e3e460d0895d68eab2be6d774f6d1428e2efb8b4df8ba8bb422c3e", 274 | "https://deno.land/x/sqlite@v3.8/build/sqlite.js": "72f63689fffcb9bb5ae10b1e8f7db09ea845cdf713e0e3a9693d8416a28f92a6", 275 | "https://deno.land/x/sqlite@v3.8/build/vfs.js": "08533cc78fb29b9d9bd62f6bb93e5ef333407013fed185776808f11223ba0e70", 276 | "https://deno.land/x/sqlite@v3.8/mod.ts": "e09fc79d8065fe222578114b109b1fd60077bff1bb75448532077f784f4d6a83", 277 | "https://deno.land/x/sqlite@v3.8/src/constants.ts": "90f3be047ec0a89bcb5d6fc30db121685fc82cb00b1c476124ff47a4b0472aa9", 278 | "https://deno.land/x/sqlite@v3.8/src/db.ts": "7d3251021756fa80f382c3952217c7446c5c8c1642b63511da0938fe33562663", 279 | "https://deno.land/x/sqlite@v3.8/src/error.ts": "f7a15cb00d7c3797da1aefee3cf86d23e0ae92e73f0ba3165496c3816ab9503a", 280 | "https://deno.land/x/sqlite@v3.8/src/function.ts": "e4c83b8ec64bf88bafad2407376b0c6a3b54e777593c70336fb40d43a79865f2", 281 | "https://deno.land/x/sqlite@v3.8/src/query.ts": "d58abda928f6582d77bad685ecf551b1be8a15e8e38403e293ec38522e030cad", 282 | "https://deno.land/x/sqlite@v3.8/src/wasm.ts": "e79d0baa6e42423257fb3c7cc98091c54399254867e0f34a09b5bdef37bd9487", 283 | "https://deno.land/x/sqlite@v3.9.1/build/sqlite.js": "2afc7875c7b9c85d89730c4a311ab3a304e5d1bf761fbadd8c07bbdf130f5f9b", 284 | "https://deno.land/x/sqlite@v3.9.1/build/vfs.js": "7f7778a9fe499cd10738d6e43867340b50b67d3e39142b0065acd51a84cd2e03", 285 | "https://deno.land/x/sqlite@v3.9.1/mod.ts": "e09fc79d8065fe222578114b109b1fd60077bff1bb75448532077f784f4d6a83", 286 | "https://deno.land/x/sqlite@v3.9.1/src/constants.ts": "90f3be047ec0a89bcb5d6fc30db121685fc82cb00b1c476124ff47a4b0472aa9", 287 | "https://deno.land/x/sqlite@v3.9.1/src/db.ts": "03d0c860957496eadedd86e51a6e650670764630e64f56df0092e86c90752401", 288 | "https://deno.land/x/sqlite@v3.9.1/src/error.ts": "f7a15cb00d7c3797da1aefee3cf86d23e0ae92e73f0ba3165496c3816ab9503a", 289 | "https://deno.land/x/sqlite@v3.9.1/src/function.ts": "bc778cab7a6d771f690afa27264c524d22fcb96f1bb61959ade7922c15a4ab8d", 290 | "https://deno.land/x/sqlite@v3.9.1/src/query.ts": "d58abda928f6582d77bad685ecf551b1be8a15e8e38403e293ec38522e030cad", 291 | "https://deno.land/x/sqlite@v3.9.1/src/wasm.ts": "e79d0baa6e42423257fb3c7cc98091c54399254867e0f34a09b5bdef37bd9487", 292 | "https://deno.land/x/ts_morph@18.0.0/bootstrap/mod.ts": "b53aad517f106c4079971fcd4a81ab79fadc40b50061a3ab2b741a09119d51e9", 293 | "https://deno.land/x/ts_morph@18.0.0/bootstrap/ts_morph_bootstrap.js": "6645ac03c5e6687dfa8c78109dc5df0250b811ecb3aea2d97c504c35e8401c06", 294 | "https://deno.land/x/ts_morph@18.0.0/common/DenoRuntime.ts": "6a7180f0c6e90dcf23ccffc86aa8271c20b1c4f34c570588d08a45880b7e172d", 295 | "https://deno.land/x/ts_morph@18.0.0/common/mod.ts": "01985d2ee7da8d1caee318a9d07664774fbee4e31602bc2bb6bb62c3489555ed", 296 | "https://deno.land/x/ts_morph@18.0.0/common/ts_morph_common.js": "845671ca951073400ce142f8acefa2d39ea9a51e29ca80928642f3f8cf2b7700", 297 | "https://deno.land/x/ts_morph@18.0.0/common/typescript.js": "d5c598b6a2db2202d0428fca5fd79fc9a301a71880831a805d778797d2413c59", 298 | "https://deno.land/x/wasmbuild@0.15.0/cache.ts": "89eea5f3ce6035a1164b3e655c95f21300498920575ade23161421f5b01967f4", 299 | "https://deno.land/x/wasmbuild@0.15.0/loader.ts": "d98d195a715f823151cbc8baa3f32127337628379a02d9eb2a3c5902dbccfc02" 300 | }, 301 | "workspace": { 302 | "dependencies": [ 303 | "jsr:@deno/dnt@~0.41.3", 304 | "jsr:@std/path@^1.0.7" 305 | ] 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /deps.ts: -------------------------------------------------------------------------------- 1 | export type { Context, MiddlewareHandler } from 'npm:hono@^4.0.0' 2 | export { createMiddleware } from 'npm:hono@^4.0.0/factory' 3 | export { getCookie, setCookie } from 'npm:hono@^4.0.0/cookie' 4 | export type { CookieOptions } from 'npm:hono@^4.0.0/utils/cookie' 5 | export * as Iron from 'npm:iron-webcrypto@^1.2.1' -------------------------------------------------------------------------------- /extras/.npmignore: -------------------------------------------------------------------------------- 1 | /src/ 2 | test_runner.js 3 | yarn.lock 4 | pnpm-lock.yaml 5 | -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | import MemoryStore from './src/store/MemoryStore.ts' 2 | import CookieStore from './src/store/CookieStore.ts' 3 | 4 | import { 5 | encrypt, 6 | decrypt 7 | } from './src/Crypto.ts' 8 | 9 | import { sessionMiddleware } from './src/Middleware.ts' 10 | import { Session } from './src/Session.ts' 11 | import type { SessionData } from './src/Session.ts' 12 | import Store from './src/store/Store.ts' 13 | import type SessionOptions from './src/SessionOptions.ts' 14 | 15 | export { 16 | MemoryStore, 17 | CookieStore, 18 | sessionMiddleware, 19 | encrypt, 20 | decrypt, 21 | Session, 22 | } 23 | 24 | export type { 25 | SessionData, 26 | SessionOptions, 27 | Store 28 | } -------------------------------------------------------------------------------- /playwright/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /test-results/ 3 | /playwright-report/ 4 | /playwright/.cache/ 5 | -------------------------------------------------------------------------------- /playwright/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playwright", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "playwright", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "@playwright/test": "^1.38.0", 13 | "@types/node": "^20.6.0" 14 | } 15 | }, 16 | "node_modules/@playwright/test": { 17 | "version": "1.38.0", 18 | "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.0.tgz", 19 | "integrity": "sha512-xis/RXXsLxwThKnlIXouxmIvvT3zvQj1JE39GsNieMUrMpb3/GySHDh2j8itCG22qKVD4MYLBp7xB73cUW/UUw==", 20 | "dev": true, 21 | "dependencies": { 22 | "playwright": "1.38.0" 23 | }, 24 | "bin": { 25 | "playwright": "cli.js" 26 | }, 27 | "engines": { 28 | "node": ">=16" 29 | } 30 | }, 31 | "node_modules/@types/node": { 32 | "version": "20.6.0", 33 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.0.tgz", 34 | "integrity": "sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==", 35 | "dev": true 36 | }, 37 | "node_modules/fsevents": { 38 | "version": "2.3.2", 39 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 40 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 41 | "dev": true, 42 | "hasInstallScript": true, 43 | "optional": true, 44 | "os": [ 45 | "darwin" 46 | ], 47 | "engines": { 48 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 49 | } 50 | }, 51 | "node_modules/playwright": { 52 | "version": "1.38.0", 53 | "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.0.tgz", 54 | "integrity": "sha512-fJGw+HO0YY+fU/F1N57DMO+TmXHTrmr905J05zwAQE9xkuwP/QLDk63rVhmyxh03dYnEhnRbsdbH9B0UVVRB3A==", 55 | "dev": true, 56 | "dependencies": { 57 | "playwright-core": "1.38.0" 58 | }, 59 | "bin": { 60 | "playwright": "cli.js" 61 | }, 62 | "engines": { 63 | "node": ">=16" 64 | }, 65 | "optionalDependencies": { 66 | "fsevents": "2.3.2" 67 | } 68 | }, 69 | "node_modules/playwright-core": { 70 | "version": "1.38.0", 71 | "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.0.tgz", 72 | "integrity": "sha512-f8z1y8J9zvmHoEhKgspmCvOExF2XdcxMW8jNRuX4vkQFrzV4MlZ55iwb5QeyiFQgOFCUolXiRHgpjSEnqvO48g==", 73 | "dev": true, 74 | "bin": { 75 | "playwright-core": "cli.js" 76 | }, 77 | "engines": { 78 | "node": ">=16" 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /playwright/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playwright", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": {}, 7 | "keywords": [], 8 | "author": "", 9 | "license": "ISC", 10 | "devDependencies": { 11 | "@playwright/test": "^1.38.0", 12 | "@types/node": "^20.6.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /playwright/playwright.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, devices } from '@playwright/test'; 2 | import { runtimeCommand } from './test_setup'; 3 | 4 | /** 5 | * Read environment variables from file. 6 | * https://github.com/motdotla/dotenv 7 | */ 8 | // require('dotenv').config(); 9 | 10 | /** 11 | * See https://playwright.dev/docs/test-configuration. 12 | */ 13 | export default defineConfig({ 14 | testDir: './tests', 15 | /* Run tests in files in parallel */ 16 | fullyParallel: true, 17 | /* Fail the build on CI if you accidentally left test.only in the source code. */ 18 | forbidOnly: !!process.env.CI, 19 | /* Retry on CI only */ 20 | retries: process.env.CI ? 2 : 0, 21 | /* Opt out of parallel tests on CI. */ 22 | workers: process.env.CI ? 1 : undefined, 23 | /* Reporter to use. See https://playwright.dev/docs/test-reporters */ 24 | reporter: 'html', 25 | /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ 26 | use: { 27 | /* Base URL to use in actions like `await page.goto('/')`. */ 28 | // baseURL: 'http://127.0.0.1:3000', 29 | 30 | /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ 31 | trace: 'on-first-retry', 32 | }, 33 | 34 | /* Configure projects for major browsers */ 35 | projects: [ 36 | { 37 | name: 'chromium', 38 | use: { ...devices['Desktop Chrome'] }, 39 | }, 40 | 41 | // { 42 | // name: 'firefox', 43 | // use: { ...devices['Desktop Firefox'] }, 44 | // }, 45 | 46 | // { 47 | // name: 'webkit', 48 | // use: { ...devices['Desktop Safari'] }, 49 | // }, 50 | 51 | /* Test against mobile viewports. */ 52 | // { 53 | // name: 'Mobile Chrome', 54 | // use: { ...devices['Pixel 5'] }, 55 | // }, 56 | // { 57 | // name: 'Mobile Safari', 58 | // use: { ...devices['iPhone 12'] }, 59 | // }, 60 | 61 | /* Test against branded browsers. */ 62 | // { 63 | // name: 'Microsoft Edge', 64 | // use: { ...devices['Desktop Edge'], channel: 'msedge' }, 65 | // }, 66 | // { 67 | // name: 'Google Chrome', 68 | // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, 69 | // }, 70 | ], 71 | 72 | /* Run your local dev server before starting the tests */ 73 | webServer: { 74 | command: runtimeCommand().command, 75 | url: runtimeCommand().server_url, 76 | reuseExistingServer: !process.env.CI, 77 | }, 78 | }); 79 | -------------------------------------------------------------------------------- /playwright/test_setup.ts: -------------------------------------------------------------------------------- 1 | export function runtimeCommand() { 2 | let command: string 3 | let server_url: string 4 | 5 | switch(process.env.JS_RUNTIME) { 6 | case 'deno': 7 | command = `cd ../test/deno && deno run -A server_deno.ts` 8 | server_url = 'http://127.0.0.1:8000' 9 | break 10 | case 'bun': 11 | command = `cd ../test/bun && bun run ${ process.env.STORE === 'sqlite' ? 'src/test_sqlite.ts' : 'src/test_cookie.ts'}` 12 | server_url = 'http://127.0.0.1:3000' 13 | break 14 | case 'cf_workers': 15 | command = `cd ../test/cloudflare_workers && npm run dev` 16 | server_url = 'http://127.0.0.1:8787' 17 | break 18 | case 'cf_pages': 19 | command = `cd ../test/cloudflare_pages && npm run preview` 20 | server_url = 'http://127.0.0.1:8788' 21 | break 22 | case 'node': 23 | command = `cd ../test/node && npm run test_cookie` 24 | server_url = 'http://127.0.0.1:3000' 25 | break 26 | default: // Deno by default 27 | command = `cd ../test/deno && deno run -A server_deno.ts` 28 | server_url = 'http://127.0.0.1:8000' 29 | } 30 | 31 | return { 32 | command, 33 | server_url 34 | } 35 | } -------------------------------------------------------------------------------- /playwright/tests/sessions.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test'; 2 | import { runtimeCommand } from '../test_setup'; 3 | 4 | test('logs in a user after several mistakes', async ({ page }) => { 5 | await page.goto(runtimeCommand().server_url + '/'); 6 | 7 | // Expect a title "to contain" a substring. 8 | await expect(page).toHaveTitle(/Hono Sessions/); 9 | 10 | await page.locator('#email').fill('test@test.com') 11 | await page.locator('#password').fill('incorrect') 12 | await page.locator('#login-button').click() 13 | 14 | await expect(page.locator('#error')).toContainText('Incorrect username or password') 15 | await expect(page.locator('#failed-login-attempts')).toContainText('Failed login attempts: 1') 16 | 17 | await page.goto(runtimeCommand().server_url + '/') 18 | await expect(page.locator('#failed-login-attempts')).toContainText('Failed login attempts: 1') 19 | await expect(page.locator('#error')).toBeHidden() 20 | await page.locator('#email').fill('test@test.com') 21 | await page.locator('#password').fill('wrong') 22 | await page.locator('#login-button').click() 23 | 24 | await expect(page.locator('#failed-login-attempts')).toContainText('Failed login attempts: 2') 25 | 26 | await page.locator('#email').fill('test@test.com') 27 | await page.locator('#password').fill('correct') 28 | await page.locator('#login-button').click() 29 | 30 | // expect failed-login-attempts to not exist in the DOM 31 | await expect(page.locator('#failed-login-attempts')).toBeHidden() 32 | await expect(page.locator('#message')).toContainText('Login Successful') 33 | 34 | await page.goto(runtimeCommand().server_url + '/') 35 | await expect(page.locator('#logout-button')).toContainText('Log out test@test.com') 36 | await expect(page.locator('#message')).toBeHidden() 37 | await page.locator('#logout-button').click() 38 | 39 | await page.goto(runtimeCommand().server_url + '/') 40 | await page.locator('#email').fill('test@test.com') 41 | await page.locator('#password').fill('incorrect') 42 | await page.locator('#login-button').click() 43 | await expect(page.locator('#error')).toContainText('Incorrect username or password') 44 | await expect(page.locator('#failed-login-attempts')).toContainText('Failed login attempts: 1') 45 | }); 46 | -------------------------------------------------------------------------------- /scripts/build_npm.ts: -------------------------------------------------------------------------------- 1 | // ex. scripts/build_npm.ts 2 | import { build, emptyDir } from "@deno/dnt"; 3 | import { fromFileUrl, dirname } from '@std/path' 4 | 5 | const version = JSON.parse(await Deno.readTextFile(dirname(fromFileUrl(import.meta.url)) + '/../deno.json')).version 6 | 7 | await emptyDir("./npm"); 8 | 9 | await build({ 10 | entryPoints: ["./mod.ts", { 11 | name: './bun-sqlite-store', 12 | path: './src/store/bun/BunSqliteStore.ts' 13 | }], 14 | outDir: "./npm", 15 | shims: { 16 | // see JS docs for overview and more options 17 | // deno: true, 18 | // crypto: true, 19 | }, 20 | package: { 21 | // package.json properties 22 | name: "hono-sessions", 23 | version, 24 | description: "Cookie-based sessions for Hono web framework", 25 | license: "MIT", 26 | repository: { 27 | type: "git", 28 | url: "git+https://github.com/jcs224/hono_sessions.git", 29 | }, 30 | bugs: { 31 | url: "https://github.com/jcs224/hono_sessions/issues", 32 | }, 33 | }, 34 | // typeCheck: false, 35 | // scriptModule: false, 36 | test: false, 37 | compilerOptions: { 38 | lib: ['DOM', 'ES2022'] 39 | } 40 | }); 41 | 42 | // post build steps 43 | Deno.copyFileSync("LICENSE", "npm/LICENSE"); 44 | Deno.copyFileSync("README.md", "npm/README.md"); 45 | Deno.copyFileSync("extras/.npmignore", "npm/.npmignore") -------------------------------------------------------------------------------- /src/Crypto.ts: -------------------------------------------------------------------------------- 1 | import { Iron } from '../deps.ts' 2 | 3 | /** 4 | * Encrypt a string or object value 5 | * 6 | * @param password Random string at least 32 characters long 7 | * @param payload String or object to encrypt 8 | * @returns A promise of the encrypted string 9 | */ 10 | export async function encrypt(password: string, payload: object | string): Promise { 11 | return await Iron.seal(globalThis.crypto, payload, password, Iron.defaults) 12 | } 13 | 14 | /** 15 | * Decrypt an encrypted payload 16 | * 17 | * @param password Random string at least 32 characters long 18 | * @param encrypted Encrypted string 19 | * @returns Promise of the unencrypted value (string or object in most cases) 20 | */ 21 | export async function decrypt(password:string, encrypted: string): Promise { 22 | return await Iron.unseal(globalThis.crypto, encrypted, {default: password}, Iron.defaults) 23 | } -------------------------------------------------------------------------------- /src/Middleware.ts: -------------------------------------------------------------------------------- 1 | import { getCookie, setCookie, createMiddleware, MiddlewareHandler } from '../deps.ts' 2 | import CookieStore from './store/CookieStore.ts' 3 | import { Session, SessionData, encrypt, decrypt } from '../mod.ts' 4 | import SessionOptions from './SessionOptions.ts' 5 | 6 | /** Function that returns a Hono-compatible session middleware */ 7 | export function sessionMiddleware(options: SessionOptions): MiddlewareHandler { 8 | 9 | const store = options.store 10 | const encryptionKey = options.encryptionKey 11 | const expireAfterSeconds = options.expireAfterSeconds 12 | const cookieOptions = options.cookieOptions 13 | const sessionCookieName = options.sessionCookieName || 'session' 14 | 15 | if (store instanceof CookieStore) { 16 | store.sessionCookieName = sessionCookieName 17 | 18 | if (encryptionKey) { 19 | store.encryptionKey = encryptionKey 20 | } else { 21 | throw new Error('encryptionKey is required while using CookieStore. encryptionKey must be at least 32 characters long.') 22 | } 23 | 24 | if (cookieOptions) { 25 | store.cookieOptions = cookieOptions 26 | } 27 | } 28 | 29 | const middleware = createMiddleware(async (c, next) => { 30 | const session = new Session 31 | let sid = '' 32 | let session_data: SessionData | null | undefined 33 | let createNewSession = false 34 | 35 | const sessionCookie = getCookie(c, sessionCookieName) 36 | 37 | if (sessionCookie) { // If there is a session cookie present... 38 | 39 | if (store instanceof CookieStore) { 40 | session_data = await store.getSession(c) 41 | } else { 42 | try { 43 | sid = (encryptionKey ? await decrypt(encryptionKey, sessionCookie) : sessionCookie) as string 44 | session_data = await store.getSessionById(sid) 45 | 46 | if (session_data) { 47 | session_data._id = sid 48 | } 49 | } catch { 50 | createNewSession = true 51 | } 52 | } 53 | 54 | if (session_data) { 55 | session.setCache(session_data) 56 | 57 | if (session.sessionValid()) { 58 | session.reupSession(expireAfterSeconds) 59 | } else { 60 | store instanceof CookieStore ? await store.deleteSession(c) : await store.deleteSession(sid) 61 | createNewSession = true 62 | } 63 | } else { 64 | createNewSession = true 65 | } 66 | } else { 67 | createNewSession = true 68 | } 69 | 70 | if (createNewSession) { 71 | const defaultData : SessionData = { 72 | _data:{}, 73 | _expire: null, 74 | _delete: false, 75 | _accessed: null, 76 | } 77 | 78 | if (store instanceof CookieStore) { 79 | await store.createSession(c, defaultData) 80 | } else { 81 | sid = globalThis.crypto.randomUUID() 82 | defaultData._id = sid 83 | await store.createSession(sid, defaultData) 84 | } 85 | 86 | session.setCache(defaultData) 87 | } 88 | 89 | if (!(store instanceof CookieStore)) { 90 | setCookie(c, sessionCookieName, encryptionKey ? await encrypt(encryptionKey, sid) : sid, cookieOptions) 91 | } 92 | 93 | session.updateAccess() 94 | 95 | c.set('session', session) 96 | 97 | await next() 98 | 99 | const shouldDelete = session.getCache()._delete; 100 | const shouldRotateSessionKey = c.get("session_key_rotation") === true; 101 | const storeIsCookieStore = store instanceof CookieStore; 102 | 103 | if (shouldDelete) { 104 | store instanceof CookieStore 105 | ? await store.deleteSession(c) 106 | : await store.deleteSession(sid); 107 | } 108 | 109 | /* 110 | * Only update session data if we didn't just delete it. 111 | * If session key rotation is enabled and the store is not a CookieStore, 112 | * we need to roate the session key by deleting the old session and creating a new one. 113 | */ 114 | const shouldRecreateSessionForNonCookieStore = 115 | !shouldDelete && 116 | !storeIsCookieStore && 117 | shouldRotateSessionKey; 118 | 119 | if (shouldRecreateSessionForNonCookieStore) { 120 | await store.deleteSession(sid); 121 | sid = globalThis.crypto.randomUUID(); 122 | await store.createSession(sid, session.getCache()); 123 | 124 | setCookie( 125 | c, 126 | sessionCookieName, 127 | encryptionKey ? await encrypt(encryptionKey, sid) : sid, 128 | cookieOptions 129 | ); 130 | } 131 | 132 | /* 133 | * We skip session data persistence if it was just deleted. 134 | * Only persist if we didn't just rotate the session key, 135 | * or the store is a CookieStore (which does not have its session key rotated) 136 | */ 137 | const shouldPersistSession = 138 | !shouldDelete && 139 | (!shouldRotateSessionKey || storeIsCookieStore); 140 | 141 | if (shouldPersistSession) { 142 | store instanceof CookieStore 143 | ? await store.persistSessionData(c, session.getCache()) 144 | : await store.persistSessionData(sid, session.getCache()); 145 | } 146 | }) 147 | 148 | return middleware 149 | } -------------------------------------------------------------------------------- /src/Session.ts: -------------------------------------------------------------------------------- 1 | interface SessionDataEntry { 2 | value: T, 3 | flash: boolean 4 | } 5 | 6 | export interface SessionData { 7 | _id?: string, // No id used with cookie store 8 | _data: Record>, 9 | _expire: string | null, 10 | _delete: boolean, 11 | _accessed: string | null, 12 | } 13 | 14 | export class Session { 15 | 16 | private cache: SessionData 17 | 18 | constructor() { 19 | this.cache = { 20 | _data: {}, 21 | _expire: null, 22 | _delete: false, 23 | _accessed: null, 24 | } 25 | } 26 | 27 | setCache(cache_data: SessionData) { 28 | this.cache = cache_data 29 | } 30 | 31 | getCache(): SessionData { 32 | return this.cache 33 | } 34 | 35 | setExpiration(expiration: string) { 36 | this.cache._expire = expiration 37 | } 38 | 39 | reupSession(expiration: number | null | undefined) { 40 | if (expiration) { 41 | this.setExpiration(new Date(Date.now() + expiration * 1000).toISOString()) 42 | } 43 | } 44 | 45 | deleteSession() { 46 | this.cache._delete = true 47 | } 48 | 49 | sessionValid(): boolean { 50 | return this.cache._expire == null || Date.now() < new Date(this.cache._expire).getTime() 51 | } 52 | 53 | updateAccess() { 54 | this.cache._accessed = new Date().toISOString() 55 | } 56 | 57 | get(key: K): T[K] | null { 58 | const entry = this.cache._data[key as string] 59 | 60 | if (entry) { 61 | const value = entry.value 62 | if (entry.flash) { 63 | delete this.cache._data[key as string] 64 | } 65 | 66 | return value as T[K] 67 | } else { 68 | return null 69 | } 70 | } 71 | 72 | set(key: K, value: T[K]) { 73 | const entry: SessionDataEntry = { 74 | value: value as T, 75 | flash: false 76 | } 77 | 78 | this.cache._data[key as string] = entry 79 | } 80 | 81 | forget(key: K) { 82 | const entry = this.cache._data[key as string] 83 | if (!entry) return 84 | delete this.cache._data[key as string] 85 | } 86 | 87 | flash(key: K, value: T[K]) { 88 | const entry: SessionDataEntry = { 89 | value: value as T, 90 | flash: true 91 | } 92 | 93 | this.cache._data[key as string] = entry 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/SessionOptions.ts: -------------------------------------------------------------------------------- 1 | import Store from './store/Store.ts' 2 | import CookieStore from './store/CookieStore.ts' 3 | import { CookieOptions } from '../deps.ts'; 4 | 5 | export default interface SessionOptions { 6 | store: Store | CookieStore 7 | encryptionKey?: string, 8 | expireAfterSeconds?: number, 9 | cookieOptions?: CookieOptions, 10 | sessionCookieName?: string 11 | } -------------------------------------------------------------------------------- /src/store/CookieStore.ts: -------------------------------------------------------------------------------- 1 | import { Context, getCookie, setCookie, CookieOptions } from '../../deps.ts' 2 | import { encrypt, decrypt, SessionData } from '../../mod.ts' 3 | 4 | interface CookieStoreOptions { 5 | encryptionKey?: string | null, 6 | cookieOptions?: CookieOptions, 7 | sessionCookieName: string 8 | } 9 | 10 | /** 11 | * Cookie storage driver class 12 | */ 13 | class CookieStore { 14 | public encryptionKey: string | null | undefined 15 | public cookieOptions: CookieOptions | undefined 16 | public sessionCookieName: string 17 | 18 | constructor(options?: CookieStoreOptions) { 19 | this.encryptionKey = options?.encryptionKey 20 | this.cookieOptions = options?.cookieOptions 21 | this.sessionCookieName = options?.sessionCookieName || 'session' 22 | } 23 | 24 | async getSession(c: Context): Promise { 25 | let session_data_raw: string 26 | 27 | const sessionCookie = getCookie(c, this.sessionCookieName) 28 | 29 | if (this.encryptionKey && sessionCookie) { 30 | // Decrypt cookie string. If decryption fails, return null 31 | try { 32 | session_data_raw = (await decrypt(this.encryptionKey, sessionCookie)) as string 33 | } catch { 34 | return null 35 | } 36 | 37 | // Parse session object from cookie string and return result. If fails, return null 38 | try { 39 | const session_data = JSON.parse(session_data_raw) as SessionData 40 | return session_data 41 | } catch { 42 | return null 43 | } 44 | } else { 45 | return null 46 | } 47 | } 48 | 49 | async createSession(c: Context, initial_data: SessionData) { 50 | const stringified_data = JSON.stringify(initial_data) 51 | setCookie(c, this.sessionCookieName, this.encryptionKey ? await encrypt(this.encryptionKey, stringified_data) : stringified_data, this.cookieOptions) 52 | } 53 | 54 | async deleteSession(c: Context) { 55 | setCookie(c, this.sessionCookieName, this.encryptionKey ? await encrypt(this.encryptionKey, '') : '', this.cookieOptions) 56 | } 57 | 58 | async persistSessionData(c: Context, session_data: SessionData) { 59 | const stringified_data = JSON.stringify(session_data) 60 | setCookie(c, this.sessionCookieName, this.encryptionKey ? await encrypt(this.encryptionKey, stringified_data) : stringified_data, this.cookieOptions) 61 | } 62 | } 63 | 64 | export default CookieStore -------------------------------------------------------------------------------- /src/store/MemoryStore.ts: -------------------------------------------------------------------------------- 1 | import Store from './Store.ts' 2 | import { SessionData } from '../../mod.ts' 3 | 4 | /** 5 | * Memory storage driver class 6 | */ 7 | class MemoryStore implements Store { 8 | private data: Map 9 | 10 | constructor() { 11 | this.data = new Map 12 | } 13 | 14 | getSessionById(sid: string): SessionData | null | undefined { 15 | return this.data.has(sid) ? this.data.get(sid) : null 16 | } 17 | 18 | createSession(sid: string, initial_data: SessionData) { 19 | this.data.set(sid, initial_data) 20 | } 21 | 22 | deleteSession(sid: string) { 23 | this.data.delete(sid) 24 | } 25 | 26 | persistSessionData(sid: string, session_data: SessionData) { 27 | this.data.set(sid, session_data) 28 | } 29 | } 30 | 31 | export default MemoryStore -------------------------------------------------------------------------------- /src/store/Store.ts: -------------------------------------------------------------------------------- 1 | import { SessionData } from "../../mod.ts" 2 | 3 | /** 4 | * Interface for required methods in session storage drivers 5 | */ 6 | export default interface Store { 7 | getSessionById(sessionId?: string) : SessionData | null | undefined | Promise 8 | createSession(sessionId: string, initialData: SessionData) : Promise | void 9 | persistSessionData(sessionId: string, sessionData: SessionData) : Promise | void 10 | deleteSession(sessionId: string) : Promise | void 11 | } -------------------------------------------------------------------------------- /src/store/bun/BunSqliteStore.ts: -------------------------------------------------------------------------------- 1 | import Store from '../Store.ts' 2 | import { SessionData } from '../../Session.ts' 3 | 4 | export class BunSqliteStore implements Store { 5 | db: any 6 | tableName: string 7 | 8 | constructor(db: any, tableName = 'sessions') { 9 | this.db = db 10 | this.tableName = tableName 11 | const query = db.query(`CREATE TABLE IF NOT EXISTS ${ tableName } (id TEXT PRIMARY KEY, data TEXT)`) 12 | query.run() 13 | } 14 | 15 | getSessionById(sessionId: string) { 16 | const query = this.db.query(`SELECT data FROM ${ this.tableName } WHERE id = $id`) 17 | const result = query.get({ $id: sessionId }) 18 | 19 | if (result) { 20 | return JSON.parse(result.data) 21 | } else { 22 | return null 23 | } 24 | } 25 | 26 | createSession(sessionId: string,initialData: SessionData) { 27 | const query = this.db.query(`INSERT INTO ${ this.tableName } (id, data) VALUES ($id, $data)`) 28 | query.run({ $id: sessionId, $data: JSON.stringify(initialData) }) 29 | } 30 | 31 | deleteSession(sessionId: string) { 32 | const query = this.db.query(`DELETE FROM ${ this.tableName } WHERE id = $id`) 33 | query.run({ $id: sessionId}) 34 | } 35 | 36 | persistSessionData(sessionId: string,sessionData: SessionData) { 37 | const query = this.db.query(`UPDATE ${ this.tableName } SET data = $data WHERE id = $id`) 38 | query.run({ $id: sessionId, $data: JSON.stringify(sessionData) }) 39 | } 40 | } -------------------------------------------------------------------------------- /test/bun/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | bun install 3 | 4 | # run using cookie store 5 | bun run dev:cookie 6 | 7 | # run using sqlite store 8 | bun run dev:sqlite 9 | ``` 10 | 11 | ``` 12 | open http://localhost:3000 13 | ``` 14 | -------------------------------------------------------------------------------- /test/bun/bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jcs224/hono_sessions/d29f2214f5a39158c952d4b3c0b53ff1d5ddedaa/test/bun/bun.lockb -------------------------------------------------------------------------------- /test/bun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev:cookie": "bun run --hot src/test_cookie.ts", 4 | "dev:sqlite": "bun run --hot src/test_sqlite.ts" 5 | }, 6 | "dependencies": { 7 | "hono": "^4.0.0", 8 | "hono-sessions": "../../npm" 9 | }, 10 | "devDependencies": { 11 | "bun-types": "^0.6.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/bun/src/test_cookie.ts: -------------------------------------------------------------------------------- 1 | import { Hono } from "hono"; 2 | import { html } from "hono/html"; 3 | import { sessionMiddleware, CookieStore, Session } from "hono-sessions"; 4 | 5 | const port = parseInt(process.env.PORT) || 3000; 6 | 7 | const app = new Hono() 8 | 9 | const store = new CookieStore() 10 | 11 | const session_routes = new Hono<{ 12 | Variables: { 13 | session: Session, 14 | session_key_rotation: boolean 15 | } 16 | }>() 17 | 18 | session_routes.use('*', sessionMiddleware({ 19 | store, 20 | expireAfterSeconds: 30, 21 | cookieOptions: { 22 | sameSite: 'Lax', 23 | path: '/', 24 | httpOnly: true, 25 | }, 26 | encryptionKey: 'string_at_least_32_characters_long' 27 | })) 28 | 29 | session_routes.post('/login', async (c) => { 30 | const session = c.get('session') 31 | 32 | const { email, password } = await c.req.parseBody() 33 | 34 | if (password === 'correct') { 35 | c.set('session_key_rotation', true) 36 | session.set('email', email) 37 | session.forget('failed-login-attempts') 38 | session.flash('message', 'Login Successful') 39 | } else { 40 | const failedLoginAttempts = (session.get('failed-login-attempts') || 0) as number 41 | session.set('failed-login-attempts', failedLoginAttempts + 1) 42 | session.flash('error', 'Incorrect username or password') 43 | } 44 | 45 | return c.redirect('/') 46 | }) 47 | 48 | session_routes.post('/logout', (c) => { 49 | c.get('session').deleteSession() 50 | return c.redirect('/') 51 | }) 52 | 53 | session_routes.get('/', (c) => { 54 | const session = c.get('session') 55 | 56 | const message = session.get('message') || '' 57 | const error = session.get('error') || '' 58 | const failedLoginAttempts = session.get('failed-login-attempts') 59 | const email = session.get('email') 60 | 61 | return c.html(html` 62 | 63 | 64 | 65 | 66 | 67 | Hono Sessions 68 | 69 | 70 | ${ message && html`

${message}

` } 71 | ${ error && html`

${error}

` } 72 | ${ failedLoginAttempts && html`

Failed login attempts: ${ failedLoginAttempts }

` } 73 | 74 | ${email ? 75 | html`
76 | 77 |
` 78 | : 79 | html`
80 |

81 | 82 |

83 |

84 | 85 |

86 | 87 |
` 88 | } 89 | 90 | `) 91 | }) 92 | 93 | app.route('/', session_routes) 94 | 95 | export default { 96 | port, 97 | fetch: app.fetch, 98 | }; 99 | -------------------------------------------------------------------------------- /test/bun/src/test_sqlite.ts: -------------------------------------------------------------------------------- 1 | import { Hono } from "hono"; 2 | import { html } from "hono/html"; 3 | import { Database } from 'bun:sqlite' 4 | import { sessionMiddleware, CookieStore, MemoryStore, Session } from "hono-sessions"; 5 | import { BunSqliteStore } from 'hono-sessions/bun-sqlite-store' 6 | 7 | const port = parseInt(process.env.PORT) || 3000; 8 | 9 | const app = new Hono() 10 | 11 | const db = new Database('./tmp/database.sqlite') 12 | const store = new BunSqliteStore(db) 13 | 14 | const session_routes = new Hono<{ 15 | Variables: { 16 | session: Session, 17 | session_key_rotation: boolean 18 | } 19 | }>() 20 | 21 | session_routes.use('*', sessionMiddleware({ 22 | store, 23 | expireAfterSeconds: 30, 24 | cookieOptions: { 25 | sameSite: 'Lax', 26 | path: '/', 27 | httpOnly: true, 28 | }, 29 | encryptionKey: 'string_at_least_32_characters_long' 30 | })) 31 | 32 | session_routes.post('/login', async (c) => { 33 | const session = c.get('session') 34 | 35 | const { email, password } = await c.req.parseBody() 36 | 37 | if (password === 'correct') { 38 | c.set('session_key_rotation', true) 39 | session.set('email', email) 40 | session.set('failed-login-attempts', null) 41 | session.flash('message', 'Login Successful') 42 | } else { 43 | const failedLoginAttempts = (session.get('failed-login-attempts') || 0) as number 44 | session.set('failed-login-attempts', failedLoginAttempts + 1) 45 | session.flash('error', 'Incorrect username or password') 46 | } 47 | 48 | return c.redirect('/') 49 | }) 50 | 51 | session_routes.post('/logout', (c) => { 52 | c.get('session').deleteSession() 53 | return c.redirect('/') 54 | }) 55 | 56 | session_routes.get('/', (c) => { 57 | const session = c.get('session') 58 | 59 | const message = session.get('message') || '' 60 | const error = session.get('error') || '' 61 | const failedLoginAttempts = session.get('failed-login-attempts') 62 | const email = session.get('email') 63 | 64 | return c.html(html` 65 | 66 | 67 | 68 | 69 | 70 | Hono Sessions 71 | 72 | 73 | ${ message && html`

${message}

` } 74 | ${ error && html`

${error}

` } 75 | ${ failedLoginAttempts && html`

Failed login attempts: ${ failedLoginAttempts }

` } 76 | 77 | ${email ? 78 | html`
79 | 80 |
` 81 | : 82 | html`
83 |

84 | 85 |

86 |

87 | 88 |

89 | 90 |
` 91 | } 92 | 93 | `) 94 | }) 95 | 96 | app.route('/', session_routes) 97 | 98 | export default { 99 | port, 100 | fetch: app.fetch, 101 | }; 102 | -------------------------------------------------------------------------------- /test/bun/tmp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jcs224/hono_sessions/d29f2214f5a39158c952d4b3c0b53ff1d5ddedaa/test/bun/tmp/.gitkeep -------------------------------------------------------------------------------- /test/bun/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "strict": true, 5 | "jsx": "react-jsx", 6 | "jsxFragmentFactory": "Fragment", 7 | "jsxImportSource": "hono/jsx" 8 | } 9 | } -------------------------------------------------------------------------------- /test/cloudflare_pages/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .wrangler 4 | .dev.vars 5 | 6 | # Change them to your taste: 7 | package-lock.json 8 | yarn.lock 9 | pnpm-lock.yaml 10 | bun.lockb -------------------------------------------------------------------------------- /test/cloudflare_pages/README.md: -------------------------------------------------------------------------------- 1 | ```txt 2 | npm install 3 | npm run dev 4 | ``` 5 | 6 | ```txt 7 | npm run deploy 8 | ``` 9 | -------------------------------------------------------------------------------- /test/cloudflare_pages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "dev": "vite", 5 | "build": "vite build", 6 | "preview": "wrangler pages dev dist", 7 | "deploy": "$npm_execpath run build && wrangler pages deploy dist" 8 | }, 9 | "dependencies": { 10 | "hono": "^4.0.0", 11 | "hono-sessions": "file:../../npm" 12 | }, 13 | "devDependencies": { 14 | "@cloudflare/workers-types": "^4.20240403.0", 15 | "@hono/vite-cloudflare-pages": "^0.2.4", 16 | "@hono/vite-dev-server": "^0.12.0", 17 | "vite": "^5.0.12", 18 | "wrangler": "^3.47.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/cloudflare_pages/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { Hono } from "hono"; 2 | import { html } from "hono/html"; 3 | import { sessionMiddleware, CookieStore, Session } from "hono-sessions"; 4 | 5 | const app = new Hono() 6 | 7 | const store = new CookieStore() 8 | 9 | const session_routes = new Hono<{ 10 | Variables: { 11 | session: Session, 12 | session_key_rotation: boolean 13 | } 14 | }>() 15 | 16 | session_routes.use('*', sessionMiddleware({ 17 | store, 18 | expireAfterSeconds: 30, 19 | cookieOptions: { 20 | sameSite: 'Lax', 21 | path: '/', 22 | httpOnly: true, 23 | }, 24 | encryptionKey: 'string_at_least_32_characters_long' 25 | })) 26 | 27 | session_routes.post('/login', async (c) => { 28 | const session = c.get('session') 29 | 30 | const { email, password } = await c.req.parseBody() 31 | 32 | if (password === 'correct') { 33 | c.set('session_key_rotation', true) 34 | session.set('email', email) 35 | session.forget('failed-login-attempts') 36 | session.flash('message', 'Login Successful') 37 | } else { 38 | const failedLoginAttempts = (session.get('failed-login-attempts') || 0) as number 39 | session.set('failed-login-attempts', failedLoginAttempts + 1) 40 | session.flash('error', 'Incorrect username or password') 41 | } 42 | 43 | return c.redirect('/') 44 | }) 45 | 46 | session_routes.post('/logout', (c) => { 47 | c.get('session').deleteSession() 48 | return c.redirect('/') 49 | }) 50 | 51 | session_routes.get('/', (c) => { 52 | const session = c.get('session') 53 | 54 | const message = session.get('message') || '' 55 | const error = session.get('error') || '' 56 | const failedLoginAttempts = session.get('failed-login-attempts') 57 | const email = session.get('email') 58 | 59 | return c.html(html` 60 | 61 | 62 | 63 | 64 | 65 | Hono Sessions 66 | 67 | 68 | ${ message && html`

${message}

` } 69 | ${ error && html`

${error}

` } 70 | ${ failedLoginAttempts && html`

Failed login attempts: ${ failedLoginAttempts }

` } 71 | 72 | ${email ? 73 | html`
74 | 75 |
` 76 | : 77 | html`
78 |

79 | 80 |

81 |

82 | 83 |

84 | 85 |
` 86 | } 87 | 88 | `) 89 | }) 90 | 91 | app.route('/', session_routes) 92 | 93 | export default app; -------------------------------------------------------------------------------- /test/cloudflare_pages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Bundler", 6 | "strict": true, 7 | "lib": [ 8 | "ESNext" 9 | ], 10 | "types": [ 11 | "@cloudflare/workers-types", 12 | "vite/client" 13 | ], 14 | "jsx": "react-jsx", 15 | "jsxImportSource": "hono/jsx" 16 | }, 17 | } -------------------------------------------------------------------------------- /test/cloudflare_pages/vite.config.ts: -------------------------------------------------------------------------------- 1 | import build from '@hono/vite-cloudflare-pages' 2 | import devServer from '@hono/vite-dev-server' 3 | import adapter from '@hono/vite-dev-server/cloudflare' 4 | import { defineConfig } from 'vite' 5 | 6 | export default defineConfig({ 7 | plugins: [ 8 | build(), 9 | devServer({ 10 | adapter, 11 | entry: 'src/index.tsx' 12 | }) 13 | ] 14 | }) 15 | -------------------------------------------------------------------------------- /test/cloudflare_pages/wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "hono-sessions-cloudflare-pages" 2 | pages_build_output_dir = "./dist" 3 | 4 | # [vars] 5 | # MY_VAR = "my-variable" 6 | 7 | # [[kv_namespaces]] 8 | # binding = "MY_KV_NAMESPACE" 9 | # id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 10 | 11 | # [[r2_buckets]] 12 | # binding = "MY_BUCKET" 13 | # bucket_name = "my-bucket" 14 | 15 | # [[d1_databases]] 16 | # binding = "DB" 17 | # database_name = "my-database" 18 | # database_id = "" 19 | 20 | # [ai] 21 | # binding = "AI" -------------------------------------------------------------------------------- /test/cloudflare_workers/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .wrangler 4 | .dev.vars 5 | 6 | # Change them to your taste: 7 | wrangler.toml -------------------------------------------------------------------------------- /test/cloudflare_workers/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | npm install 3 | npm run dev 4 | ``` 5 | 6 | ``` 7 | npm run deploy 8 | ``` 9 | -------------------------------------------------------------------------------- /test/cloudflare_workers/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudflare_workers", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "hono": "^4.0.0", 9 | "hono-sessions": "file:../../npm" 10 | }, 11 | "devDependencies": { 12 | "@cloudflare/workers-types": "^4.20230821.0", 13 | "wrangler": "^3.7.0" 14 | } 15 | }, 16 | "../../npm": { 17 | "version": "0.4.2", 18 | "license": "MIT", 19 | "dependencies": { 20 | "hono": "^4.0.0", 21 | "iron-webcrypto": "0.10.1" 22 | } 23 | }, 24 | "node_modules/@cloudflare/kv-asset-handler": { 25 | "version": "0.3.2", 26 | "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.2.tgz", 27 | "integrity": "sha512-EeEjMobfuJrwoctj7FA1y1KEbM0+Q1xSjobIEyie9k4haVEBB7vkDvsasw1pM3rO39mL2akxIAzLMUAtrMHZhA==", 28 | "dev": true, 29 | "dependencies": { 30 | "mime": "^3.0.0" 31 | }, 32 | "engines": { 33 | "node": ">=16.13" 34 | } 35 | }, 36 | "node_modules/@cloudflare/workerd-darwin-64": { 37 | "version": "1.20240419.0", 38 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240419.0.tgz", 39 | "integrity": "sha512-PGVe9sYWULHfvGhN0IZh8MsskNG/ufnBSqPbgFCxJHCTrVXLPuC35EoVaforyqjKRwj3U35XMyGo9KHcGnTeHQ==", 40 | "cpu": [ 41 | "x64" 42 | ], 43 | "dev": true, 44 | "optional": true, 45 | "os": [ 46 | "darwin" 47 | ], 48 | "engines": { 49 | "node": ">=16" 50 | } 51 | }, 52 | "node_modules/@cloudflare/workerd-darwin-arm64": { 53 | "version": "1.20240419.0", 54 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240419.0.tgz", 55 | "integrity": "sha512-z4etQSPiD5Gcjs962LiC7ZdmXnN6SGof5KrYoFiSI9X9kUvpuGH/lnjVVPd+NnVNeDU2kzmcAIgyZjkjTaqVXQ==", 56 | "cpu": [ 57 | "arm64" 58 | ], 59 | "dev": true, 60 | "optional": true, 61 | "os": [ 62 | "darwin" 63 | ], 64 | "engines": { 65 | "node": ">=16" 66 | } 67 | }, 68 | "node_modules/@cloudflare/workerd-linux-64": { 69 | "version": "1.20240419.0", 70 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240419.0.tgz", 71 | "integrity": "sha512-lBwhg0j3sYTFMsEb4bOClbVje8nqrYOu0H3feQlX+Eks94JIhWPkf8ywK4at/BUc1comPMhCgzDHwc2OMPUGgg==", 72 | "cpu": [ 73 | "x64" 74 | ], 75 | "dev": true, 76 | "optional": true, 77 | "os": [ 78 | "linux" 79 | ], 80 | "engines": { 81 | "node": ">=16" 82 | } 83 | }, 84 | "node_modules/@cloudflare/workerd-linux-arm64": { 85 | "version": "1.20240419.0", 86 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240419.0.tgz", 87 | "integrity": "sha512-ZMY6wwWkxL+WPq8ydOp/irSYjAnMhBz1OC1+4z+OANtDs2beaZODmq7LEB3hb5WUAaTPY7DIjZh3DfDfty0nYg==", 88 | "cpu": [ 89 | "arm64" 90 | ], 91 | "dev": true, 92 | "optional": true, 93 | "os": [ 94 | "linux" 95 | ], 96 | "engines": { 97 | "node": ">=16" 98 | } 99 | }, 100 | "node_modules/@cloudflare/workerd-windows-64": { 101 | "version": "1.20240419.0", 102 | "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240419.0.tgz", 103 | "integrity": "sha512-YJjgaJN2yGTkV7Cr4K3i8N4dUwVQTclT3Pr3NpRZCcLjTszwlE53++XXDnHMKGXBbSguIizaVbmcU2EtmIXyeQ==", 104 | "cpu": [ 105 | "x64" 106 | ], 107 | "dev": true, 108 | "optional": true, 109 | "os": [ 110 | "win32" 111 | ], 112 | "engines": { 113 | "node": ">=16" 114 | } 115 | }, 116 | "node_modules/@cloudflare/workers-types": { 117 | "version": "4.20240502.0", 118 | "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240502.0.tgz", 119 | "integrity": "sha512-OB1jIyPOzyOcuZFHWhsQnkRLN6u8+jmU9X3T4KZlGgn3Ivw8pBiswhLOp+yFeChR3Y4/5+V0hPFRko5SReordg==", 120 | "dev": true 121 | }, 122 | "node_modules/@cspotcode/source-map-support": { 123 | "version": "0.8.1", 124 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 125 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 126 | "dev": true, 127 | "dependencies": { 128 | "@jridgewell/trace-mapping": "0.3.9" 129 | }, 130 | "engines": { 131 | "node": ">=12" 132 | } 133 | }, 134 | "node_modules/@esbuild-plugins/node-globals-polyfill": { 135 | "version": "0.2.3", 136 | "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", 137 | "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", 138 | "dev": true, 139 | "peerDependencies": { 140 | "esbuild": "*" 141 | } 142 | }, 143 | "node_modules/@esbuild-plugins/node-modules-polyfill": { 144 | "version": "0.2.2", 145 | "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", 146 | "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", 147 | "dev": true, 148 | "dependencies": { 149 | "escape-string-regexp": "^4.0.0", 150 | "rollup-plugin-node-polyfills": "^0.2.1" 151 | }, 152 | "peerDependencies": { 153 | "esbuild": "*" 154 | } 155 | }, 156 | "node_modules/@esbuild/android-arm": { 157 | "version": "0.17.19", 158 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", 159 | "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", 160 | "cpu": [ 161 | "arm" 162 | ], 163 | "dev": true, 164 | "optional": true, 165 | "os": [ 166 | "android" 167 | ], 168 | "engines": { 169 | "node": ">=12" 170 | } 171 | }, 172 | "node_modules/@esbuild/android-arm64": { 173 | "version": "0.17.19", 174 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", 175 | "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", 176 | "cpu": [ 177 | "arm64" 178 | ], 179 | "dev": true, 180 | "optional": true, 181 | "os": [ 182 | "android" 183 | ], 184 | "engines": { 185 | "node": ">=12" 186 | } 187 | }, 188 | "node_modules/@esbuild/android-x64": { 189 | "version": "0.17.19", 190 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", 191 | "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", 192 | "cpu": [ 193 | "x64" 194 | ], 195 | "dev": true, 196 | "optional": true, 197 | "os": [ 198 | "android" 199 | ], 200 | "engines": { 201 | "node": ">=12" 202 | } 203 | }, 204 | "node_modules/@esbuild/darwin-arm64": { 205 | "version": "0.17.19", 206 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", 207 | "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", 208 | "cpu": [ 209 | "arm64" 210 | ], 211 | "dev": true, 212 | "optional": true, 213 | "os": [ 214 | "darwin" 215 | ], 216 | "engines": { 217 | "node": ">=12" 218 | } 219 | }, 220 | "node_modules/@esbuild/darwin-x64": { 221 | "version": "0.17.19", 222 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", 223 | "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", 224 | "cpu": [ 225 | "x64" 226 | ], 227 | "dev": true, 228 | "optional": true, 229 | "os": [ 230 | "darwin" 231 | ], 232 | "engines": { 233 | "node": ">=12" 234 | } 235 | }, 236 | "node_modules/@esbuild/freebsd-arm64": { 237 | "version": "0.17.19", 238 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", 239 | "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", 240 | "cpu": [ 241 | "arm64" 242 | ], 243 | "dev": true, 244 | "optional": true, 245 | "os": [ 246 | "freebsd" 247 | ], 248 | "engines": { 249 | "node": ">=12" 250 | } 251 | }, 252 | "node_modules/@esbuild/freebsd-x64": { 253 | "version": "0.17.19", 254 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", 255 | "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", 256 | "cpu": [ 257 | "x64" 258 | ], 259 | "dev": true, 260 | "optional": true, 261 | "os": [ 262 | "freebsd" 263 | ], 264 | "engines": { 265 | "node": ">=12" 266 | } 267 | }, 268 | "node_modules/@esbuild/linux-arm": { 269 | "version": "0.17.19", 270 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", 271 | "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", 272 | "cpu": [ 273 | "arm" 274 | ], 275 | "dev": true, 276 | "optional": true, 277 | "os": [ 278 | "linux" 279 | ], 280 | "engines": { 281 | "node": ">=12" 282 | } 283 | }, 284 | "node_modules/@esbuild/linux-arm64": { 285 | "version": "0.17.19", 286 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", 287 | "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", 288 | "cpu": [ 289 | "arm64" 290 | ], 291 | "dev": true, 292 | "optional": true, 293 | "os": [ 294 | "linux" 295 | ], 296 | "engines": { 297 | "node": ">=12" 298 | } 299 | }, 300 | "node_modules/@esbuild/linux-ia32": { 301 | "version": "0.17.19", 302 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", 303 | "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", 304 | "cpu": [ 305 | "ia32" 306 | ], 307 | "dev": true, 308 | "optional": true, 309 | "os": [ 310 | "linux" 311 | ], 312 | "engines": { 313 | "node": ">=12" 314 | } 315 | }, 316 | "node_modules/@esbuild/linux-loong64": { 317 | "version": "0.17.19", 318 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", 319 | "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", 320 | "cpu": [ 321 | "loong64" 322 | ], 323 | "dev": true, 324 | "optional": true, 325 | "os": [ 326 | "linux" 327 | ], 328 | "engines": { 329 | "node": ">=12" 330 | } 331 | }, 332 | "node_modules/@esbuild/linux-mips64el": { 333 | "version": "0.17.19", 334 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", 335 | "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", 336 | "cpu": [ 337 | "mips64el" 338 | ], 339 | "dev": true, 340 | "optional": true, 341 | "os": [ 342 | "linux" 343 | ], 344 | "engines": { 345 | "node": ">=12" 346 | } 347 | }, 348 | "node_modules/@esbuild/linux-ppc64": { 349 | "version": "0.17.19", 350 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", 351 | "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", 352 | "cpu": [ 353 | "ppc64" 354 | ], 355 | "dev": true, 356 | "optional": true, 357 | "os": [ 358 | "linux" 359 | ], 360 | "engines": { 361 | "node": ">=12" 362 | } 363 | }, 364 | "node_modules/@esbuild/linux-riscv64": { 365 | "version": "0.17.19", 366 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", 367 | "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", 368 | "cpu": [ 369 | "riscv64" 370 | ], 371 | "dev": true, 372 | "optional": true, 373 | "os": [ 374 | "linux" 375 | ], 376 | "engines": { 377 | "node": ">=12" 378 | } 379 | }, 380 | "node_modules/@esbuild/linux-s390x": { 381 | "version": "0.17.19", 382 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", 383 | "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", 384 | "cpu": [ 385 | "s390x" 386 | ], 387 | "dev": true, 388 | "optional": true, 389 | "os": [ 390 | "linux" 391 | ], 392 | "engines": { 393 | "node": ">=12" 394 | } 395 | }, 396 | "node_modules/@esbuild/linux-x64": { 397 | "version": "0.17.19", 398 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", 399 | "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", 400 | "cpu": [ 401 | "x64" 402 | ], 403 | "dev": true, 404 | "optional": true, 405 | "os": [ 406 | "linux" 407 | ], 408 | "engines": { 409 | "node": ">=12" 410 | } 411 | }, 412 | "node_modules/@esbuild/netbsd-x64": { 413 | "version": "0.17.19", 414 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", 415 | "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", 416 | "cpu": [ 417 | "x64" 418 | ], 419 | "dev": true, 420 | "optional": true, 421 | "os": [ 422 | "netbsd" 423 | ], 424 | "engines": { 425 | "node": ">=12" 426 | } 427 | }, 428 | "node_modules/@esbuild/openbsd-x64": { 429 | "version": "0.17.19", 430 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", 431 | "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", 432 | "cpu": [ 433 | "x64" 434 | ], 435 | "dev": true, 436 | "optional": true, 437 | "os": [ 438 | "openbsd" 439 | ], 440 | "engines": { 441 | "node": ">=12" 442 | } 443 | }, 444 | "node_modules/@esbuild/sunos-x64": { 445 | "version": "0.17.19", 446 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", 447 | "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", 448 | "cpu": [ 449 | "x64" 450 | ], 451 | "dev": true, 452 | "optional": true, 453 | "os": [ 454 | "sunos" 455 | ], 456 | "engines": { 457 | "node": ">=12" 458 | } 459 | }, 460 | "node_modules/@esbuild/win32-arm64": { 461 | "version": "0.17.19", 462 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", 463 | "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", 464 | "cpu": [ 465 | "arm64" 466 | ], 467 | "dev": true, 468 | "optional": true, 469 | "os": [ 470 | "win32" 471 | ], 472 | "engines": { 473 | "node": ">=12" 474 | } 475 | }, 476 | "node_modules/@esbuild/win32-ia32": { 477 | "version": "0.17.19", 478 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", 479 | "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", 480 | "cpu": [ 481 | "ia32" 482 | ], 483 | "dev": true, 484 | "optional": true, 485 | "os": [ 486 | "win32" 487 | ], 488 | "engines": { 489 | "node": ">=12" 490 | } 491 | }, 492 | "node_modules/@esbuild/win32-x64": { 493 | "version": "0.17.19", 494 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", 495 | "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", 496 | "cpu": [ 497 | "x64" 498 | ], 499 | "dev": true, 500 | "optional": true, 501 | "os": [ 502 | "win32" 503 | ], 504 | "engines": { 505 | "node": ">=12" 506 | } 507 | }, 508 | "node_modules/@fastify/busboy": { 509 | "version": "2.1.1", 510 | "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", 511 | "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", 512 | "dev": true, 513 | "engines": { 514 | "node": ">=14" 515 | } 516 | }, 517 | "node_modules/@jridgewell/resolve-uri": { 518 | "version": "3.1.2", 519 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 520 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 521 | "dev": true, 522 | "engines": { 523 | "node": ">=6.0.0" 524 | } 525 | }, 526 | "node_modules/@jridgewell/sourcemap-codec": { 527 | "version": "1.4.15", 528 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 529 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 530 | "dev": true 531 | }, 532 | "node_modules/@jridgewell/trace-mapping": { 533 | "version": "0.3.9", 534 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 535 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 536 | "dev": true, 537 | "dependencies": { 538 | "@jridgewell/resolve-uri": "^3.0.3", 539 | "@jridgewell/sourcemap-codec": "^1.4.10" 540 | } 541 | }, 542 | "node_modules/@types/node": { 543 | "version": "20.12.11", 544 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", 545 | "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", 546 | "dev": true, 547 | "dependencies": { 548 | "undici-types": "~5.26.4" 549 | } 550 | }, 551 | "node_modules/@types/node-forge": { 552 | "version": "1.3.11", 553 | "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", 554 | "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", 555 | "dev": true, 556 | "dependencies": { 557 | "@types/node": "*" 558 | } 559 | }, 560 | "node_modules/acorn": { 561 | "version": "8.11.3", 562 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", 563 | "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", 564 | "dev": true, 565 | "bin": { 566 | "acorn": "bin/acorn" 567 | }, 568 | "engines": { 569 | "node": ">=0.4.0" 570 | } 571 | }, 572 | "node_modules/acorn-walk": { 573 | "version": "8.3.2", 574 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", 575 | "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", 576 | "dev": true, 577 | "engines": { 578 | "node": ">=0.4.0" 579 | } 580 | }, 581 | "node_modules/anymatch": { 582 | "version": "3.1.3", 583 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 584 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 585 | "dev": true, 586 | "dependencies": { 587 | "normalize-path": "^3.0.0", 588 | "picomatch": "^2.0.4" 589 | }, 590 | "engines": { 591 | "node": ">= 8" 592 | } 593 | }, 594 | "node_modules/as-table": { 595 | "version": "1.0.55", 596 | "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", 597 | "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", 598 | "dev": true, 599 | "dependencies": { 600 | "printable-characters": "^1.0.42" 601 | } 602 | }, 603 | "node_modules/binary-extensions": { 604 | "version": "2.3.0", 605 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 606 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 607 | "dev": true, 608 | "engines": { 609 | "node": ">=8" 610 | }, 611 | "funding": { 612 | "url": "https://github.com/sponsors/sindresorhus" 613 | } 614 | }, 615 | "node_modules/blake3-wasm": { 616 | "version": "2.1.5", 617 | "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", 618 | "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", 619 | "dev": true 620 | }, 621 | "node_modules/braces": { 622 | "version": "3.0.2", 623 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 624 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 625 | "dev": true, 626 | "dependencies": { 627 | "fill-range": "^7.0.1" 628 | }, 629 | "engines": { 630 | "node": ">=8" 631 | } 632 | }, 633 | "node_modules/capnp-ts": { 634 | "version": "0.7.0", 635 | "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", 636 | "integrity": "sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==", 637 | "dev": true, 638 | "dependencies": { 639 | "debug": "^4.3.1", 640 | "tslib": "^2.2.0" 641 | } 642 | }, 643 | "node_modules/chokidar": { 644 | "version": "3.6.0", 645 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", 646 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 647 | "dev": true, 648 | "dependencies": { 649 | "anymatch": "~3.1.2", 650 | "braces": "~3.0.2", 651 | "glob-parent": "~5.1.2", 652 | "is-binary-path": "~2.1.0", 653 | "is-glob": "~4.0.1", 654 | "normalize-path": "~3.0.0", 655 | "readdirp": "~3.6.0" 656 | }, 657 | "engines": { 658 | "node": ">= 8.10.0" 659 | }, 660 | "funding": { 661 | "url": "https://paulmillr.com/funding/" 662 | }, 663 | "optionalDependencies": { 664 | "fsevents": "~2.3.2" 665 | } 666 | }, 667 | "node_modules/cookie": { 668 | "version": "0.5.0", 669 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 670 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 671 | "dev": true, 672 | "engines": { 673 | "node": ">= 0.6" 674 | } 675 | }, 676 | "node_modules/data-uri-to-buffer": { 677 | "version": "2.0.2", 678 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", 679 | "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", 680 | "dev": true 681 | }, 682 | "node_modules/debug": { 683 | "version": "4.3.4", 684 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 685 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 686 | "dev": true, 687 | "dependencies": { 688 | "ms": "2.1.2" 689 | }, 690 | "engines": { 691 | "node": ">=6.0" 692 | }, 693 | "peerDependenciesMeta": { 694 | "supports-color": { 695 | "optional": true 696 | } 697 | } 698 | }, 699 | "node_modules/esbuild": { 700 | "version": "0.17.19", 701 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", 702 | "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", 703 | "dev": true, 704 | "hasInstallScript": true, 705 | "bin": { 706 | "esbuild": "bin/esbuild" 707 | }, 708 | "engines": { 709 | "node": ">=12" 710 | }, 711 | "optionalDependencies": { 712 | "@esbuild/android-arm": "0.17.19", 713 | "@esbuild/android-arm64": "0.17.19", 714 | "@esbuild/android-x64": "0.17.19", 715 | "@esbuild/darwin-arm64": "0.17.19", 716 | "@esbuild/darwin-x64": "0.17.19", 717 | "@esbuild/freebsd-arm64": "0.17.19", 718 | "@esbuild/freebsd-x64": "0.17.19", 719 | "@esbuild/linux-arm": "0.17.19", 720 | "@esbuild/linux-arm64": "0.17.19", 721 | "@esbuild/linux-ia32": "0.17.19", 722 | "@esbuild/linux-loong64": "0.17.19", 723 | "@esbuild/linux-mips64el": "0.17.19", 724 | "@esbuild/linux-ppc64": "0.17.19", 725 | "@esbuild/linux-riscv64": "0.17.19", 726 | "@esbuild/linux-s390x": "0.17.19", 727 | "@esbuild/linux-x64": "0.17.19", 728 | "@esbuild/netbsd-x64": "0.17.19", 729 | "@esbuild/openbsd-x64": "0.17.19", 730 | "@esbuild/sunos-x64": "0.17.19", 731 | "@esbuild/win32-arm64": "0.17.19", 732 | "@esbuild/win32-ia32": "0.17.19", 733 | "@esbuild/win32-x64": "0.17.19" 734 | } 735 | }, 736 | "node_modules/escape-string-regexp": { 737 | "version": "4.0.0", 738 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 739 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 740 | "dev": true, 741 | "engines": { 742 | "node": ">=10" 743 | }, 744 | "funding": { 745 | "url": "https://github.com/sponsors/sindresorhus" 746 | } 747 | }, 748 | "node_modules/estree-walker": { 749 | "version": "0.6.1", 750 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", 751 | "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", 752 | "dev": true 753 | }, 754 | "node_modules/exit-hook": { 755 | "version": "2.2.1", 756 | "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", 757 | "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", 758 | "dev": true, 759 | "engines": { 760 | "node": ">=6" 761 | }, 762 | "funding": { 763 | "url": "https://github.com/sponsors/sindresorhus" 764 | } 765 | }, 766 | "node_modules/fill-range": { 767 | "version": "7.0.1", 768 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 769 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 770 | "dev": true, 771 | "dependencies": { 772 | "to-regex-range": "^5.0.1" 773 | }, 774 | "engines": { 775 | "node": ">=8" 776 | } 777 | }, 778 | "node_modules/fsevents": { 779 | "version": "2.3.3", 780 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 781 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 782 | "dev": true, 783 | "hasInstallScript": true, 784 | "optional": true, 785 | "os": [ 786 | "darwin" 787 | ], 788 | "engines": { 789 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 790 | } 791 | }, 792 | "node_modules/function-bind": { 793 | "version": "1.1.2", 794 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 795 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 796 | "dev": true, 797 | "funding": { 798 | "url": "https://github.com/sponsors/ljharb" 799 | } 800 | }, 801 | "node_modules/get-source": { 802 | "version": "2.0.12", 803 | "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", 804 | "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", 805 | "dev": true, 806 | "dependencies": { 807 | "data-uri-to-buffer": "^2.0.0", 808 | "source-map": "^0.6.1" 809 | } 810 | }, 811 | "node_modules/glob-parent": { 812 | "version": "5.1.2", 813 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 814 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 815 | "dev": true, 816 | "dependencies": { 817 | "is-glob": "^4.0.1" 818 | }, 819 | "engines": { 820 | "node": ">= 6" 821 | } 822 | }, 823 | "node_modules/glob-to-regexp": { 824 | "version": "0.4.1", 825 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", 826 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", 827 | "dev": true 828 | }, 829 | "node_modules/hasown": { 830 | "version": "2.0.2", 831 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 832 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 833 | "dev": true, 834 | "dependencies": { 835 | "function-bind": "^1.1.2" 836 | }, 837 | "engines": { 838 | "node": ">= 0.4" 839 | } 840 | }, 841 | "node_modules/hono": { 842 | "version": "4.3.4", 843 | "resolved": "https://registry.npmjs.org/hono/-/hono-4.3.4.tgz", 844 | "integrity": "sha512-oh+PBwW8yElj3bUlY2dTXhuPt1MCZp6Nb04tejLwY+GXdphQH6uCpUP0dY5iLvFY5wM8fNHrMx1QeMKbhnzw9w==", 845 | "engines": { 846 | "node": ">=16.0.0" 847 | } 848 | }, 849 | "node_modules/hono-sessions": { 850 | "resolved": "../../npm", 851 | "link": true 852 | }, 853 | "node_modules/is-binary-path": { 854 | "version": "2.1.0", 855 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 856 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 857 | "dev": true, 858 | "dependencies": { 859 | "binary-extensions": "^2.0.0" 860 | }, 861 | "engines": { 862 | "node": ">=8" 863 | } 864 | }, 865 | "node_modules/is-core-module": { 866 | "version": "2.13.1", 867 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", 868 | "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", 869 | "dev": true, 870 | "dependencies": { 871 | "hasown": "^2.0.0" 872 | }, 873 | "funding": { 874 | "url": "https://github.com/sponsors/ljharb" 875 | } 876 | }, 877 | "node_modules/is-extglob": { 878 | "version": "2.1.1", 879 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 880 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 881 | "dev": true, 882 | "engines": { 883 | "node": ">=0.10.0" 884 | } 885 | }, 886 | "node_modules/is-glob": { 887 | "version": "4.0.3", 888 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 889 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 890 | "dev": true, 891 | "dependencies": { 892 | "is-extglob": "^2.1.1" 893 | }, 894 | "engines": { 895 | "node": ">=0.10.0" 896 | } 897 | }, 898 | "node_modules/is-number": { 899 | "version": "7.0.0", 900 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 901 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 902 | "dev": true, 903 | "engines": { 904 | "node": ">=0.12.0" 905 | } 906 | }, 907 | "node_modules/magic-string": { 908 | "version": "0.25.9", 909 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 910 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 911 | "dev": true, 912 | "dependencies": { 913 | "sourcemap-codec": "^1.4.8" 914 | } 915 | }, 916 | "node_modules/mime": { 917 | "version": "3.0.0", 918 | "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", 919 | "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", 920 | "dev": true, 921 | "bin": { 922 | "mime": "cli.js" 923 | }, 924 | "engines": { 925 | "node": ">=10.0.0" 926 | } 927 | }, 928 | "node_modules/miniflare": { 929 | "version": "3.20240419.1", 930 | "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240419.1.tgz", 931 | "integrity": "sha512-Q9n0W07uUD/u0c/b03E4iogeXOAMjZnE3P7B5Yi8sPaZAx6TYWwjurGBja+Pg2yILN2iMaliEobfVyAKss33cA==", 932 | "dev": true, 933 | "dependencies": { 934 | "@cspotcode/source-map-support": "0.8.1", 935 | "acorn": "^8.8.0", 936 | "acorn-walk": "^8.2.0", 937 | "capnp-ts": "^0.7.0", 938 | "exit-hook": "^2.2.1", 939 | "glob-to-regexp": "^0.4.1", 940 | "stoppable": "^1.1.0", 941 | "undici": "^5.28.2", 942 | "workerd": "1.20240419.0", 943 | "ws": "^8.11.0", 944 | "youch": "^3.2.2", 945 | "zod": "^3.20.6" 946 | }, 947 | "bin": { 948 | "miniflare": "bootstrap.js" 949 | }, 950 | "engines": { 951 | "node": ">=16.13" 952 | } 953 | }, 954 | "node_modules/ms": { 955 | "version": "2.1.2", 956 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 957 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 958 | "dev": true 959 | }, 960 | "node_modules/mustache": { 961 | "version": "4.2.0", 962 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", 963 | "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", 964 | "dev": true, 965 | "bin": { 966 | "mustache": "bin/mustache" 967 | } 968 | }, 969 | "node_modules/nanoid": { 970 | "version": "3.3.7", 971 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", 972 | "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", 973 | "dev": true, 974 | "funding": [ 975 | { 976 | "type": "github", 977 | "url": "https://github.com/sponsors/ai" 978 | } 979 | ], 980 | "bin": { 981 | "nanoid": "bin/nanoid.cjs" 982 | }, 983 | "engines": { 984 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 985 | } 986 | }, 987 | "node_modules/node-forge": { 988 | "version": "1.3.1", 989 | "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", 990 | "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", 991 | "dev": true, 992 | "engines": { 993 | "node": ">= 6.13.0" 994 | } 995 | }, 996 | "node_modules/normalize-path": { 997 | "version": "3.0.0", 998 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 999 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1000 | "dev": true, 1001 | "engines": { 1002 | "node": ">=0.10.0" 1003 | } 1004 | }, 1005 | "node_modules/path-parse": { 1006 | "version": "1.0.7", 1007 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1008 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1009 | "dev": true 1010 | }, 1011 | "node_modules/path-to-regexp": { 1012 | "version": "6.2.2", 1013 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", 1014 | "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", 1015 | "dev": true 1016 | }, 1017 | "node_modules/picomatch": { 1018 | "version": "2.3.1", 1019 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1020 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1021 | "dev": true, 1022 | "engines": { 1023 | "node": ">=8.6" 1024 | }, 1025 | "funding": { 1026 | "url": "https://github.com/sponsors/jonschlinkert" 1027 | } 1028 | }, 1029 | "node_modules/printable-characters": { 1030 | "version": "1.0.42", 1031 | "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", 1032 | "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", 1033 | "dev": true 1034 | }, 1035 | "node_modules/readdirp": { 1036 | "version": "3.6.0", 1037 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1038 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1039 | "dev": true, 1040 | "dependencies": { 1041 | "picomatch": "^2.2.1" 1042 | }, 1043 | "engines": { 1044 | "node": ">=8.10.0" 1045 | } 1046 | }, 1047 | "node_modules/resolve": { 1048 | "version": "1.22.8", 1049 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", 1050 | "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", 1051 | "dev": true, 1052 | "dependencies": { 1053 | "is-core-module": "^2.13.0", 1054 | "path-parse": "^1.0.7", 1055 | "supports-preserve-symlinks-flag": "^1.0.0" 1056 | }, 1057 | "bin": { 1058 | "resolve": "bin/resolve" 1059 | }, 1060 | "funding": { 1061 | "url": "https://github.com/sponsors/ljharb" 1062 | } 1063 | }, 1064 | "node_modules/resolve.exports": { 1065 | "version": "2.0.2", 1066 | "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", 1067 | "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", 1068 | "dev": true, 1069 | "engines": { 1070 | "node": ">=10" 1071 | } 1072 | }, 1073 | "node_modules/rollup-plugin-inject": { 1074 | "version": "3.0.2", 1075 | "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", 1076 | "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", 1077 | "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", 1078 | "dev": true, 1079 | "dependencies": { 1080 | "estree-walker": "^0.6.1", 1081 | "magic-string": "^0.25.3", 1082 | "rollup-pluginutils": "^2.8.1" 1083 | } 1084 | }, 1085 | "node_modules/rollup-plugin-node-polyfills": { 1086 | "version": "0.2.1", 1087 | "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", 1088 | "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", 1089 | "dev": true, 1090 | "dependencies": { 1091 | "rollup-plugin-inject": "^3.0.0" 1092 | } 1093 | }, 1094 | "node_modules/rollup-pluginutils": { 1095 | "version": "2.8.2", 1096 | "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", 1097 | "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", 1098 | "dev": true, 1099 | "dependencies": { 1100 | "estree-walker": "^0.6.1" 1101 | } 1102 | }, 1103 | "node_modules/selfsigned": { 1104 | "version": "2.4.1", 1105 | "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", 1106 | "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", 1107 | "dev": true, 1108 | "dependencies": { 1109 | "@types/node-forge": "^1.3.0", 1110 | "node-forge": "^1" 1111 | }, 1112 | "engines": { 1113 | "node": ">=10" 1114 | } 1115 | }, 1116 | "node_modules/source-map": { 1117 | "version": "0.6.1", 1118 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1119 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1120 | "dev": true, 1121 | "engines": { 1122 | "node": ">=0.10.0" 1123 | } 1124 | }, 1125 | "node_modules/sourcemap-codec": { 1126 | "version": "1.4.8", 1127 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 1128 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 1129 | "deprecated": "Please use @jridgewell/sourcemap-codec instead", 1130 | "dev": true 1131 | }, 1132 | "node_modules/stacktracey": { 1133 | "version": "2.1.8", 1134 | "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", 1135 | "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", 1136 | "dev": true, 1137 | "dependencies": { 1138 | "as-table": "^1.0.36", 1139 | "get-source": "^2.0.12" 1140 | } 1141 | }, 1142 | "node_modules/stoppable": { 1143 | "version": "1.1.0", 1144 | "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", 1145 | "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", 1146 | "dev": true, 1147 | "engines": { 1148 | "node": ">=4", 1149 | "npm": ">=6" 1150 | } 1151 | }, 1152 | "node_modules/supports-preserve-symlinks-flag": { 1153 | "version": "1.0.0", 1154 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1155 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1156 | "dev": true, 1157 | "engines": { 1158 | "node": ">= 0.4" 1159 | }, 1160 | "funding": { 1161 | "url": "https://github.com/sponsors/ljharb" 1162 | } 1163 | }, 1164 | "node_modules/to-regex-range": { 1165 | "version": "5.0.1", 1166 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1167 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1168 | "dev": true, 1169 | "dependencies": { 1170 | "is-number": "^7.0.0" 1171 | }, 1172 | "engines": { 1173 | "node": ">=8.0" 1174 | } 1175 | }, 1176 | "node_modules/tslib": { 1177 | "version": "2.6.2", 1178 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", 1179 | "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", 1180 | "dev": true 1181 | }, 1182 | "node_modules/undici": { 1183 | "version": "5.28.4", 1184 | "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", 1185 | "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", 1186 | "dev": true, 1187 | "dependencies": { 1188 | "@fastify/busboy": "^2.0.0" 1189 | }, 1190 | "engines": { 1191 | "node": ">=14.0" 1192 | } 1193 | }, 1194 | "node_modules/undici-types": { 1195 | "version": "5.26.5", 1196 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", 1197 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", 1198 | "dev": true 1199 | }, 1200 | "node_modules/workerd": { 1201 | "version": "1.20240419.0", 1202 | "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240419.0.tgz", 1203 | "integrity": "sha512-9yV98KpkQgG+bdEsKEW8i1AYZgxns6NVSfdOVEB2Ue1pTMtIEYfUyqUE+O2amisRrfaC3Pw4EvjtTmVaoetfeg==", 1204 | "dev": true, 1205 | "hasInstallScript": true, 1206 | "bin": { 1207 | "workerd": "bin/workerd" 1208 | }, 1209 | "engines": { 1210 | "node": ">=16" 1211 | }, 1212 | "optionalDependencies": { 1213 | "@cloudflare/workerd-darwin-64": "1.20240419.0", 1214 | "@cloudflare/workerd-darwin-arm64": "1.20240419.0", 1215 | "@cloudflare/workerd-linux-64": "1.20240419.0", 1216 | "@cloudflare/workerd-linux-arm64": "1.20240419.0", 1217 | "@cloudflare/workerd-windows-64": "1.20240419.0" 1218 | } 1219 | }, 1220 | "node_modules/wrangler": { 1221 | "version": "3.55.0", 1222 | "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.55.0.tgz", 1223 | "integrity": "sha512-VhtCioKxOdVqkHa8jQ6C6bX3by2Ko0uM0DKzrA+6lBZvfDUlGDWSOPiG+1fOHBHj2JTVBntxWCztXP6L+Udr8w==", 1224 | "dev": true, 1225 | "dependencies": { 1226 | "@cloudflare/kv-asset-handler": "0.3.2", 1227 | "@esbuild-plugins/node-globals-polyfill": "^0.2.3", 1228 | "@esbuild-plugins/node-modules-polyfill": "^0.2.2", 1229 | "blake3-wasm": "^2.1.5", 1230 | "chokidar": "^3.5.3", 1231 | "esbuild": "0.17.19", 1232 | "miniflare": "3.20240419.1", 1233 | "nanoid": "^3.3.3", 1234 | "path-to-regexp": "^6.2.0", 1235 | "resolve": "^1.22.8", 1236 | "resolve.exports": "^2.0.2", 1237 | "selfsigned": "^2.0.1", 1238 | "source-map": "0.6.1", 1239 | "xxhash-wasm": "^1.0.1" 1240 | }, 1241 | "bin": { 1242 | "wrangler": "bin/wrangler.js", 1243 | "wrangler2": "bin/wrangler.js" 1244 | }, 1245 | "engines": { 1246 | "node": ">=16.17.0" 1247 | }, 1248 | "optionalDependencies": { 1249 | "fsevents": "~2.3.2" 1250 | }, 1251 | "peerDependencies": { 1252 | "@cloudflare/workers-types": "^4.20240419.0" 1253 | }, 1254 | "peerDependenciesMeta": { 1255 | "@cloudflare/workers-types": { 1256 | "optional": true 1257 | } 1258 | } 1259 | }, 1260 | "node_modules/ws": { 1261 | "version": "8.17.0", 1262 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", 1263 | "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", 1264 | "dev": true, 1265 | "engines": { 1266 | "node": ">=10.0.0" 1267 | }, 1268 | "peerDependencies": { 1269 | "bufferutil": "^4.0.1", 1270 | "utf-8-validate": ">=5.0.2" 1271 | }, 1272 | "peerDependenciesMeta": { 1273 | "bufferutil": { 1274 | "optional": true 1275 | }, 1276 | "utf-8-validate": { 1277 | "optional": true 1278 | } 1279 | } 1280 | }, 1281 | "node_modules/xxhash-wasm": { 1282 | "version": "1.0.2", 1283 | "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz", 1284 | "integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==", 1285 | "dev": true 1286 | }, 1287 | "node_modules/youch": { 1288 | "version": "3.3.3", 1289 | "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.3.tgz", 1290 | "integrity": "sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==", 1291 | "dev": true, 1292 | "dependencies": { 1293 | "cookie": "^0.5.0", 1294 | "mustache": "^4.2.0", 1295 | "stacktracey": "^2.1.8" 1296 | } 1297 | }, 1298 | "node_modules/zod": { 1299 | "version": "3.23.8", 1300 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", 1301 | "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", 1302 | "dev": true, 1303 | "funding": { 1304 | "url": "https://github.com/sponsors/colinhacks" 1305 | } 1306 | } 1307 | } 1308 | } 1309 | -------------------------------------------------------------------------------- /test/cloudflare_workers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev": "wrangler dev src/index.ts", 4 | "deploy": "wrangler deploy --minify src/index.ts" 5 | }, 6 | "dependencies": { 7 | "hono": "^4.0.0", 8 | "hono-sessions": "file:../../npm" 9 | }, 10 | "devDependencies": { 11 | "@cloudflare/workers-types": "^4.20230821.0", 12 | "wrangler": "^3.7.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/cloudflare_workers/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Hono } from "hono"; 2 | import { html } from "hono/html"; 3 | import { sessionMiddleware, CookieStore, Session } from "hono-sessions"; 4 | 5 | const app = new Hono() 6 | 7 | const store = new CookieStore() 8 | 9 | const session_routes = new Hono<{ 10 | Variables: { 11 | session: Session, 12 | session_key_rotation: boolean 13 | } 14 | }>() 15 | 16 | session_routes.use('*', sessionMiddleware({ 17 | store, 18 | expireAfterSeconds: 30, 19 | cookieOptions: { 20 | sameSite: 'Lax', 21 | path: '/', 22 | httpOnly: true, 23 | }, 24 | encryptionKey: 'string_at_least_32_characters_long' 25 | })) 26 | 27 | session_routes.post('/login', async (c) => { 28 | const session = c.get('session') 29 | 30 | const { email, password } = await c.req.parseBody() 31 | 32 | if (password === 'correct') { 33 | c.set('session_key_rotation', true) 34 | session.set('email', email) 35 | session.forget('failed-login-attempts') 36 | session.flash('message', 'Login Successful') 37 | } else { 38 | const failedLoginAttempts = (session.get('failed-login-attempts') || 0) as number 39 | session.set('failed-login-attempts', failedLoginAttempts + 1) 40 | session.flash('error', 'Incorrect username or password') 41 | } 42 | 43 | return c.redirect('/') 44 | }) 45 | 46 | session_routes.post('/logout', (c) => { 47 | c.get('session').deleteSession() 48 | return c.redirect('/') 49 | }) 50 | 51 | session_routes.get('/', (c) => { 52 | const session = c.get('session') 53 | 54 | const message = session.get('message') || '' 55 | const error = session.get('error') || '' 56 | const failedLoginAttempts = session.get('failed-login-attempts') 57 | const email = session.get('email') 58 | 59 | return c.html(html` 60 | 61 | 62 | 63 | 64 | 65 | Hono Sessions 66 | 67 | 68 | ${ message && html`

${message}

` } 69 | ${ error && html`

${error}

` } 70 | ${ failedLoginAttempts && html`

Failed login attempts: ${ failedLoginAttempts }

` } 71 | 72 | ${email ? 73 | html`
74 | 75 |
` 76 | : 77 | html`
78 |

79 | 80 |

81 |

82 | 83 |

84 | 85 |
` 86 | } 87 | 88 | `) 89 | }) 90 | 91 | app.route('/', session_routes) 92 | 93 | export default app; -------------------------------------------------------------------------------- /test/cloudflare_workers/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "strict": true, 8 | "lib": [ 9 | "esnext" 10 | ], 11 | "types": [ 12 | "@cloudflare/workers-types" 13 | ], 14 | "jsx": "react-jsx", 15 | "jsxImportSource": "hono/jsx" 16 | }, 17 | } -------------------------------------------------------------------------------- /test/deno/MakeStore.ts: -------------------------------------------------------------------------------- 1 | import { Store, CookieStore, MemoryStore } from '../../mod.ts' 2 | 3 | export async function MakeDenoStore(storeDriver: string | undefined): Promise { 4 | let store: Store | CookieStore 5 | 6 | switch(storeDriver) { 7 | case 'memory': 8 | store = new MemoryStore() 9 | break 10 | case 'cookie': 11 | store = new CookieStore() 12 | break 13 | default: 14 | store = new MemoryStore() 15 | break 16 | } 17 | 18 | return store 19 | } -------------------------------------------------------------------------------- /test/deno/server_deno.ts: -------------------------------------------------------------------------------- 1 | import { Hono } from 'npm:hono@^4.0.0' 2 | import { html } from 'npm:hono@^4.0.0/html' 3 | import { sessionMiddleware as session, Session } from '../../mod.ts' 4 | import { MakeDenoStore } from './MakeStore.ts' 5 | import 'https://deno.land/std@0.198.0/dotenv/load.ts' 6 | 7 | const app = new Hono() 8 | const store = await MakeDenoStore(Deno.env.get('STORE')) 9 | 10 | type SessionDataTypes = { 11 | 'email': string 12 | 'failed-login-attempts': number | null 13 | 'message': string 14 | 'error': string 15 | } 16 | 17 | const session_routes = new Hono<{ 18 | Variables: { 19 | session: Session, 20 | session_key_rotation: boolean 21 | } 22 | }>() 23 | 24 | session_routes.use('*', session({ 25 | store, 26 | encryptionKey: Deno.env.get('ENCRYPTION_KEY'), 27 | expireAfterSeconds: 30, 28 | cookieOptions: { 29 | sameSite: 'Lax', 30 | path: '/', 31 | httpOnly: true, 32 | }, 33 | })) 34 | 35 | session_routes.post('/login', async (c) => { 36 | const session = c.get('session') 37 | 38 | const { email, password } = await c.req.parseBody() 39 | 40 | if (password === 'correct') { 41 | c.set('session_key_rotation', true) 42 | session.set('email', email as string) 43 | session.forget('failed-login-attempts') 44 | session.flash('message', 'Login Successful') 45 | } else { 46 | const failedLoginAttempts = (session.get('failed-login-attempts') || 0) as number 47 | session.set('failed-login-attempts', failedLoginAttempts + 1) 48 | session.flash('error', 'Incorrect username or password') 49 | } 50 | 51 | return c.redirect('/') 52 | }) 53 | 54 | session_routes.post('/logout', (c) => { 55 | c.get('session').deleteSession() 56 | return c.redirect('/') 57 | }) 58 | 59 | session_routes.get('/', (c) => { 60 | const session = c.get('session') 61 | 62 | const message = session.get('message') || '' 63 | const error = session.get('error') || '' 64 | const failedLoginAttempts = session.get('failed-login-attempts') 65 | const email = session.get('email') 66 | 67 | return c.html(html` 68 | 69 | 70 | 71 | 72 | 73 | Hono Sessions 74 | 75 | 76 | ${ message && html`

${message}

` } 77 | ${ error && html`

${error}

` } 78 | ${ failedLoginAttempts && html`

Failed login attempts: ${ failedLoginAttempts }

` } 79 | 80 | ${email ? 81 | html`
82 | 83 |
` 84 | : 85 | html`
86 |

87 | 88 |

89 |

90 | 91 |

92 | 93 |
` 94 | } 95 | 96 | `) 97 | }) 98 | 99 | app.route('/', session_routes) 100 | 101 | Deno.serve(app.fetch) -------------------------------------------------------------------------------- /test/deno/tmp/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jcs224/hono_sessions/d29f2214f5a39158c952d4b3c0b53ff1d5ddedaa/test/deno/tmp/.gitkeep -------------------------------------------------------------------------------- /test/node/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /test/node/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | npm install 3 | npm run dev 4 | ``` 5 | 6 | ``` 7 | open http://localhost:3000 8 | ``` 9 | -------------------------------------------------------------------------------- /test/node/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "@hono/node-server": "^1.7.0", 9 | "hono": "^4.0.0", 10 | "hono-sessions": "../../npm" 11 | }, 12 | "devDependencies": { 13 | "tsx": "^3.12.2" 14 | } 15 | }, 16 | "../../npm": { 17 | "version": "0.4.2", 18 | "license": "MIT", 19 | "dependencies": { 20 | "hono": "^4.0.0", 21 | "iron-webcrypto": "0.10.1" 22 | } 23 | }, 24 | "node_modules/@esbuild/android-arm": { 25 | "version": "0.18.20", 26 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", 27 | "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", 28 | "cpu": [ 29 | "arm" 30 | ], 31 | "dev": true, 32 | "optional": true, 33 | "os": [ 34 | "android" 35 | ], 36 | "engines": { 37 | "node": ">=12" 38 | } 39 | }, 40 | "node_modules/@esbuild/android-arm64": { 41 | "version": "0.18.20", 42 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", 43 | "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", 44 | "cpu": [ 45 | "arm64" 46 | ], 47 | "dev": true, 48 | "optional": true, 49 | "os": [ 50 | "android" 51 | ], 52 | "engines": { 53 | "node": ">=12" 54 | } 55 | }, 56 | "node_modules/@esbuild/android-x64": { 57 | "version": "0.18.20", 58 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", 59 | "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", 60 | "cpu": [ 61 | "x64" 62 | ], 63 | "dev": true, 64 | "optional": true, 65 | "os": [ 66 | "android" 67 | ], 68 | "engines": { 69 | "node": ">=12" 70 | } 71 | }, 72 | "node_modules/@esbuild/darwin-arm64": { 73 | "version": "0.18.20", 74 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", 75 | "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", 76 | "cpu": [ 77 | "arm64" 78 | ], 79 | "dev": true, 80 | "optional": true, 81 | "os": [ 82 | "darwin" 83 | ], 84 | "engines": { 85 | "node": ">=12" 86 | } 87 | }, 88 | "node_modules/@esbuild/darwin-x64": { 89 | "version": "0.18.20", 90 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", 91 | "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", 92 | "cpu": [ 93 | "x64" 94 | ], 95 | "dev": true, 96 | "optional": true, 97 | "os": [ 98 | "darwin" 99 | ], 100 | "engines": { 101 | "node": ">=12" 102 | } 103 | }, 104 | "node_modules/@esbuild/freebsd-arm64": { 105 | "version": "0.18.20", 106 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", 107 | "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", 108 | "cpu": [ 109 | "arm64" 110 | ], 111 | "dev": true, 112 | "optional": true, 113 | "os": [ 114 | "freebsd" 115 | ], 116 | "engines": { 117 | "node": ">=12" 118 | } 119 | }, 120 | "node_modules/@esbuild/freebsd-x64": { 121 | "version": "0.18.20", 122 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", 123 | "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", 124 | "cpu": [ 125 | "x64" 126 | ], 127 | "dev": true, 128 | "optional": true, 129 | "os": [ 130 | "freebsd" 131 | ], 132 | "engines": { 133 | "node": ">=12" 134 | } 135 | }, 136 | "node_modules/@esbuild/linux-arm": { 137 | "version": "0.18.20", 138 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", 139 | "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", 140 | "cpu": [ 141 | "arm" 142 | ], 143 | "dev": true, 144 | "optional": true, 145 | "os": [ 146 | "linux" 147 | ], 148 | "engines": { 149 | "node": ">=12" 150 | } 151 | }, 152 | "node_modules/@esbuild/linux-arm64": { 153 | "version": "0.18.20", 154 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", 155 | "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", 156 | "cpu": [ 157 | "arm64" 158 | ], 159 | "dev": true, 160 | "optional": true, 161 | "os": [ 162 | "linux" 163 | ], 164 | "engines": { 165 | "node": ">=12" 166 | } 167 | }, 168 | "node_modules/@esbuild/linux-ia32": { 169 | "version": "0.18.20", 170 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", 171 | "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", 172 | "cpu": [ 173 | "ia32" 174 | ], 175 | "dev": true, 176 | "optional": true, 177 | "os": [ 178 | "linux" 179 | ], 180 | "engines": { 181 | "node": ">=12" 182 | } 183 | }, 184 | "node_modules/@esbuild/linux-loong64": { 185 | "version": "0.18.20", 186 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", 187 | "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", 188 | "cpu": [ 189 | "loong64" 190 | ], 191 | "dev": true, 192 | "optional": true, 193 | "os": [ 194 | "linux" 195 | ], 196 | "engines": { 197 | "node": ">=12" 198 | } 199 | }, 200 | "node_modules/@esbuild/linux-mips64el": { 201 | "version": "0.18.20", 202 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", 203 | "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", 204 | "cpu": [ 205 | "mips64el" 206 | ], 207 | "dev": true, 208 | "optional": true, 209 | "os": [ 210 | "linux" 211 | ], 212 | "engines": { 213 | "node": ">=12" 214 | } 215 | }, 216 | "node_modules/@esbuild/linux-ppc64": { 217 | "version": "0.18.20", 218 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", 219 | "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", 220 | "cpu": [ 221 | "ppc64" 222 | ], 223 | "dev": true, 224 | "optional": true, 225 | "os": [ 226 | "linux" 227 | ], 228 | "engines": { 229 | "node": ">=12" 230 | } 231 | }, 232 | "node_modules/@esbuild/linux-riscv64": { 233 | "version": "0.18.20", 234 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", 235 | "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", 236 | "cpu": [ 237 | "riscv64" 238 | ], 239 | "dev": true, 240 | "optional": true, 241 | "os": [ 242 | "linux" 243 | ], 244 | "engines": { 245 | "node": ">=12" 246 | } 247 | }, 248 | "node_modules/@esbuild/linux-s390x": { 249 | "version": "0.18.20", 250 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", 251 | "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", 252 | "cpu": [ 253 | "s390x" 254 | ], 255 | "dev": true, 256 | "optional": true, 257 | "os": [ 258 | "linux" 259 | ], 260 | "engines": { 261 | "node": ">=12" 262 | } 263 | }, 264 | "node_modules/@esbuild/linux-x64": { 265 | "version": "0.18.20", 266 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", 267 | "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", 268 | "cpu": [ 269 | "x64" 270 | ], 271 | "dev": true, 272 | "optional": true, 273 | "os": [ 274 | "linux" 275 | ], 276 | "engines": { 277 | "node": ">=12" 278 | } 279 | }, 280 | "node_modules/@esbuild/netbsd-x64": { 281 | "version": "0.18.20", 282 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", 283 | "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", 284 | "cpu": [ 285 | "x64" 286 | ], 287 | "dev": true, 288 | "optional": true, 289 | "os": [ 290 | "netbsd" 291 | ], 292 | "engines": { 293 | "node": ">=12" 294 | } 295 | }, 296 | "node_modules/@esbuild/openbsd-x64": { 297 | "version": "0.18.20", 298 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", 299 | "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", 300 | "cpu": [ 301 | "x64" 302 | ], 303 | "dev": true, 304 | "optional": true, 305 | "os": [ 306 | "openbsd" 307 | ], 308 | "engines": { 309 | "node": ">=12" 310 | } 311 | }, 312 | "node_modules/@esbuild/sunos-x64": { 313 | "version": "0.18.20", 314 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", 315 | "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", 316 | "cpu": [ 317 | "x64" 318 | ], 319 | "dev": true, 320 | "optional": true, 321 | "os": [ 322 | "sunos" 323 | ], 324 | "engines": { 325 | "node": ">=12" 326 | } 327 | }, 328 | "node_modules/@esbuild/win32-arm64": { 329 | "version": "0.18.20", 330 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", 331 | "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", 332 | "cpu": [ 333 | "arm64" 334 | ], 335 | "dev": true, 336 | "optional": true, 337 | "os": [ 338 | "win32" 339 | ], 340 | "engines": { 341 | "node": ">=12" 342 | } 343 | }, 344 | "node_modules/@esbuild/win32-ia32": { 345 | "version": "0.18.20", 346 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", 347 | "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", 348 | "cpu": [ 349 | "ia32" 350 | ], 351 | "dev": true, 352 | "optional": true, 353 | "os": [ 354 | "win32" 355 | ], 356 | "engines": { 357 | "node": ">=12" 358 | } 359 | }, 360 | "node_modules/@esbuild/win32-x64": { 361 | "version": "0.18.20", 362 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", 363 | "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", 364 | "cpu": [ 365 | "x64" 366 | ], 367 | "dev": true, 368 | "optional": true, 369 | "os": [ 370 | "win32" 371 | ], 372 | "engines": { 373 | "node": ">=12" 374 | } 375 | }, 376 | "node_modules/@hono/node-server": { 377 | "version": "1.11.1", 378 | "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.11.1.tgz", 379 | "integrity": "sha512-GW1Iomhmm1o4Z+X57xGby8A35Cu9UZLL7pSMdqDBkD99U5cywff8F+8hLk5aBTzNubnsFAvWQ/fZjNwPsEn9lA==", 380 | "engines": { 381 | "node": ">=18.14.1" 382 | } 383 | }, 384 | "node_modules/buffer-from": { 385 | "version": "1.1.2", 386 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 387 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 388 | "dev": true 389 | }, 390 | "node_modules/esbuild": { 391 | "version": "0.18.20", 392 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", 393 | "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", 394 | "dev": true, 395 | "hasInstallScript": true, 396 | "bin": { 397 | "esbuild": "bin/esbuild" 398 | }, 399 | "engines": { 400 | "node": ">=12" 401 | }, 402 | "optionalDependencies": { 403 | "@esbuild/android-arm": "0.18.20", 404 | "@esbuild/android-arm64": "0.18.20", 405 | "@esbuild/android-x64": "0.18.20", 406 | "@esbuild/darwin-arm64": "0.18.20", 407 | "@esbuild/darwin-x64": "0.18.20", 408 | "@esbuild/freebsd-arm64": "0.18.20", 409 | "@esbuild/freebsd-x64": "0.18.20", 410 | "@esbuild/linux-arm": "0.18.20", 411 | "@esbuild/linux-arm64": "0.18.20", 412 | "@esbuild/linux-ia32": "0.18.20", 413 | "@esbuild/linux-loong64": "0.18.20", 414 | "@esbuild/linux-mips64el": "0.18.20", 415 | "@esbuild/linux-ppc64": "0.18.20", 416 | "@esbuild/linux-riscv64": "0.18.20", 417 | "@esbuild/linux-s390x": "0.18.20", 418 | "@esbuild/linux-x64": "0.18.20", 419 | "@esbuild/netbsd-x64": "0.18.20", 420 | "@esbuild/openbsd-x64": "0.18.20", 421 | "@esbuild/sunos-x64": "0.18.20", 422 | "@esbuild/win32-arm64": "0.18.20", 423 | "@esbuild/win32-ia32": "0.18.20", 424 | "@esbuild/win32-x64": "0.18.20" 425 | } 426 | }, 427 | "node_modules/fsevents": { 428 | "version": "2.3.3", 429 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 430 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 431 | "dev": true, 432 | "hasInstallScript": true, 433 | "optional": true, 434 | "os": [ 435 | "darwin" 436 | ], 437 | "engines": { 438 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 439 | } 440 | }, 441 | "node_modules/get-tsconfig": { 442 | "version": "4.7.5", 443 | "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", 444 | "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", 445 | "dev": true, 446 | "dependencies": { 447 | "resolve-pkg-maps": "^1.0.0" 448 | }, 449 | "funding": { 450 | "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" 451 | } 452 | }, 453 | "node_modules/hono": { 454 | "version": "4.3.4", 455 | "resolved": "https://registry.npmjs.org/hono/-/hono-4.3.4.tgz", 456 | "integrity": "sha512-oh+PBwW8yElj3bUlY2dTXhuPt1MCZp6Nb04tejLwY+GXdphQH6uCpUP0dY5iLvFY5wM8fNHrMx1QeMKbhnzw9w==", 457 | "engines": { 458 | "node": ">=16.0.0" 459 | } 460 | }, 461 | "node_modules/hono-sessions": { 462 | "resolved": "../../npm", 463 | "link": true 464 | }, 465 | "node_modules/resolve-pkg-maps": { 466 | "version": "1.0.0", 467 | "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", 468 | "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", 469 | "dev": true, 470 | "funding": { 471 | "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" 472 | } 473 | }, 474 | "node_modules/source-map": { 475 | "version": "0.6.1", 476 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 477 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 478 | "dev": true, 479 | "engines": { 480 | "node": ">=0.10.0" 481 | } 482 | }, 483 | "node_modules/source-map-support": { 484 | "version": "0.5.21", 485 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 486 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 487 | "dev": true, 488 | "dependencies": { 489 | "buffer-from": "^1.0.0", 490 | "source-map": "^0.6.0" 491 | } 492 | }, 493 | "node_modules/tsx": { 494 | "version": "3.14.0", 495 | "resolved": "https://registry.npmjs.org/tsx/-/tsx-3.14.0.tgz", 496 | "integrity": "sha512-xHtFaKtHxM9LOklMmJdI3BEnQq/D5F73Of2E1GDrITi9sgoVkvIsrQUTY1G8FlmGtA+awCI4EBlTRRYxkL2sRg==", 497 | "dev": true, 498 | "dependencies": { 499 | "esbuild": "~0.18.20", 500 | "get-tsconfig": "^4.7.2", 501 | "source-map-support": "^0.5.21" 502 | }, 503 | "bin": { 504 | "tsx": "dist/cli.mjs" 505 | }, 506 | "optionalDependencies": { 507 | "fsevents": "~2.3.3" 508 | } 509 | } 510 | } 511 | } 512 | -------------------------------------------------------------------------------- /test/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "test_cookie": "tsx watch src/test_cookie.ts" 4 | }, 5 | "dependencies": { 6 | "@hono/node-server": "^1.7.0", 7 | "hono": "^4.0.0", 8 | "hono-sessions": "../../npm" 9 | }, 10 | "devDependencies": { 11 | "tsx": "^3.12.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/node/src/test_cookie.ts: -------------------------------------------------------------------------------- 1 | import { serve } from '@hono/node-server' 2 | import { Hono } from 'hono' 3 | import { html } from "hono/html"; 4 | import { sessionMiddleware, CookieStore, Session } from "hono-sessions"; 5 | 6 | const app = new Hono() 7 | 8 | const store = new CookieStore() 9 | 10 | const session_routes = new Hono<{ 11 | Variables: { 12 | session: Session, 13 | session_key_rotation: boolean 14 | } 15 | }>() 16 | 17 | session_routes.use('*', sessionMiddleware({ 18 | store, 19 | expireAfterSeconds: 30, 20 | cookieOptions: { 21 | sameSite: 'Lax', 22 | path: '/', 23 | httpOnly: true, 24 | }, 25 | encryptionKey: 'string_at_least_32_characters_long' 26 | })) 27 | 28 | session_routes.post('/login', async (c) => { 29 | const session = c.get('session') 30 | 31 | const { email, password } = await c.req.parseBody() 32 | 33 | if (password === 'correct') { 34 | c.set('session_key_rotation', true) 35 | session.set('email', email) 36 | session.forget('failed-login-attempts') 37 | session.flash('message', 'Login Successful') 38 | } else { 39 | const failedLoginAttempts = (session.get('failed-login-attempts') || 0) as number 40 | session.set('failed-login-attempts', failedLoginAttempts + 1) 41 | session.flash('error', 'Incorrect username or password') 42 | } 43 | 44 | return c.redirect('/') 45 | }) 46 | 47 | session_routes.post('/logout', (c) => { 48 | c.get('session').deleteSession() 49 | return c.redirect('/') 50 | }) 51 | 52 | session_routes.get('/', (c) => { 53 | const session = c.get('session') 54 | 55 | const message = session.get('message') || '' 56 | const error = session.get('error') || '' 57 | const failedLoginAttempts = session.get('failed-login-attempts') 58 | const email = session.get('email') 59 | 60 | return c.html(html` 61 | 62 | 63 | 64 | 65 | 66 | Hono Sessions 67 | 68 | 69 | ${ message && html`

${message}

` } 70 | ${ error && html`

${error}

` } 71 | ${ failedLoginAttempts && html`

Failed login attempts: ${ failedLoginAttempts }

` } 72 | 73 | ${email ? 74 | html`
75 | 76 |
` 77 | : 78 | html`
79 |

80 | 81 |

82 |

83 | 84 |

85 | 86 |
` 87 | } 88 | 89 | `) 90 | }) 91 | 92 | app.route('/', session_routes) 93 | 94 | const port = 3000 95 | console.log(`Server is running on port ${port}`) 96 | 97 | serve({ 98 | fetch: app.fetch, 99 | port 100 | }) 101 | -------------------------------------------------------------------------------- /test/node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "hono/jsx", 6 | } 7 | } --------------------------------------------------------------------------------