├── .eslintignore
├── .eslintrc.cjs
├── .github
└── workflows
│ └── publish.yml
├── .gitignore
├── .jshintrc
├── .npmrc
├── .prettierignore
├── .prettierrc
├── LICENSE.txt
├── README.md
├── docs
├── .gitignore
├── README.md
├── astro.config.mjs
├── package.json
├── pnpm-lock.yaml
├── public
│ └── favicon.svg
├── src
│ ├── assets
│ │ ├── ethercorps.png
│ │ ├── ethercorps_transparent.png
│ │ ├── houston.webp
│ │ └── logo.svg
│ ├── content
│ │ ├── config.ts
│ │ └── docs
│ │ │ ├── guides
│ │ │ └── example.md
│ │ │ ├── index.mdx
│ │ │ └── reference
│ │ │ └── example.md
│ ├── env.d.ts
│ └── tailwind.css
├── tailwind.config.cjs
└── tsconfig.json
├── examples
├── ioredis
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── playwright.config.ts
│ ├── pnpm-lock.yaml
│ ├── src
│ │ ├── app.css
│ │ ├── app.d.ts
│ │ ├── app.html
│ │ ├── hooks.server.ts
│ │ ├── lib
│ │ │ └── session.ts
│ │ └── routes
│ │ │ ├── +layout.svelte
│ │ │ ├── +page.server.ts
│ │ │ ├── +page.svelte
│ │ │ └── api
│ │ │ ├── login
│ │ │ └── +server.ts
│ │ │ ├── logout
│ │ │ └── +server.ts
│ │ │ └── updateCookieData
│ │ │ └── +server.ts
│ ├── static
│ │ ├── favicon.png
│ │ └── logo.svg
│ ├── svelte.config.js
│ ├── tests
│ │ └── test.ts
│ ├── tsconfig.json
│ └── vite.config.ts
├── node
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── playwright.config.ts
│ ├── pnpm-lock.yaml
│ ├── src
│ │ ├── app.css
│ │ ├── app.d.ts
│ │ ├── app.html
│ │ ├── hooks.server.ts
│ │ ├── lib
│ │ │ └── session.ts
│ │ └── routes
│ │ │ ├── +layout.svelte
│ │ │ ├── +page.server.ts
│ │ │ ├── +page.svelte
│ │ │ └── api
│ │ │ ├── login
│ │ │ └── +server.ts
│ │ │ ├── logout
│ │ │ └── +server.ts
│ │ │ └── updateCookieData
│ │ │ └── +server.ts
│ ├── static
│ │ ├── favicon.png
│ │ └── logo.svg
│ ├── svelte.config.js
│ ├── tests
│ │ └── test.ts
│ ├── tsconfig.json
│ └── vite.config.ts
└── upstash
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── playwright.config.ts
│ ├── pnpm-lock.yaml
│ ├── src
│ ├── app.css
│ ├── app.d.ts
│ ├── app.html
│ ├── hooks.server.ts
│ ├── lib
│ │ └── session.ts
│ └── routes
│ │ ├── +layout.svelte
│ │ ├── +page.server.ts
│ │ ├── +page.svelte
│ │ └── api
│ │ ├── login
│ │ └── +server.ts
│ │ ├── logout
│ │ └── +server.ts
│ │ └── updateCookieData
│ │ └── +server.ts
│ ├── static
│ ├── favicon.png
│ └── logo.svg
│ ├── svelte.config.js
│ ├── tests
│ └── test.ts
│ ├── tsconfig.json
│ └── vite.config.ts
├── package.json
├── pnpm-lock.yaml
├── src
├── app.d.ts
├── app.html
├── index.test.ts
├── lib
│ ├── index.ts
│ ├── providers
│ │ ├── ioredis.ts
│ │ ├── redis.ts
│ │ └── upstash.ts
│ └── shared.ts
└── routes
│ ├── +page.server.ts
│ └── +page.svelte
├── static
├── favicon.png
└── logo.svg
├── svelte.config.js
├── tsconfig.json
└── vite.config.ts
/.eslintignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 |
10 | # Ignore files for PNPM, NPM and YARN
11 | pnpm-lock.yaml
12 | package-lock.json
13 | yarn.lock
14 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: [
4 | 'eslint:recommended',
5 | 'plugin:@typescript-eslint/recommended',
6 | 'plugin:svelte/recommended',
7 | 'prettier'
8 | ],
9 | parser: '@typescript-eslint/parser',
10 | plugins: ['@typescript-eslint'],
11 | parserOptions: {
12 | sourceType: 'module',
13 | ecmaVersion: 2020,
14 | extraFileExtensions: ['.svelte']
15 | },
16 | env: {
17 | browser: true,
18 | es2017: true,
19 | node: true
20 | },
21 | overrides: [
22 | {
23 | files: ['*.svelte'],
24 | parser: 'svelte-eslint-parser',
25 | parserOptions: {
26 | parser: '@typescript-eslint/parser'
27 | }
28 | }
29 | ]
30 | };
31 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches: master
4 |
5 | jobs:
6 | publish:
7 | runs-on: ubuntu-latest
8 | env:
9 | CI: true
10 | steps:
11 | - uses: actions/checkout@v3
12 | - uses: actions/setup-node@v3
13 | with:
14 | node-version: 20
15 | - uses: pnpm/action-setup@v2
16 | name: Install pnpm
17 | id: pnpm-install
18 | with:
19 | version: 8.6.1
20 | - run: pnpm install
21 | - run: pnpm package
22 | - uses: JS-DevTools/npm-publish@v2
23 | with:
24 | token: ${{ secrets.NPM_TOKEN }}
25 | ignore-scripts: true
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /dist
5 | /.svelte-kit
6 | /package
7 | .env
8 | .env.*
9 | !.env.example
10 | vite.config.js.timestamp-*
11 | vite.config.ts.timestamp-*
12 | .idea
13 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esversion": 6
3 | }
4 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 | resolution-mode=highest
3 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 |
10 | # Ignore files for PNPM, NPM and YARN
11 | pnpm-lock.yaml
12 | package-lock.json
13 | yarn.lock
14 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": true,
3 | "singleQuote": true,
4 | "trailingComma": "none",
5 | "printWidth": 100,
6 | "plugins": ["prettier-plugin-svelte"],
7 | "pluginSearchDirs": ["."],
8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
9 | }
10 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Ether Corps
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | [![Contributors][contributors-shield]][contributors-url]
3 | [![Forks][forks-shield]][forks-url]
4 | [![Stargazers][stars-shield]][stars-url]
5 | [![Issues][issues-shield]][issues-url]
6 | [![MIT License][license-shield]][license-url]
7 | [![LinkedIn][linkedin-shield]][linkedin-url]
8 |
9 |
10 |
11 |
33 |
34 |
35 | Table of Contents
36 |
37 |
38 | About The Project
39 |
43 |
44 |
45 | Getting Started
46 |
50 |
51 | Usage
52 | Roadmap
53 | License
54 | Contact
55 | Acknowledgments
56 |
57 |
58 |
59 |
60 |
61 | ## About The Project
62 |
63 | [//]: # '[![Product Name Screen Shot][product-screenshot]](https://github.com/etherCorps/SK-Redis-SessionManager)'
64 |
65 | "SvelteKit-Redis-Session" stands out as an indispensable tool for developers aiming to seamlessly integrate Redis as a session manager within their SvelteKit applications. Designed with a keen attention to detail, this package ensures that managing user sessions is not only efficient but also intuitive.
66 |
67 | (back to top )
68 |
69 | ## Key Features
70 |
71 | - `Simplicity at its Core`: With intuitive functions, developers can effortlessly store and retrieve data without wading through complexities.
72 | - `Enhanced Security`: Understanding the need for robust data protection, the package offers signature & encryption for session data.
73 | - `Intelligent Session Management`: The package intelligently handles session expiration, reducing the manual oversight typically needed.
74 | - `Bespoke Customization`: Recognizing that one size doesn't fit all, "SvelteKit-Redis-Session" offers high customizability, allowing developers to tailor its functionalities to their distinct needs, and in turn, enhancing application performance.
75 | - `For all runtimes`: As of now we have so many runtimes cloudflare workers, vercel, netlify.
76 | - `Support for multiple redis libraries`: We support `redis` & `ioredis` out of the box.
77 | - `Support for @upstash/redis`: It's mandatory if you are working with workers, edge and serverless. Cloudflare workers doesn't support TCP.
78 |
79 | ### Built With
80 |
81 | - [![SvelteKit][SvelteKit]][SvelteKit-url]
82 | - [![Redis][Redis]][Redis-url]
83 | - [![Svelte][Svelte.dev]][Svelte-url]
84 |
85 | (back to top )
86 |
87 |
88 |
89 | ## Getting Started
90 |
91 | This is an example of how you may give instructions on setting up your project locally.
92 | To get a local copy up and running follow these simple example steps.
93 |
94 | ### Prerequisites
95 |
96 | This is an example of how to list things you need to use the software and how to install them.
97 |
98 | - Install the `@ethercorps/sveltekit-redis-session`
99 | ```sh
100 | pnpm i @ethercorps/sveltekit-redis-session
101 | ```
102 | - Choose which redis library you are using:
103 | - `redis`: Official redis nodeJs implementation
104 | ```sh
105 | pnpm i redis
106 | ```
107 | - `ioredis`: A robust, performance-focused and full-featured Redis client for Node.js.
108 | ```sh
109 | pnpm i ioredis
110 | ```
111 | - `@upstash/redis`: is an HTTP/REST based Redis client built on top of Upstash REST API.
112 | ```sh
113 | pnpm i @upstash/redis
114 | ```
115 |
116 | ### Setup
117 |
118 | [//]: # 'Guide to how'
119 | [//]: # 'to use @ethercorps/SvelteKit-redis-session '
120 |
121 | 1. First, we need to make instance of it to use everywhere in the project.
122 | ```ts
123 | import { IoRedisSessionStore } from '@ethercorps/SvelteKit-redis-session';
124 | import Redis from 'ioredis';
125 | export const sessionManager = new IoRedisSessionStore({
126 | redisClient: new Redis(), // Required A pre-initiated redis client
127 | secret: 'your-secret-key', // Required A secret key for encryption and other things,
128 | cookieName: 'session', // CookieName to be saved in cookies for browser Default session
129 | prefix: 'sk-session', // Prefix for Redis Keys Default sk-session
130 | signed: true, // Do you want to sign your cookies Default true
131 | encrypted: false, // Do you want to encrypt your cookies using 'aes-256-cbc' algorithm Default false
132 | useTTL: true, // Do you wanna use redis's Expire key functionality Default false
133 | renewSessionBeforeExpire: false, // Do you wanna update session expire time in built function Default false
134 | renewBeforeSeconds: 30 * 60, // If renewSessionBeforeExpire is true define your renew before time in seconds Default 30 minutes
135 | serializer: JSON, // You can define your own serializer functions to stringify and parse sessionData for redis Default JSON
136 | cookiesOptions: {
137 | path: '/',
138 | httpOnly: true,
139 | sameSite: 'strict',
140 | secure: !dev, // From SvelteKit "$app/environment"
141 | maxAge: 60 * 60 * 24 // You have to define time in seconds and it's also used for redis key expiry time
142 | } // You have more options these are default used in package for more check sveltekit CookieSerializeOptions type.
143 | });
144 | ```
145 | > These are the default config example you can use as per your need and make it better for your use.
146 | > I have written an article to explain more about this package link for article .
147 | 2. To create a new session and add cookies for user after authentication
148 |
149 | ```ts
150 | // Example it's a +page.server.ts
151 | import sessionManager from 'sessionManagerFile';
152 |
153 | export const actions: Actions = {
154 | login: async ({ req, cookies, locals }) => {
155 | const formdata = await request.formData();
156 | // Form validation && user validation
157 | const { data, error, message } = sessionManager.createSession(cookies, userData, userId);
158 | // data is the value we added to cookies, check for error which is a boolean and message.
159 | /* add data to locals too for accessing data from client */
160 | throw redirect(307, '/dashboard');
161 | }
162 | };
163 | ```
164 |
165 | 3. To get session data for the cookie
166 |
167 | ```ts
168 | /* hooks.server.ts */
169 | import sessionManager from 'sessionManagerFile';
170 |
171 | export const handle: Handle = async ({ event, resolve }) => {
172 | /* your validation logic */
173 | const { data, error, message } = sessionManager.getSession(event.cookies);
174 | // data is the User session data we saved to redis while login, check for error which is a boolean and message.
175 | /* do error check and then set data to locals as per your logic */
176 | };
177 | ```
178 |
179 | 4. To update session expiry in redis and cookies
180 |
181 | ```ts
182 | // in any server side file or endpoint where you can access browser cookies
183 | import sessionManager from 'sessionManagerFile';
184 | const { data, error, message } = await sessionManager.updateSessionExpiry(cookies);
185 | // data is going to be null or key which is updated, error is a boolean value and message a string
186 | ```
187 |
188 | 5. To update session data in redis and cookies
189 |
190 | ```ts
191 | // in any server side file or endpoint where you can access browser cookies
192 | import sessionManager from 'sessionManagerFile';
193 | const { data, error, message } = await sessionManager.updateSession(cookies, newSessionData);
194 | // data is going to be null or key which is updated, error is a boolean value and message a string
195 | ```
196 |
197 | 6. To delete session from redis and cookie from browser
198 |
199 | ```ts
200 | // Example it's a +page.server.ts
201 |
202 | import sessionManager from 'sessionManagerFile';
203 | export const actions: Actions = {
204 | logout: async ({ cookies, locals }) => {
205 | const { data, error, message } = await sessionManager.deleteSession(cookies);
206 | // data is the value we deleted key, check for error which is a boolean and message.
207 | /* clear your locals too */
208 | throw redirect(307, '/login');
209 | }
210 | };
211 | ```
212 |
213 | 7. To get all sessions of a user from redis and cookie from browser
214 |
215 | ```ts
216 | // Example it's a +server.ts
217 |
218 | import sessionManager from 'sessionManagerFile';
219 |
220 | export const GET: RequestHandler = async ({ cookies, locals }) => {
221 | const { data, error, message } = await sessionManager.getSessionsByUserId(userId);
222 | // data is the session data array, check for error which is a boolean and message.
223 | /* clear your locals too */
224 | return json({data})
225 | }
226 | };
227 | ```
228 |
229 | (back to top )
230 |
231 |
232 |
233 | ## Usage
234 |
235 | Examples are going to be added soon.
236 |
237 | _For more examples, please refer to the [Examples](https://github.com/etherCorps/SK-Redis-SessionManager/tree/master/examples)_
238 |
239 | (back to top )
240 |
241 |
242 |
243 | ## Roadmap
244 |
245 | See the [open issues](https://github.com/etherCorps/SK-Redis-SessionManager/issues) for a full list of proposed
246 | features (and known issues).
247 |
248 | (back to top )
249 |
250 |
251 |
252 | [//]: # '## Contributing'
253 | [//]: #
254 | [//]: # 'Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any'
255 | [//]: # 'contributions you make are **greatly appreciated**.'
256 | [//]: #
257 | [//]: # 'If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also'
258 | [//]: # 'simply open an issue with the tag "enhancement".'
259 | [//]: # "Don't forget to give the project a star! Thanks again!"
260 | [//]: #
261 | [//]: # '1. Fork the Project'
262 | [//]: # '2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)'
263 | [//]: # "3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)"
264 | [//]: # '4. Push to the Branch (`git push origin feature/AmazingFeature`)'
265 | [//]: # '5. Open a Pull Request'
266 | [//]: #
267 | [//]: # '(back to top )
'
268 |
269 |
270 |
271 | ## License
272 |
273 | Distributed under the MIT License. See `LICENSE.txt` for more information.
274 |
275 | (back to top )
276 |
277 |
278 |
279 | ## Contact
280 |
281 | Your Name - [@theether0](https://twitter.com/theether0) - meenashivam9650@gmail.com
282 |
283 | Project
284 | Link: [https://github.com/etherCorps/SK-Redis-SessionManager](https://github.com/etherCorps/SK-Redis-SessionManager)
285 |
286 | (back to top )
287 |
288 |
289 |
290 | ## Acknowledgments
291 |
292 | - [logos-by-larkef from landingfolio](https://www.landingfolio.com/logos-by-larkef) :: For logo
293 | - [connect-redis by TJ Holowaychuk](https://github.com/tj/connect-redis/tree/master) :: Creator of connect redis for express session.
294 | - []()
295 |
296 | (back to top )
297 |
298 |
299 |
300 |
301 | [contributors-shield]: https://img.shields.io/github/contributors/etherCorps/SK-Redis-SessionManager.svg?style=for-the-badge
302 | [contributors-url]: https://github.com/etherCorps/SK-Redis-SessionManager/graphs/contributors
303 | [forks-shield]: https://img.shields.io/github/forks/etherCorps/SK-Redis-SessionManager.svg?style=for-the-badge
304 | [forks-url]: https://github.com/etherCorps/SK-Redis-SessionManager/network/members
305 | [stars-shield]: https://img.shields.io/github/stars/etherCorps/SK-Redis-SessionManager.svg?style=for-the-badge
306 | [stars-url]: https://github.com/etherCorps/SK-Redis-SessionManager/stargazers
307 | [issues-shield]: https://img.shields.io/github/issues/etherCorps/SK-Redis-SessionManager.svg?style=for-the-badge
308 | [issues-url]: https://github.com/etherCorps/SK-Redis-SessionManager/issues
309 | [license-shield]: https://img.shields.io/github/license/etherCorps/SK-Redis-SessionManager.svg?style=for-the-badge
310 | [license-url]: https://github.com/etherCorps/SK-Redis-SessionManager/blob/master/LICENSE.txt
311 | [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
312 | [linkedin-url]: https://linkedin.com/in/theether0
313 | [product-screenshot]: static/screenshot.png
314 | [SvelteKit]: https://img.shields.io/badge/sveltekit-000000?style=for-the-badge&logo=svelte&logoColor=white
315 | [SvelteKit-url]: https://kit.svelte.dev
316 | [Redis]: https://img.shields.io/badge/Redis-DD0031?style=for-the-badge&logo=Redis&logoColor=white
317 | [Redis-url]: https://redis.io/
318 | [Svelte.dev]: https://img.shields.io/badge/Svelte-4A4A55?style=for-the-badge&logo=svelte&logoColor=FF3E00
319 | [Svelte-url]: https://svelte.dev/
320 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 | # generated types
4 | .astro/
5 |
6 | # dependencies
7 | node_modules/
8 |
9 | # logs
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 | .vscode
23 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Starlight Starter Kit: Tailwind
2 |
3 | ```
4 | npm create astro@latest -- --template starlight/tailwind
5 | ```
6 |
7 | [](https://stackblitz.com/github/withastro/starlight/tree/main/examples/tailwind)
8 | [](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/tailwind)
9 |
10 | > 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
11 |
12 | ## 🚀 Project Structure
13 |
14 | Inside of your Astro + Starlight project, you'll see the following folders and files:
15 |
16 | ```
17 | .
18 | ├── public/
19 | ├── src/
20 | │ ├── assets/
21 | │ ├── content/
22 | │ │ ├── docs/
23 | │ │ └── config.ts
24 | │ └── env.d.ts
25 | ├── astro.config.mjs
26 | ├── package.json
27 | ├── tailwind.config.cjs
28 | └── tsconfig.json
29 | ```
30 |
31 | Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.
32 |
33 | Images can be added to `src/assets/` and embedded in Markdown with a relative link.
34 |
35 | Static assets, like favicons, can be placed in the `public/` directory.
36 |
37 | ## 🧞 Commands
38 |
39 | All commands are run from the root of the project, from a terminal:
40 |
41 | | Command | Action |
42 | | :------------------------ | :----------------------------------------------- |
43 | | `npm install` | Installs dependencies |
44 | | `npm run dev` | Starts local dev server at `localhost:3000` |
45 | | `npm run build` | Build your production site to `./dist/` |
46 | | `npm run preview` | Preview your build locally, before deploying |
47 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
48 | | `npm run astro -- --help` | Get help using the Astro CLI |
49 |
50 | ## 👀 Want to learn more?
51 |
52 | Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
53 |
--------------------------------------------------------------------------------
/docs/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'astro/config';
2 | import starlight from '@astrojs/starlight';
3 | import tailwind from '@astrojs/tailwind';
4 |
5 | // https://astro.build/config
6 | export default defineConfig({
7 | integrations: [
8 | starlight({
9 | title: 'SK Redis Session',
10 | logo: {
11 | src: './src/assets/logo.svg'
12 | },
13 | social: {
14 | github: 'https://github.com/etherCorps/SK-Redis-SessionManager',
15 | discord: 'https://discord.gg/y8yN33wQ'
16 | },
17 | sidebar: [
18 | {
19 | label: 'Guides',
20 | items: [
21 | // Each item here is one entry in the navigation menu.
22 | { label: 'Example Guide', link: '/guides/example/' }
23 | ]
24 | },
25 | {
26 | label: 'Reference',
27 | autogenerate: { directory: 'reference' }
28 | }
29 | ],
30 | customCss: ['./src/tailwind.css']
31 | }),
32 | tailwind({ applyBaseStyles: false })
33 | ],
34 | // Process images with sharp: https://docs.astro.build/en/guides/assets/#using-sharp
35 | image: {
36 | service: {
37 | entrypoint: 'astro/assets/services/sharp'
38 | }
39 | }
40 | });
41 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "preview": "astro preview",
10 | "astro": "astro"
11 | },
12 | "dependencies": {
13 | "@astrojs/starlight": "^0.8.0",
14 | "@astrojs/starlight-tailwind": "^1.0.2",
15 | "@astrojs/tailwind": "^4.0.0",
16 | "astro": "^2.10.3",
17 | "sharp": "^0.32.3",
18 | "tailwindcss": "^3.3.3"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/docs/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/src/assets/ethercorps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/docs/src/assets/ethercorps.png
--------------------------------------------------------------------------------
/docs/src/assets/ethercorps_transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/docs/src/assets/ethercorps_transparent.png
--------------------------------------------------------------------------------
/docs/src/assets/houston.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/docs/src/assets/houston.webp
--------------------------------------------------------------------------------
/docs/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/docs/src/content/config.ts:
--------------------------------------------------------------------------------
1 | import { defineCollection } from 'astro:content';
2 | import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
3 |
4 | export const collections = {
5 | docs: defineCollection({ schema: docsSchema() }),
6 | i18n: defineCollection({ type: 'data', schema: i18nSchema() })
7 | };
8 |
--------------------------------------------------------------------------------
/docs/src/content/docs/guides/example.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Example Guide
3 | description: A guide in my new Starlight docs site.
4 | ---
5 |
6 | Guides lead a user through a specific task they want to accomplish, often with a sequence of steps.
7 | Writing a good guide requires thinking about what your users are trying to do.
8 |
9 | ## Further reading
10 |
11 | - Read [about how-to guides](https://diataxis.fr/how-to-guides/) in the Diátaxis framework
12 |
--------------------------------------------------------------------------------
/docs/src/content/docs/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Welcome to Sveltekit Redis Session Manager
3 | description: Manage your session in Sveltekit with redis for all runtimes.
4 | template: splash
5 | hero:
6 | title: |
7 | Welcome to Redis Session Manger with
8 |
14 | Sveltekit
15 |
16 | tagline: Sveltekit redis session manager for all runtimes.
17 | image:
18 | alt: 'Sveltekit Redis Session Manger'
19 | html: ' '
20 | actions:
21 | - text: Documentation
22 | link: /guides/example/
23 | icon: right-arrow
24 | variant: primary
25 | - text: Read the Starlight docs
26 | link: https://starlight.astro.build
27 | icon: external
28 | ---
29 |
30 | import { Card, CardGrid } from '@astrojs/starlight/components';
31 |
32 | ## Next steps
33 |
34 |
35 |
36 | Edit `src/content/docs/index.mdx` to see this page change.
37 |
38 |
39 | Add Markdown or MDX files to `src/content/docs` to create new pages.
40 |
41 |
42 | Edit your `sidebar` and other config in `astro.config.mjs`.
43 |
44 |
45 | Learn more in [the Starlight Docs](https://starlight.astro.build/).
46 |
47 |
48 |
--------------------------------------------------------------------------------
/docs/src/content/docs/reference/example.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Example Reference
3 | description: A reference page in my new Starlight docs site.
4 | ---
5 |
6 | Reference pages are ideal for outlining how things work in terse and clear terms.
7 | Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what your documenting.
8 |
9 | ## Further reading
10 |
11 | - Read [about reference](https://diataxis.fr/reference/) in the Diátaxis framework
12 |
--------------------------------------------------------------------------------
/docs/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/docs/src/tailwind.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | /*
6 | Add additional Tailwind styles to this file, for example with @layer:
7 | https://tailwindcss.com/docs/adding-custom-styles#using-css-and-layer
8 | */
9 |
--------------------------------------------------------------------------------
/docs/tailwind.config.cjs:
--------------------------------------------------------------------------------
1 | const colors = require('tailwindcss/colors');
2 | const starlightPlugin = require('@astrojs/starlight-tailwind');
3 |
4 | /** @type {import('tailwindcss').Config} */
5 | module.exports = {
6 | content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
7 | theme: {
8 | extend: {
9 | colors: {
10 | // Your preferred accent color. Indigo is closest to Starlight’s defaults.
11 | accent: colors.amber,
12 | // Your preferred gray scale. Zinc is closest to Starlight’s defaults.
13 | gray: colors.slate
14 | }
15 | }
16 | },
17 | plugins: [starlightPlugin()]
18 | };
19 |
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/base"
3 | }
4 |
--------------------------------------------------------------------------------
/examples/ioredis/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /dist
5 | /.svelte-kit
6 | /package
7 | .env
8 | .env.*
9 | !.env.example
10 | vite.config.js.timestamp-*
11 | vite.config.ts.timestamp-*
12 | .idea
13 |
--------------------------------------------------------------------------------
/examples/ioredis/README.md:
--------------------------------------------------------------------------------
1 | # create-svelte
2 |
3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
4 |
5 | ## Creating a project
6 |
7 | If you're seeing this, you've probably already done this step. Congrats!
8 |
9 | ```bash
10 | # create a new project in the current directory
11 | npm create svelte@latest
12 |
13 | # create a new project in my-app
14 | npm create svelte@latest my-app
15 | ```
16 |
17 | ## Developing
18 |
19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
20 |
21 | ```bash
22 | npm run dev
23 |
24 | # or start the server and open the app in a new browser tab
25 | npm run dev -- --open
26 | ```
27 |
28 | ## Building
29 |
30 | To create a production version of your app:
31 |
32 | ```bash
33 | npm run build
34 | ```
35 |
36 | You can preview the production build with `npm run preview`.
37 |
38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
39 |
--------------------------------------------------------------------------------
/examples/ioredis/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ioredis-vercel",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vite dev --host",
7 | "build": "vite build",
8 | "build:pac": "cd ../.. && pnpm install && pnpm build && cd examples/ioredis && pnpm build",
9 | "preview": "vite preview",
10 | "test": "playwright test",
11 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
13 | "lint": "prettier --plugin-search-dir . --check . && eslint .",
14 | "format": "prettier --plugin-search-dir . --write ."
15 | },
16 | "devDependencies": {
17 | "@playwright/test": "^1.37.1",
18 | "@sveltejs/adapter-vercel": "^2.4.3",
19 | "@sveltejs/kit": "^1.23.0",
20 | "@typescript-eslint/eslint-plugin": "^5.62.0",
21 | "@typescript-eslint/parser": "^5.62.0",
22 | "eslint": "^8.48.0",
23 | "eslint-config-prettier": "^8.10.0",
24 | "eslint-plugin-svelte3": "^4.0.0",
25 | "ioredis": "^5.3.2",
26 | "prettier": "^2.8.8",
27 | "prettier-plugin-svelte": "^2.10.1",
28 | "svelte": "^4.0.0",
29 | "svelte-check": "^3.5.0",
30 | "svelte-french-toast": "^1.2.0",
31 | "tslib": "^2.6.2",
32 | "typescript": "^5.0.0",
33 | "vite": "^4.4.9"
34 | },
35 | "type": "module",
36 | "dependencies": {
37 | "@ethercorps/sveltekit-redis-session": "link:../../"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/ioredis/playwright.config.ts:
--------------------------------------------------------------------------------
1 | import type { PlaywrightTestConfig } from '@playwright/test';
2 |
3 | const config: PlaywrightTestConfig = {
4 | webServer: {
5 | command: 'npm run build && npm run preview',
6 | port: 4173
7 | },
8 | testDir: 'tests'
9 | };
10 |
11 | export default config;
12 |
--------------------------------------------------------------------------------
/examples/ioredis/src/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/examples/ioredis/src/app.css
--------------------------------------------------------------------------------
/examples/ioredis/src/app.d.ts:
--------------------------------------------------------------------------------
1 | // See https://kit.svelte.dev/docs/types#app
2 | // for information about these interfaces
3 | // and what to do when importing types
4 | declare global {
5 | namespace App {
6 | // interface Error {}
7 | interface Locals {
8 | isUserLoggedIn: boolean;
9 | user: {
10 | email: string;
11 | name: string;
12 | } | null;
13 | }
14 | // interface PageData {}
15 | // interface Platform {}
16 | }
17 | }
18 |
19 | export {};
20 |
--------------------------------------------------------------------------------
/examples/ioredis/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %sveltekit.head%
8 |
9 |
10 | %sveltekit.body%
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/ioredis/src/hooks.server.ts:
--------------------------------------------------------------------------------
1 | import type { Handle } from '@sveltejs/kit';
2 | import { sessionManager } from '$lib/session';
3 | import { redirect } from '@sveltejs/kit';
4 |
5 | export const handle: Handle = async ({ event, resolve }) => {
6 | const userSession = await sessionManager.getSession(await event.cookies);
7 |
8 | event.locals = {
9 | isUserLoggedIn: false,
10 | user: null
11 | };
12 | if (userSession.error) {
13 | await sessionManager.deleteCookie(await event.cookies);
14 | return resolve(event);
15 | }
16 | if (userSession && userSession.data) {
17 | event.locals = {
18 | isUserLoggedIn: true,
19 | user: userSession?.data
20 | };
21 | }
22 | return resolve(event);
23 | };
24 |
--------------------------------------------------------------------------------
/examples/ioredis/src/lib/session.ts:
--------------------------------------------------------------------------------
1 | import {
2 | IoRedisSessionStore,
3 | type ioRedisSessionOptions
4 | } from '@ethercorps/sveltekit-redis-session';
5 | import { SECRET, REDIS_URL } from '$env/static/private';
6 | import Redis from 'ioredis';
7 |
8 | const sessionOptions: ioRedisSessionOptions = {
9 | redisClient: new Redis(REDIS_URL),
10 | secret: SECRET,
11 | sessionPrefix: 'vercel-ioredis-srs-example-session',
12 | userSessionsPrefix: 'vercel-ioredis-srs-example-user',
13 | cookieName: 'session',
14 | cookiesOptions: {
15 | maxAge: 10 * 60
16 | }
17 | };
18 | export const sessionManager = new IoRedisSessionStore(sessionOptions);
19 |
--------------------------------------------------------------------------------
/examples/ioredis/src/routes/+layout.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/ioredis/src/routes/+page.server.ts:
--------------------------------------------------------------------------------
1 | import type { Actions } from '@sveltejs/kit';
2 | import { fail } from '@sveltejs/kit';
3 | import { sessionManager } from '$lib/session';
4 | import type { PageServerLoad } from './$types';
5 |
6 | export let ssr = true;
7 | export const load: PageServerLoad = async ({ locals }) => {
8 | return {
9 | user: locals.user,
10 | isAuthenticated: locals.isUserLoggedIn
11 | };
12 | };
13 |
14 | export const actions: Actions = {
15 | default: async ({ request, cookies }) => {
16 | const formData = await request.formData();
17 | if (
18 | formData.get('email') !== 'shivam@example.com' ||
19 | formData.get('password') !== 'Shivam@Meena'
20 | ) {
21 | return fail(400, {
22 | data: Object.fromEntries(formData),
23 | message: 'Check form for errors'
24 | });
25 | }
26 |
27 | const { data, error, message } = await sessionManager.createSession(
28 | cookies,
29 | { email: formData.get('email') },
30 | '1'
31 | );
32 | if (error) {
33 | console.log(message);
34 | return fail(400, {
35 | data: Object.fromEntries(formData),
36 | message
37 | });
38 | }
39 | console.log(data);
40 | return { success: true, message };
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/examples/ioredis/src/routes/+page.svelte:
--------------------------------------------------------------------------------
1 |
52 |
53 |
54 |
55 |
56 | {#if show}
57 |
58 |
59 |
64 |
65 |
66 |
67 |
68 | {#if $page.data.user?.name} {$page.data.user.name} • {/if}
69 | Session is valid for only 10 Mins
70 |
71 |
72 | {#if $page.data.user?.email} {$page.data.user.email} {/if}
73 |
74 |
75 | You are testing for sveltekit redis session manager by ethercorps.
76 |
77 |
78 |
79 |
80 |
83 |
updateCookieData()}
85 | type="button"
86 | class="inline-flex items-center bg-amber-500 px-4 py-2.5 text-center text-sm font-medium text-amber-100 shadow-sm hover:bg-amber-100 hover:text-amber-900 transition easy-in-out duration-500"
87 | >
88 |
96 |
101 |
102 |
103 | Update Cookie Data
104 |
105 |
logoutUser()}
107 | type="button"
108 | class="inline-flex items-center bg-red-500 px-4 py-2.5 text-center text-sm font-medium text-red-100 shadow-sm hover:bg-red-100 hover:text-red-900 transition easy-in-out duration-500"
109 | >
110 |
118 |
123 |
124 | Logout
125 |
126 |
127 |
128 | {:else}
129 |
177 | {/if}
178 |
179 |
180 |
181 |
182 |
190 |
--------------------------------------------------------------------------------
/examples/ioredis/src/routes/api/login/+server.ts:
--------------------------------------------------------------------------------
1 | import { fail, json, redirect, type RequestHandler } from '@sveltejs/kit';
2 | import { sessionManager } from '$lib/session';
3 |
4 | export const POST: RequestHandler = async ({ request, locals, cookies }) => {
5 | if (locals && locals.isUserLoggedIn) {
6 | const { email, password } = await request.json();
7 | if (email !== 'shivam@example.com' || password !== 'Shivam@Meena') {
8 | return fail(400, {
9 | email,
10 | password,
11 | message: 'Invalid credentials'
12 | });
13 | }
14 | const { error, message } = await sessionManager.createSession(
15 | cookies,
16 | {
17 | email
18 | },
19 | '2'
20 | );
21 | if (error) {
22 | return fail(400, {
23 | email,
24 | password,
25 | message
26 | });
27 | }
28 | return json({ success: true, message });
29 | }
30 | throw redirect(302, '/');
31 | };
32 |
--------------------------------------------------------------------------------
/examples/ioredis/src/routes/api/logout/+server.ts:
--------------------------------------------------------------------------------
1 | import { json, redirect } from '@sveltejs/kit';
2 | import type { RequestHandler } from './$types';
3 | import { sessionManager } from '$lib/session';
4 |
5 | export const POST = (async ({ request, locals, cookies }) => {
6 | if (locals && locals.isUserLoggedIn) {
7 | const { email } = await request.json();
8 | const deleteData = await sessionManager.deleteSession(cookies);
9 | if (deleteData.error) await sessionManager.deleteCookie(cookies);
10 | return json({ loggedIn: false, message: 'Successfully logged out' });
11 | }
12 | throw redirect(302, '/');
13 | }) satisfies RequestHandler;
14 |
--------------------------------------------------------------------------------
/examples/ioredis/src/routes/api/updateCookieData/+server.ts:
--------------------------------------------------------------------------------
1 | import type { RequestHandler } from '@sveltejs/kit';
2 | import { fail, json, redirect } from '@sveltejs/kit';
3 | import { sessionManager } from '$lib/session';
4 |
5 | export const POST = (async ({ request, locals, cookies }) => {
6 | if (locals && locals.isUserLoggedIn) {
7 | const additionalData = await request.json();
8 | const newSessionData = { ...locals.user, ...additionalData };
9 | const { data, error, message } = await sessionManager.updateSession(cookies, newSessionData);
10 | if (!error) {
11 | locals.user = newSessionData;
12 | }
13 | return json({
14 | success: !error,
15 | message,
16 | sessionData: await sessionManager.getSession(cookies)
17 | });
18 | }
19 | throw redirect(302, '/');
20 | }) satisfies RequestHandler;
21 |
--------------------------------------------------------------------------------
/examples/ioredis/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/examples/ioredis/static/favicon.png
--------------------------------------------------------------------------------
/examples/ioredis/static/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/ioredis/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from '@sveltejs/adapter-vercel';
2 | import { vitePreprocess } from '@sveltejs/kit/vite';
3 |
4 | /** @type {import('@sveltejs/kit').Config} */
5 | const config = {
6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors
7 | // for more information about preprocessors
8 | preprocess: vitePreprocess(),
9 |
10 | kit: {
11 | adapter: adapter()
12 | }
13 | };
14 |
15 | export default config;
16 |
--------------------------------------------------------------------------------
/examples/ioredis/tests/test.ts:
--------------------------------------------------------------------------------
1 | import { expect, test } from '@playwright/test';
2 |
3 | test('index page has expected h1', async ({ page }) => {
4 | await page.goto('/');
5 | expect(await page.textContent('h1')).toBe('Welcome to SvelteKit');
6 | });
7 |
--------------------------------------------------------------------------------
/examples/ioredis/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "checkJs": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "resolveJsonModule": true,
9 | "skipLibCheck": true,
10 | "sourceMap": true,
11 | "strict": true
12 | }
13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
14 | //
15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
16 | // from the referenced tsconfig.json - TypeScript does not merge them in
17 | }
18 |
--------------------------------------------------------------------------------
/examples/ioredis/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { sveltekit } from '@sveltejs/kit/vite';
2 | import type { UserConfig } from 'vite';
3 |
4 | const config: UserConfig = {
5 | plugins: [sveltekit()]
6 | };
7 |
8 | export default config;
9 |
--------------------------------------------------------------------------------
/examples/node/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /dist
5 | /.svelte-kit
6 | /package
7 | .env
8 | .env.*
9 | !.env.example
10 | vite.config.js.timestamp-*
11 | vite.config.ts.timestamp-*
12 | .idea
13 | .netlify
14 |
--------------------------------------------------------------------------------
/examples/node/README.md:
--------------------------------------------------------------------------------
1 | # create-svelte
2 |
3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
4 |
5 | ## Creating a project
6 |
7 | If you're seeing this, you've probably already done this step. Congrats!
8 |
9 | ```bash
10 | # create a new project in the current directory
11 | npm create svelte@latest
12 |
13 | # create a new project in my-app
14 | npm create svelte@latest my-app
15 | ```
16 |
17 | ## Developing
18 |
19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
20 |
21 | ```bash
22 | npm run dev
23 |
24 | # or start the server and open the app in a new browser tab
25 | npm run dev -- --open
26 | ```
27 |
28 | ## Building
29 |
30 | To create a production version of your app:
31 |
32 | ```bash
33 | npm run build
34 | ```
35 |
36 | You can preview the production build with `npm run preview`.
37 |
38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
39 |
--------------------------------------------------------------------------------
/examples/node/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-netlify",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vite dev --host",
7 | "build": "vite build",
8 | "build:pac": "cd ../.. && pnpm install && pnpm build && cd examples/node && pnpm build",
9 | "preview": "vite preview",
10 | "test": "playwright test",
11 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
13 | "lint": "prettier --plugin-search-dir . --check . && eslint .",
14 | "format": "prettier --plugin-search-dir . --write ."
15 | },
16 | "devDependencies": {
17 | "@playwright/test": "^1.37.1",
18 | "@sveltejs/adapter-netlify": "^2.0.8",
19 | "@sveltejs/kit": "^1.23.0",
20 | "@typescript-eslint/eslint-plugin": "^5.62.0",
21 | "@typescript-eslint/parser": "^5.62.0",
22 | "eslint": "^8.48.0",
23 | "eslint-config-prettier": "^8.10.0",
24 | "eslint-plugin-svelte3": "^4.0.0",
25 | "ioredis": "^5.3.2",
26 | "prettier": "^2.8.8",
27 | "prettier-plugin-svelte": "^2.10.1",
28 | "svelte": "^4.0.0",
29 | "svelte-check": "^3.5.0",
30 | "svelte-french-toast": "^1.2.0",
31 | "tslib": "^2.6.2",
32 | "typescript": "^5.0.0",
33 | "vite": "^4.4.9"
34 | },
35 | "type": "module",
36 | "dependencies": {
37 | "@ethercorps/sveltekit-redis-session": "link:../../",
38 | "redis": "^4.6.10"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/examples/node/playwright.config.ts:
--------------------------------------------------------------------------------
1 | import type { PlaywrightTestConfig } from '@playwright/test';
2 |
3 | const config: PlaywrightTestConfig = {
4 | webServer: {
5 | command: 'npm run build && npm run preview',
6 | port: 4173
7 | },
8 | testDir: 'tests'
9 | };
10 |
11 | export default config;
12 |
--------------------------------------------------------------------------------
/examples/node/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '6.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | dependencies:
8 | '@ethercorps/sveltekit-redis-session':
9 | specifier: link:../../
10 | version: link:../..
11 | redis:
12 | specifier: ^4.6.10
13 | version: 4.6.10
14 |
15 | devDependencies:
16 | '@playwright/test':
17 | specifier: ^1.37.1
18 | version: 1.37.1
19 | '@sveltejs/adapter-netlify':
20 | specifier: ^2.0.8
21 | version: 2.0.8(@sveltejs/kit@1.23.0)
22 | '@sveltejs/kit':
23 | specifier: ^1.23.0
24 | version: 1.23.0(svelte@4.0.0)(vite@4.4.9)
25 | '@typescript-eslint/eslint-plugin':
26 | specifier: ^5.62.0
27 | version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.48.0)(typescript@5.2.2)
28 | '@typescript-eslint/parser':
29 | specifier: ^5.62.0
30 | version: 5.62.0(eslint@8.48.0)(typescript@5.2.2)
31 | eslint:
32 | specifier: ^8.48.0
33 | version: 8.48.0
34 | eslint-config-prettier:
35 | specifier: ^8.10.0
36 | version: 8.10.0(eslint@8.48.0)
37 | eslint-plugin-svelte3:
38 | specifier: ^4.0.0
39 | version: 4.0.0(eslint@8.48.0)(svelte@4.0.0)
40 | ioredis:
41 | specifier: ^5.3.2
42 | version: 5.3.2
43 | prettier:
44 | specifier: ^2.8.8
45 | version: 2.8.8
46 | prettier-plugin-svelte:
47 | specifier: ^2.10.1
48 | version: 2.10.1(prettier@2.8.8)(svelte@4.0.0)
49 | svelte:
50 | specifier: ^4.0.0
51 | version: 4.0.0
52 | svelte-check:
53 | specifier: ^3.5.0
54 | version: 3.5.0(svelte@4.0.0)
55 | svelte-french-toast:
56 | specifier: ^1.2.0
57 | version: 1.2.0(svelte@4.0.0)
58 | tslib:
59 | specifier: ^2.6.2
60 | version: 2.6.2
61 | typescript:
62 | specifier: ^5.0.0
63 | version: 5.2.2
64 | vite:
65 | specifier: ^4.4.9
66 | version: 4.4.9
67 |
68 | packages:
69 |
70 | /@aashutoshrathi/word-wrap@1.2.6:
71 | resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
72 | engines: {node: '>=0.10.0'}
73 | dev: true
74 |
75 | /@ampproject/remapping@2.2.1:
76 | resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
77 | engines: {node: '>=6.0.0'}
78 | dependencies:
79 | '@jridgewell/gen-mapping': 0.3.3
80 | '@jridgewell/trace-mapping': 0.3.19
81 | dev: true
82 |
83 | /@esbuild/android-arm64@0.18.20:
84 | resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
85 | engines: {node: '>=12'}
86 | cpu: [arm64]
87 | os: [android]
88 | requiresBuild: true
89 | dev: true
90 | optional: true
91 |
92 | /@esbuild/android-arm@0.18.20:
93 | resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
94 | engines: {node: '>=12'}
95 | cpu: [arm]
96 | os: [android]
97 | requiresBuild: true
98 | dev: true
99 | optional: true
100 |
101 | /@esbuild/android-x64@0.18.20:
102 | resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
103 | engines: {node: '>=12'}
104 | cpu: [x64]
105 | os: [android]
106 | requiresBuild: true
107 | dev: true
108 | optional: true
109 |
110 | /@esbuild/darwin-arm64@0.18.20:
111 | resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
112 | engines: {node: '>=12'}
113 | cpu: [arm64]
114 | os: [darwin]
115 | requiresBuild: true
116 | dev: true
117 | optional: true
118 |
119 | /@esbuild/darwin-x64@0.18.20:
120 | resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
121 | engines: {node: '>=12'}
122 | cpu: [x64]
123 | os: [darwin]
124 | requiresBuild: true
125 | dev: true
126 | optional: true
127 |
128 | /@esbuild/freebsd-arm64@0.18.20:
129 | resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
130 | engines: {node: '>=12'}
131 | cpu: [arm64]
132 | os: [freebsd]
133 | requiresBuild: true
134 | dev: true
135 | optional: true
136 |
137 | /@esbuild/freebsd-x64@0.18.20:
138 | resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
139 | engines: {node: '>=12'}
140 | cpu: [x64]
141 | os: [freebsd]
142 | requiresBuild: true
143 | dev: true
144 | optional: true
145 |
146 | /@esbuild/linux-arm64@0.18.20:
147 | resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
148 | engines: {node: '>=12'}
149 | cpu: [arm64]
150 | os: [linux]
151 | requiresBuild: true
152 | dev: true
153 | optional: true
154 |
155 | /@esbuild/linux-arm@0.18.20:
156 | resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
157 | engines: {node: '>=12'}
158 | cpu: [arm]
159 | os: [linux]
160 | requiresBuild: true
161 | dev: true
162 | optional: true
163 |
164 | /@esbuild/linux-ia32@0.18.20:
165 | resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
166 | engines: {node: '>=12'}
167 | cpu: [ia32]
168 | os: [linux]
169 | requiresBuild: true
170 | dev: true
171 | optional: true
172 |
173 | /@esbuild/linux-loong64@0.18.20:
174 | resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
175 | engines: {node: '>=12'}
176 | cpu: [loong64]
177 | os: [linux]
178 | requiresBuild: true
179 | dev: true
180 | optional: true
181 |
182 | /@esbuild/linux-mips64el@0.18.20:
183 | resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
184 | engines: {node: '>=12'}
185 | cpu: [mips64el]
186 | os: [linux]
187 | requiresBuild: true
188 | dev: true
189 | optional: true
190 |
191 | /@esbuild/linux-ppc64@0.18.20:
192 | resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
193 | engines: {node: '>=12'}
194 | cpu: [ppc64]
195 | os: [linux]
196 | requiresBuild: true
197 | dev: true
198 | optional: true
199 |
200 | /@esbuild/linux-riscv64@0.18.20:
201 | resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
202 | engines: {node: '>=12'}
203 | cpu: [riscv64]
204 | os: [linux]
205 | requiresBuild: true
206 | dev: true
207 | optional: true
208 |
209 | /@esbuild/linux-s390x@0.18.20:
210 | resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
211 | engines: {node: '>=12'}
212 | cpu: [s390x]
213 | os: [linux]
214 | requiresBuild: true
215 | dev: true
216 | optional: true
217 |
218 | /@esbuild/linux-x64@0.18.20:
219 | resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
220 | engines: {node: '>=12'}
221 | cpu: [x64]
222 | os: [linux]
223 | requiresBuild: true
224 | dev: true
225 | optional: true
226 |
227 | /@esbuild/netbsd-x64@0.18.20:
228 | resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
229 | engines: {node: '>=12'}
230 | cpu: [x64]
231 | os: [netbsd]
232 | requiresBuild: true
233 | dev: true
234 | optional: true
235 |
236 | /@esbuild/openbsd-x64@0.18.20:
237 | resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
238 | engines: {node: '>=12'}
239 | cpu: [x64]
240 | os: [openbsd]
241 | requiresBuild: true
242 | dev: true
243 | optional: true
244 |
245 | /@esbuild/sunos-x64@0.18.20:
246 | resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
247 | engines: {node: '>=12'}
248 | cpu: [x64]
249 | os: [sunos]
250 | requiresBuild: true
251 | dev: true
252 | optional: true
253 |
254 | /@esbuild/win32-arm64@0.18.20:
255 | resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
256 | engines: {node: '>=12'}
257 | cpu: [arm64]
258 | os: [win32]
259 | requiresBuild: true
260 | dev: true
261 | optional: true
262 |
263 | /@esbuild/win32-ia32@0.18.20:
264 | resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
265 | engines: {node: '>=12'}
266 | cpu: [ia32]
267 | os: [win32]
268 | requiresBuild: true
269 | dev: true
270 | optional: true
271 |
272 | /@esbuild/win32-x64@0.18.20:
273 | resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
274 | engines: {node: '>=12'}
275 | cpu: [x64]
276 | os: [win32]
277 | requiresBuild: true
278 | dev: true
279 | optional: true
280 |
281 | /@eslint-community/eslint-utils@4.4.0(eslint@8.48.0):
282 | resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
283 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
284 | peerDependencies:
285 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
286 | dependencies:
287 | eslint: 8.48.0
288 | eslint-visitor-keys: 3.4.3
289 | dev: true
290 |
291 | /@eslint-community/regexpp@4.8.0:
292 | resolution: {integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==}
293 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
294 | dev: true
295 |
296 | /@eslint/eslintrc@2.1.2:
297 | resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==}
298 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
299 | dependencies:
300 | ajv: 6.12.6
301 | debug: 4.3.4
302 | espree: 9.6.1
303 | globals: 13.21.0
304 | ignore: 5.2.4
305 | import-fresh: 3.3.0
306 | js-yaml: 4.1.0
307 | minimatch: 3.1.2
308 | strip-json-comments: 3.1.1
309 | transitivePeerDependencies:
310 | - supports-color
311 | dev: true
312 |
313 | /@eslint/js@8.48.0:
314 | resolution: {integrity: sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==}
315 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
316 | dev: true
317 |
318 | /@humanwhocodes/config-array@0.11.10:
319 | resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==}
320 | engines: {node: '>=10.10.0'}
321 | dependencies:
322 | '@humanwhocodes/object-schema': 1.2.1
323 | debug: 4.3.4
324 | minimatch: 3.1.2
325 | transitivePeerDependencies:
326 | - supports-color
327 | dev: true
328 |
329 | /@humanwhocodes/module-importer@1.0.1:
330 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
331 | engines: {node: '>=12.22'}
332 | dev: true
333 |
334 | /@humanwhocodes/object-schema@1.2.1:
335 | resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
336 | dev: true
337 |
338 | /@iarna/toml@2.2.5:
339 | resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
340 | dev: true
341 |
342 | /@ioredis/commands@1.2.0:
343 | resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
344 | dev: true
345 |
346 | /@jridgewell/gen-mapping@0.3.3:
347 | resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
348 | engines: {node: '>=6.0.0'}
349 | dependencies:
350 | '@jridgewell/set-array': 1.1.2
351 | '@jridgewell/sourcemap-codec': 1.4.15
352 | '@jridgewell/trace-mapping': 0.3.19
353 | dev: true
354 |
355 | /@jridgewell/resolve-uri@3.1.1:
356 | resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==}
357 | engines: {node: '>=6.0.0'}
358 | dev: true
359 |
360 | /@jridgewell/set-array@1.1.2:
361 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
362 | engines: {node: '>=6.0.0'}
363 | dev: true
364 |
365 | /@jridgewell/sourcemap-codec@1.4.15:
366 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
367 | dev: true
368 |
369 | /@jridgewell/trace-mapping@0.3.19:
370 | resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==}
371 | dependencies:
372 | '@jridgewell/resolve-uri': 3.1.1
373 | '@jridgewell/sourcemap-codec': 1.4.15
374 | dev: true
375 |
376 | /@nodelib/fs.scandir@2.1.5:
377 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
378 | engines: {node: '>= 8'}
379 | dependencies:
380 | '@nodelib/fs.stat': 2.0.5
381 | run-parallel: 1.2.0
382 | dev: true
383 |
384 | /@nodelib/fs.stat@2.0.5:
385 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
386 | engines: {node: '>= 8'}
387 | dev: true
388 |
389 | /@nodelib/fs.walk@1.2.8:
390 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
391 | engines: {node: '>= 8'}
392 | dependencies:
393 | '@nodelib/fs.scandir': 2.1.5
394 | fastq: 1.15.0
395 | dev: true
396 |
397 | /@playwright/test@1.37.1:
398 | resolution: {integrity: sha512-bq9zTli3vWJo8S3LwB91U0qDNQDpEXnw7knhxLM0nwDvexQAwx9tO8iKDZSqqneVq+URd/WIoz+BALMqUTgdSg==}
399 | engines: {node: '>=16'}
400 | hasBin: true
401 | dependencies:
402 | '@types/node': 20.5.6
403 | playwright-core: 1.37.1
404 | optionalDependencies:
405 | fsevents: 2.3.2
406 | dev: true
407 |
408 | /@polka/url@1.0.0-next.21:
409 | resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
410 | dev: true
411 |
412 | /@redis/bloom@1.2.0(@redis/client@1.5.11):
413 | resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
414 | peerDependencies:
415 | '@redis/client': ^1.0.0
416 | dependencies:
417 | '@redis/client': 1.5.11
418 | dev: false
419 |
420 | /@redis/client@1.5.11:
421 | resolution: {integrity: sha512-cV7yHcOAtNQ5x/yQl7Yw1xf53kO0FNDTdDU6bFIMbW6ljB7U7ns0YRM+QIkpoqTAt6zK5k9Fq0QWlUbLcq9AvA==}
422 | engines: {node: '>=14'}
423 | dependencies:
424 | cluster-key-slot: 1.1.2
425 | generic-pool: 3.9.0
426 | yallist: 4.0.0
427 | dev: false
428 |
429 | /@redis/graph@1.1.0(@redis/client@1.5.11):
430 | resolution: {integrity: sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==}
431 | peerDependencies:
432 | '@redis/client': ^1.0.0
433 | dependencies:
434 | '@redis/client': 1.5.11
435 | dev: false
436 |
437 | /@redis/json@1.0.6(@redis/client@1.5.11):
438 | resolution: {integrity: sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==}
439 | peerDependencies:
440 | '@redis/client': ^1.0.0
441 | dependencies:
442 | '@redis/client': 1.5.11
443 | dev: false
444 |
445 | /@redis/search@1.1.5(@redis/client@1.5.11):
446 | resolution: {integrity: sha512-hPP8w7GfGsbtYEJdn4n7nXa6xt6hVZnnDktKW4ArMaFQ/m/aR7eFvsLQmG/mn1Upq99btPJk+F27IQ2dYpCoUg==}
447 | peerDependencies:
448 | '@redis/client': ^1.0.0
449 | dependencies:
450 | '@redis/client': 1.5.11
451 | dev: false
452 |
453 | /@redis/time-series@1.0.5(@redis/client@1.5.11):
454 | resolution: {integrity: sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==}
455 | peerDependencies:
456 | '@redis/client': ^1.0.0
457 | dependencies:
458 | '@redis/client': 1.5.11
459 | dev: false
460 |
461 | /@sveltejs/adapter-netlify@2.0.8(@sveltejs/kit@1.23.0):
462 | resolution: {integrity: sha512-kfsoSsZth5CZHEIjr4TL4Cb6NmVul7/XNu5rJ04EbIOjYD1bnA4U7Sk1BmoRVyJae7UtUwG6Gkh01RFQSaIeNQ==}
463 | peerDependencies:
464 | '@sveltejs/kit': ^1.5.0
465 | dependencies:
466 | '@iarna/toml': 2.2.5
467 | '@sveltejs/kit': 1.23.0(svelte@4.0.0)(vite@4.4.9)
468 | esbuild: 0.18.20
469 | set-cookie-parser: 2.6.0
470 | dev: true
471 |
472 | /@sveltejs/kit@1.23.0(svelte@4.0.0)(vite@4.4.9):
473 | resolution: {integrity: sha512-MuDM6afpSMnPFMtEsE1O+Qn6NVPNHDqsDYYZE/8/+Z3IvGmE+GKHC+za6fEmCfwXLqNlxFZiV8s8kKOeNVJP+g==}
474 | engines: {node: ^16.14 || >=18}
475 | hasBin: true
476 | requiresBuild: true
477 | peerDependencies:
478 | svelte: ^3.54.0 || ^4.0.0-next.0
479 | vite: ^4.0.0
480 | dependencies:
481 | '@sveltejs/vite-plugin-svelte': 2.4.5(svelte@4.0.0)(vite@4.4.9)
482 | '@types/cookie': 0.5.1
483 | cookie: 0.5.0
484 | devalue: 4.3.2
485 | esm-env: 1.0.0
486 | kleur: 4.1.5
487 | magic-string: 0.30.3
488 | mime: 3.0.0
489 | sade: 1.8.1
490 | set-cookie-parser: 2.6.0
491 | sirv: 2.0.3
492 | svelte: 4.0.0
493 | undici: 5.23.0
494 | vite: 4.4.9
495 | transitivePeerDependencies:
496 | - supports-color
497 | dev: true
498 |
499 | /@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.4.5)(svelte@4.0.0)(vite@4.4.9):
500 | resolution: {integrity: sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==}
501 | engines: {node: ^14.18.0 || >= 16}
502 | peerDependencies:
503 | '@sveltejs/vite-plugin-svelte': ^2.2.0
504 | svelte: ^3.54.0 || ^4.0.0
505 | vite: ^4.0.0
506 | dependencies:
507 | '@sveltejs/vite-plugin-svelte': 2.4.5(svelte@4.0.0)(vite@4.4.9)
508 | debug: 4.3.4
509 | svelte: 4.0.0
510 | vite: 4.4.9
511 | transitivePeerDependencies:
512 | - supports-color
513 | dev: true
514 |
515 | /@sveltejs/vite-plugin-svelte@2.4.5(svelte@4.0.0)(vite@4.4.9):
516 | resolution: {integrity: sha512-UJKsFNwhzCVuiZd06jM/psscyNJNDwjQC+qIeb7GBJK9iWeQCcIyfcPWDvbCudfcJggY9jtxJeeaZH7uny93FQ==}
517 | engines: {node: ^14.18.0 || >= 16}
518 | peerDependencies:
519 | svelte: ^3.54.0 || ^4.0.0
520 | vite: ^4.0.0
521 | dependencies:
522 | '@sveltejs/vite-plugin-svelte-inspector': 1.0.4(@sveltejs/vite-plugin-svelte@2.4.5)(svelte@4.0.0)(vite@4.4.9)
523 | debug: 4.3.4
524 | deepmerge: 4.3.1
525 | kleur: 4.1.5
526 | magic-string: 0.30.3
527 | svelte: 4.0.0
528 | svelte-hmr: 0.15.3(svelte@4.0.0)
529 | vite: 4.4.9
530 | vitefu: 0.2.4(vite@4.4.9)
531 | transitivePeerDependencies:
532 | - supports-color
533 | dev: true
534 |
535 | /@types/cookie@0.5.1:
536 | resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==}
537 | dev: true
538 |
539 | /@types/estree@1.0.1:
540 | resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==}
541 | dev: true
542 |
543 | /@types/json-schema@7.0.12:
544 | resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
545 | dev: true
546 |
547 | /@types/node@20.5.6:
548 | resolution: {integrity: sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==}
549 | dev: true
550 |
551 | /@types/pug@2.0.6:
552 | resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==}
553 | dev: true
554 |
555 | /@types/semver@7.5.0:
556 | resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==}
557 | dev: true
558 |
559 | /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.48.0)(typescript@5.2.2):
560 | resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==}
561 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
562 | peerDependencies:
563 | '@typescript-eslint/parser': ^5.0.0
564 | eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
565 | typescript: '*'
566 | peerDependenciesMeta:
567 | typescript:
568 | optional: true
569 | dependencies:
570 | '@eslint-community/regexpp': 4.8.0
571 | '@typescript-eslint/parser': 5.62.0(eslint@8.48.0)(typescript@5.2.2)
572 | '@typescript-eslint/scope-manager': 5.62.0
573 | '@typescript-eslint/type-utils': 5.62.0(eslint@8.48.0)(typescript@5.2.2)
574 | '@typescript-eslint/utils': 5.62.0(eslint@8.48.0)(typescript@5.2.2)
575 | debug: 4.3.4
576 | eslint: 8.48.0
577 | graphemer: 1.4.0
578 | ignore: 5.2.4
579 | natural-compare-lite: 1.4.0
580 | semver: 7.5.4
581 | tsutils: 3.21.0(typescript@5.2.2)
582 | typescript: 5.2.2
583 | transitivePeerDependencies:
584 | - supports-color
585 | dev: true
586 |
587 | /@typescript-eslint/parser@5.62.0(eslint@8.48.0)(typescript@5.2.2):
588 | resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==}
589 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
590 | peerDependencies:
591 | eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
592 | typescript: '*'
593 | peerDependenciesMeta:
594 | typescript:
595 | optional: true
596 | dependencies:
597 | '@typescript-eslint/scope-manager': 5.62.0
598 | '@typescript-eslint/types': 5.62.0
599 | '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2)
600 | debug: 4.3.4
601 | eslint: 8.48.0
602 | typescript: 5.2.2
603 | transitivePeerDependencies:
604 | - supports-color
605 | dev: true
606 |
607 | /@typescript-eslint/scope-manager@5.62.0:
608 | resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==}
609 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
610 | dependencies:
611 | '@typescript-eslint/types': 5.62.0
612 | '@typescript-eslint/visitor-keys': 5.62.0
613 | dev: true
614 |
615 | /@typescript-eslint/type-utils@5.62.0(eslint@8.48.0)(typescript@5.2.2):
616 | resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==}
617 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
618 | peerDependencies:
619 | eslint: '*'
620 | typescript: '*'
621 | peerDependenciesMeta:
622 | typescript:
623 | optional: true
624 | dependencies:
625 | '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2)
626 | '@typescript-eslint/utils': 5.62.0(eslint@8.48.0)(typescript@5.2.2)
627 | debug: 4.3.4
628 | eslint: 8.48.0
629 | tsutils: 3.21.0(typescript@5.2.2)
630 | typescript: 5.2.2
631 | transitivePeerDependencies:
632 | - supports-color
633 | dev: true
634 |
635 | /@typescript-eslint/types@5.62.0:
636 | resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==}
637 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
638 | dev: true
639 |
640 | /@typescript-eslint/typescript-estree@5.62.0(typescript@5.2.2):
641 | resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==}
642 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
643 | peerDependencies:
644 | typescript: '*'
645 | peerDependenciesMeta:
646 | typescript:
647 | optional: true
648 | dependencies:
649 | '@typescript-eslint/types': 5.62.0
650 | '@typescript-eslint/visitor-keys': 5.62.0
651 | debug: 4.3.4
652 | globby: 11.1.0
653 | is-glob: 4.0.3
654 | semver: 7.5.4
655 | tsutils: 3.21.0(typescript@5.2.2)
656 | typescript: 5.2.2
657 | transitivePeerDependencies:
658 | - supports-color
659 | dev: true
660 |
661 | /@typescript-eslint/utils@5.62.0(eslint@8.48.0)(typescript@5.2.2):
662 | resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==}
663 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
664 | peerDependencies:
665 | eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
666 | dependencies:
667 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0)
668 | '@types/json-schema': 7.0.12
669 | '@types/semver': 7.5.0
670 | '@typescript-eslint/scope-manager': 5.62.0
671 | '@typescript-eslint/types': 5.62.0
672 | '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.2.2)
673 | eslint: 8.48.0
674 | eslint-scope: 5.1.1
675 | semver: 7.5.4
676 | transitivePeerDependencies:
677 | - supports-color
678 | - typescript
679 | dev: true
680 |
681 | /@typescript-eslint/visitor-keys@5.62.0:
682 | resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==}
683 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
684 | dependencies:
685 | '@typescript-eslint/types': 5.62.0
686 | eslint-visitor-keys: 3.4.3
687 | dev: true
688 |
689 | /acorn-jsx@5.3.2(acorn@8.10.0):
690 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
691 | peerDependencies:
692 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
693 | dependencies:
694 | acorn: 8.10.0
695 | dev: true
696 |
697 | /acorn@8.10.0:
698 | resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==}
699 | engines: {node: '>=0.4.0'}
700 | hasBin: true
701 | dev: true
702 |
703 | /ajv@6.12.6:
704 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
705 | dependencies:
706 | fast-deep-equal: 3.1.3
707 | fast-json-stable-stringify: 2.1.0
708 | json-schema-traverse: 0.4.1
709 | uri-js: 4.4.1
710 | dev: true
711 |
712 | /ansi-regex@5.0.1:
713 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
714 | engines: {node: '>=8'}
715 | dev: true
716 |
717 | /ansi-styles@4.3.0:
718 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
719 | engines: {node: '>=8'}
720 | dependencies:
721 | color-convert: 2.0.1
722 | dev: true
723 |
724 | /anymatch@3.1.3:
725 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
726 | engines: {node: '>= 8'}
727 | dependencies:
728 | normalize-path: 3.0.0
729 | picomatch: 2.3.1
730 | dev: true
731 |
732 | /argparse@2.0.1:
733 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
734 | dev: true
735 |
736 | /aria-query@5.3.0:
737 | resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
738 | dependencies:
739 | dequal: 2.0.3
740 | dev: true
741 |
742 | /array-union@2.1.0:
743 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
744 | engines: {node: '>=8'}
745 | dev: true
746 |
747 | /axobject-query@3.2.1:
748 | resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
749 | dependencies:
750 | dequal: 2.0.3
751 | dev: true
752 |
753 | /balanced-match@1.0.2:
754 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
755 | dev: true
756 |
757 | /binary-extensions@2.2.0:
758 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
759 | engines: {node: '>=8'}
760 | dev: true
761 |
762 | /brace-expansion@1.1.11:
763 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
764 | dependencies:
765 | balanced-match: 1.0.2
766 | concat-map: 0.0.1
767 | dev: true
768 |
769 | /braces@3.0.2:
770 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
771 | engines: {node: '>=8'}
772 | dependencies:
773 | fill-range: 7.0.1
774 | dev: true
775 |
776 | /buffer-crc32@0.2.13:
777 | resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
778 | dev: true
779 |
780 | /busboy@1.6.0:
781 | resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
782 | engines: {node: '>=10.16.0'}
783 | dependencies:
784 | streamsearch: 1.1.0
785 | dev: true
786 |
787 | /callsites@3.1.0:
788 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
789 | engines: {node: '>=6'}
790 | dev: true
791 |
792 | /chalk@4.1.2:
793 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
794 | engines: {node: '>=10'}
795 | dependencies:
796 | ansi-styles: 4.3.0
797 | supports-color: 7.2.0
798 | dev: true
799 |
800 | /chokidar@3.5.3:
801 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
802 | engines: {node: '>= 8.10.0'}
803 | dependencies:
804 | anymatch: 3.1.3
805 | braces: 3.0.2
806 | glob-parent: 5.1.2
807 | is-binary-path: 2.1.0
808 | is-glob: 4.0.3
809 | normalize-path: 3.0.0
810 | readdirp: 3.6.0
811 | optionalDependencies:
812 | fsevents: 2.3.3
813 | dev: true
814 |
815 | /cluster-key-slot@1.1.2:
816 | resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
817 | engines: {node: '>=0.10.0'}
818 |
819 | /code-red@1.0.4:
820 | resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==}
821 | dependencies:
822 | '@jridgewell/sourcemap-codec': 1.4.15
823 | '@types/estree': 1.0.1
824 | acorn: 8.10.0
825 | estree-walker: 3.0.3
826 | periscopic: 3.1.0
827 | dev: true
828 |
829 | /color-convert@2.0.1:
830 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
831 | engines: {node: '>=7.0.0'}
832 | dependencies:
833 | color-name: 1.1.4
834 | dev: true
835 |
836 | /color-name@1.1.4:
837 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
838 | dev: true
839 |
840 | /concat-map@0.0.1:
841 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
842 | dev: true
843 |
844 | /cookie@0.5.0:
845 | resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
846 | engines: {node: '>= 0.6'}
847 | dev: true
848 |
849 | /cross-spawn@7.0.3:
850 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
851 | engines: {node: '>= 8'}
852 | dependencies:
853 | path-key: 3.1.1
854 | shebang-command: 2.0.0
855 | which: 2.0.2
856 | dev: true
857 |
858 | /css-tree@2.3.1:
859 | resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
860 | engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
861 | dependencies:
862 | mdn-data: 2.0.30
863 | source-map-js: 1.0.2
864 | dev: true
865 |
866 | /debug@4.3.4:
867 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
868 | engines: {node: '>=6.0'}
869 | peerDependencies:
870 | supports-color: '*'
871 | peerDependenciesMeta:
872 | supports-color:
873 | optional: true
874 | dependencies:
875 | ms: 2.1.2
876 | dev: true
877 |
878 | /deep-is@0.1.4:
879 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
880 | dev: true
881 |
882 | /deepmerge@4.3.1:
883 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
884 | engines: {node: '>=0.10.0'}
885 | dev: true
886 |
887 | /denque@2.1.0:
888 | resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
889 | engines: {node: '>=0.10'}
890 | dev: true
891 |
892 | /dequal@2.0.3:
893 | resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
894 | engines: {node: '>=6'}
895 | dev: true
896 |
897 | /detect-indent@6.1.0:
898 | resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
899 | engines: {node: '>=8'}
900 | dev: true
901 |
902 | /devalue@4.3.2:
903 | resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==}
904 | dev: true
905 |
906 | /dir-glob@3.0.1:
907 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
908 | engines: {node: '>=8'}
909 | dependencies:
910 | path-type: 4.0.0
911 | dev: true
912 |
913 | /doctrine@3.0.0:
914 | resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
915 | engines: {node: '>=6.0.0'}
916 | dependencies:
917 | esutils: 2.0.3
918 | dev: true
919 |
920 | /es6-promise@3.3.1:
921 | resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
922 | dev: true
923 |
924 | /esbuild@0.18.20:
925 | resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
926 | engines: {node: '>=12'}
927 | hasBin: true
928 | requiresBuild: true
929 | optionalDependencies:
930 | '@esbuild/android-arm': 0.18.20
931 | '@esbuild/android-arm64': 0.18.20
932 | '@esbuild/android-x64': 0.18.20
933 | '@esbuild/darwin-arm64': 0.18.20
934 | '@esbuild/darwin-x64': 0.18.20
935 | '@esbuild/freebsd-arm64': 0.18.20
936 | '@esbuild/freebsd-x64': 0.18.20
937 | '@esbuild/linux-arm': 0.18.20
938 | '@esbuild/linux-arm64': 0.18.20
939 | '@esbuild/linux-ia32': 0.18.20
940 | '@esbuild/linux-loong64': 0.18.20
941 | '@esbuild/linux-mips64el': 0.18.20
942 | '@esbuild/linux-ppc64': 0.18.20
943 | '@esbuild/linux-riscv64': 0.18.20
944 | '@esbuild/linux-s390x': 0.18.20
945 | '@esbuild/linux-x64': 0.18.20
946 | '@esbuild/netbsd-x64': 0.18.20
947 | '@esbuild/openbsd-x64': 0.18.20
948 | '@esbuild/sunos-x64': 0.18.20
949 | '@esbuild/win32-arm64': 0.18.20
950 | '@esbuild/win32-ia32': 0.18.20
951 | '@esbuild/win32-x64': 0.18.20
952 | dev: true
953 |
954 | /escape-string-regexp@4.0.0:
955 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
956 | engines: {node: '>=10'}
957 | dev: true
958 |
959 | /eslint-config-prettier@8.10.0(eslint@8.48.0):
960 | resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
961 | hasBin: true
962 | peerDependencies:
963 | eslint: '>=7.0.0'
964 | dependencies:
965 | eslint: 8.48.0
966 | dev: true
967 |
968 | /eslint-plugin-svelte3@4.0.0(eslint@8.48.0)(svelte@4.0.0):
969 | resolution: {integrity: sha512-OIx9lgaNzD02+MDFNLw0GEUbuovNcglg+wnd/UY0fbZmlQSz7GlQiQ1f+yX0XvC07XPcDOnFcichqI3xCwp71g==}
970 | peerDependencies:
971 | eslint: '>=8.0.0'
972 | svelte: ^3.2.0
973 | dependencies:
974 | eslint: 8.48.0
975 | svelte: 4.0.0
976 | dev: true
977 |
978 | /eslint-scope@5.1.1:
979 | resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
980 | engines: {node: '>=8.0.0'}
981 | dependencies:
982 | esrecurse: 4.3.0
983 | estraverse: 4.3.0
984 | dev: true
985 |
986 | /eslint-scope@7.2.2:
987 | resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
988 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
989 | dependencies:
990 | esrecurse: 4.3.0
991 | estraverse: 5.3.0
992 | dev: true
993 |
994 | /eslint-visitor-keys@3.4.3:
995 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
996 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
997 | dev: true
998 |
999 | /eslint@8.48.0:
1000 | resolution: {integrity: sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==}
1001 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
1002 | hasBin: true
1003 | dependencies:
1004 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0)
1005 | '@eslint-community/regexpp': 4.8.0
1006 | '@eslint/eslintrc': 2.1.2
1007 | '@eslint/js': 8.48.0
1008 | '@humanwhocodes/config-array': 0.11.10
1009 | '@humanwhocodes/module-importer': 1.0.1
1010 | '@nodelib/fs.walk': 1.2.8
1011 | ajv: 6.12.6
1012 | chalk: 4.1.2
1013 | cross-spawn: 7.0.3
1014 | debug: 4.3.4
1015 | doctrine: 3.0.0
1016 | escape-string-regexp: 4.0.0
1017 | eslint-scope: 7.2.2
1018 | eslint-visitor-keys: 3.4.3
1019 | espree: 9.6.1
1020 | esquery: 1.5.0
1021 | esutils: 2.0.3
1022 | fast-deep-equal: 3.1.3
1023 | file-entry-cache: 6.0.1
1024 | find-up: 5.0.0
1025 | glob-parent: 6.0.2
1026 | globals: 13.21.0
1027 | graphemer: 1.4.0
1028 | ignore: 5.2.4
1029 | imurmurhash: 0.1.4
1030 | is-glob: 4.0.3
1031 | is-path-inside: 3.0.3
1032 | js-yaml: 4.1.0
1033 | json-stable-stringify-without-jsonify: 1.0.1
1034 | levn: 0.4.1
1035 | lodash.merge: 4.6.2
1036 | minimatch: 3.1.2
1037 | natural-compare: 1.4.0
1038 | optionator: 0.9.3
1039 | strip-ansi: 6.0.1
1040 | text-table: 0.2.0
1041 | transitivePeerDependencies:
1042 | - supports-color
1043 | dev: true
1044 |
1045 | /esm-env@1.0.0:
1046 | resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==}
1047 | dev: true
1048 |
1049 | /espree@9.6.1:
1050 | resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
1051 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
1052 | dependencies:
1053 | acorn: 8.10.0
1054 | acorn-jsx: 5.3.2(acorn@8.10.0)
1055 | eslint-visitor-keys: 3.4.3
1056 | dev: true
1057 |
1058 | /esquery@1.5.0:
1059 | resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
1060 | engines: {node: '>=0.10'}
1061 | dependencies:
1062 | estraverse: 5.3.0
1063 | dev: true
1064 |
1065 | /esrecurse@4.3.0:
1066 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
1067 | engines: {node: '>=4.0'}
1068 | dependencies:
1069 | estraverse: 5.3.0
1070 | dev: true
1071 |
1072 | /estraverse@4.3.0:
1073 | resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
1074 | engines: {node: '>=4.0'}
1075 | dev: true
1076 |
1077 | /estraverse@5.3.0:
1078 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
1079 | engines: {node: '>=4.0'}
1080 | dev: true
1081 |
1082 | /estree-walker@3.0.3:
1083 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
1084 | dependencies:
1085 | '@types/estree': 1.0.1
1086 | dev: true
1087 |
1088 | /esutils@2.0.3:
1089 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
1090 | engines: {node: '>=0.10.0'}
1091 | dev: true
1092 |
1093 | /fast-deep-equal@3.1.3:
1094 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
1095 | dev: true
1096 |
1097 | /fast-glob@3.3.1:
1098 | resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
1099 | engines: {node: '>=8.6.0'}
1100 | dependencies:
1101 | '@nodelib/fs.stat': 2.0.5
1102 | '@nodelib/fs.walk': 1.2.8
1103 | glob-parent: 5.1.2
1104 | merge2: 1.4.1
1105 | micromatch: 4.0.5
1106 | dev: true
1107 |
1108 | /fast-json-stable-stringify@2.1.0:
1109 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
1110 | dev: true
1111 |
1112 | /fast-levenshtein@2.0.6:
1113 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
1114 | dev: true
1115 |
1116 | /fastq@1.15.0:
1117 | resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
1118 | dependencies:
1119 | reusify: 1.0.4
1120 | dev: true
1121 |
1122 | /file-entry-cache@6.0.1:
1123 | resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
1124 | engines: {node: ^10.12.0 || >=12.0.0}
1125 | dependencies:
1126 | flat-cache: 3.1.0
1127 | dev: true
1128 |
1129 | /fill-range@7.0.1:
1130 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
1131 | engines: {node: '>=8'}
1132 | dependencies:
1133 | to-regex-range: 5.0.1
1134 | dev: true
1135 |
1136 | /find-up@5.0.0:
1137 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
1138 | engines: {node: '>=10'}
1139 | dependencies:
1140 | locate-path: 6.0.0
1141 | path-exists: 4.0.0
1142 | dev: true
1143 |
1144 | /flat-cache@3.1.0:
1145 | resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==}
1146 | engines: {node: '>=12.0.0'}
1147 | dependencies:
1148 | flatted: 3.2.7
1149 | keyv: 4.5.3
1150 | rimraf: 3.0.2
1151 | dev: true
1152 |
1153 | /flatted@3.2.7:
1154 | resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
1155 | dev: true
1156 |
1157 | /fs.realpath@1.0.0:
1158 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
1159 | dev: true
1160 |
1161 | /fsevents@2.3.2:
1162 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
1163 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
1164 | os: [darwin]
1165 | requiresBuild: true
1166 | dev: true
1167 | optional: true
1168 |
1169 | /fsevents@2.3.3:
1170 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
1171 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
1172 | os: [darwin]
1173 | requiresBuild: true
1174 | dev: true
1175 | optional: true
1176 |
1177 | /generic-pool@3.9.0:
1178 | resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==}
1179 | engines: {node: '>= 4'}
1180 | dev: false
1181 |
1182 | /glob-parent@5.1.2:
1183 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
1184 | engines: {node: '>= 6'}
1185 | dependencies:
1186 | is-glob: 4.0.3
1187 | dev: true
1188 |
1189 | /glob-parent@6.0.2:
1190 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
1191 | engines: {node: '>=10.13.0'}
1192 | dependencies:
1193 | is-glob: 4.0.3
1194 | dev: true
1195 |
1196 | /glob@7.2.3:
1197 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
1198 | dependencies:
1199 | fs.realpath: 1.0.0
1200 | inflight: 1.0.6
1201 | inherits: 2.0.4
1202 | minimatch: 3.1.2
1203 | once: 1.4.0
1204 | path-is-absolute: 1.0.1
1205 | dev: true
1206 |
1207 | /globals@13.21.0:
1208 | resolution: {integrity: sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==}
1209 | engines: {node: '>=8'}
1210 | dependencies:
1211 | type-fest: 0.20.2
1212 | dev: true
1213 |
1214 | /globby@11.1.0:
1215 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
1216 | engines: {node: '>=10'}
1217 | dependencies:
1218 | array-union: 2.1.0
1219 | dir-glob: 3.0.1
1220 | fast-glob: 3.3.1
1221 | ignore: 5.2.4
1222 | merge2: 1.4.1
1223 | slash: 3.0.0
1224 | dev: true
1225 |
1226 | /graceful-fs@4.2.11:
1227 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
1228 | dev: true
1229 |
1230 | /graphemer@1.4.0:
1231 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
1232 | dev: true
1233 |
1234 | /has-flag@4.0.0:
1235 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
1236 | engines: {node: '>=8'}
1237 | dev: true
1238 |
1239 | /ignore@5.2.4:
1240 | resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
1241 | engines: {node: '>= 4'}
1242 | dev: true
1243 |
1244 | /import-fresh@3.3.0:
1245 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
1246 | engines: {node: '>=6'}
1247 | dependencies:
1248 | parent-module: 1.0.1
1249 | resolve-from: 4.0.0
1250 | dev: true
1251 |
1252 | /imurmurhash@0.1.4:
1253 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
1254 | engines: {node: '>=0.8.19'}
1255 | dev: true
1256 |
1257 | /inflight@1.0.6:
1258 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
1259 | dependencies:
1260 | once: 1.4.0
1261 | wrappy: 1.0.2
1262 | dev: true
1263 |
1264 | /inherits@2.0.4:
1265 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
1266 | dev: true
1267 |
1268 | /ioredis@5.3.2:
1269 | resolution: {integrity: sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==}
1270 | engines: {node: '>=12.22.0'}
1271 | dependencies:
1272 | '@ioredis/commands': 1.2.0
1273 | cluster-key-slot: 1.1.2
1274 | debug: 4.3.4
1275 | denque: 2.1.0
1276 | lodash.defaults: 4.2.0
1277 | lodash.isarguments: 3.1.0
1278 | redis-errors: 1.2.0
1279 | redis-parser: 3.0.0
1280 | standard-as-callback: 2.1.0
1281 | transitivePeerDependencies:
1282 | - supports-color
1283 | dev: true
1284 |
1285 | /is-binary-path@2.1.0:
1286 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
1287 | engines: {node: '>=8'}
1288 | dependencies:
1289 | binary-extensions: 2.2.0
1290 | dev: true
1291 |
1292 | /is-extglob@2.1.1:
1293 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
1294 | engines: {node: '>=0.10.0'}
1295 | dev: true
1296 |
1297 | /is-glob@4.0.3:
1298 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
1299 | engines: {node: '>=0.10.0'}
1300 | dependencies:
1301 | is-extglob: 2.1.1
1302 | dev: true
1303 |
1304 | /is-number@7.0.0:
1305 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
1306 | engines: {node: '>=0.12.0'}
1307 | dev: true
1308 |
1309 | /is-path-inside@3.0.3:
1310 | resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
1311 | engines: {node: '>=8'}
1312 | dev: true
1313 |
1314 | /is-reference@3.0.1:
1315 | resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==}
1316 | dependencies:
1317 | '@types/estree': 1.0.1
1318 | dev: true
1319 |
1320 | /isexe@2.0.0:
1321 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
1322 | dev: true
1323 |
1324 | /js-yaml@4.1.0:
1325 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
1326 | hasBin: true
1327 | dependencies:
1328 | argparse: 2.0.1
1329 | dev: true
1330 |
1331 | /json-buffer@3.0.1:
1332 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
1333 | dev: true
1334 |
1335 | /json-schema-traverse@0.4.1:
1336 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
1337 | dev: true
1338 |
1339 | /json-stable-stringify-without-jsonify@1.0.1:
1340 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
1341 | dev: true
1342 |
1343 | /keyv@4.5.3:
1344 | resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==}
1345 | dependencies:
1346 | json-buffer: 3.0.1
1347 | dev: true
1348 |
1349 | /kleur@4.1.5:
1350 | resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
1351 | engines: {node: '>=6'}
1352 | dev: true
1353 |
1354 | /levn@0.4.1:
1355 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
1356 | engines: {node: '>= 0.8.0'}
1357 | dependencies:
1358 | prelude-ls: 1.2.1
1359 | type-check: 0.4.0
1360 | dev: true
1361 |
1362 | /locate-character@3.0.0:
1363 | resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
1364 | dev: true
1365 |
1366 | /locate-path@6.0.0:
1367 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
1368 | engines: {node: '>=10'}
1369 | dependencies:
1370 | p-locate: 5.0.0
1371 | dev: true
1372 |
1373 | /lodash.defaults@4.2.0:
1374 | resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
1375 | dev: true
1376 |
1377 | /lodash.isarguments@3.1.0:
1378 | resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
1379 | dev: true
1380 |
1381 | /lodash.merge@4.6.2:
1382 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
1383 | dev: true
1384 |
1385 | /lru-cache@6.0.0:
1386 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
1387 | engines: {node: '>=10'}
1388 | dependencies:
1389 | yallist: 4.0.0
1390 | dev: true
1391 |
1392 | /magic-string@0.27.0:
1393 | resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
1394 | engines: {node: '>=12'}
1395 | dependencies:
1396 | '@jridgewell/sourcemap-codec': 1.4.15
1397 | dev: true
1398 |
1399 | /magic-string@0.30.3:
1400 | resolution: {integrity: sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==}
1401 | engines: {node: '>=12'}
1402 | dependencies:
1403 | '@jridgewell/sourcemap-codec': 1.4.15
1404 | dev: true
1405 |
1406 | /mdn-data@2.0.30:
1407 | resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
1408 | dev: true
1409 |
1410 | /merge2@1.4.1:
1411 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
1412 | engines: {node: '>= 8'}
1413 | dev: true
1414 |
1415 | /micromatch@4.0.5:
1416 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
1417 | engines: {node: '>=8.6'}
1418 | dependencies:
1419 | braces: 3.0.2
1420 | picomatch: 2.3.1
1421 | dev: true
1422 |
1423 | /mime@3.0.0:
1424 | resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
1425 | engines: {node: '>=10.0.0'}
1426 | hasBin: true
1427 | dev: true
1428 |
1429 | /min-indent@1.0.1:
1430 | resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
1431 | engines: {node: '>=4'}
1432 | dev: true
1433 |
1434 | /minimatch@3.1.2:
1435 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
1436 | dependencies:
1437 | brace-expansion: 1.1.11
1438 | dev: true
1439 |
1440 | /minimist@1.2.8:
1441 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
1442 | dev: true
1443 |
1444 | /mkdirp@0.5.6:
1445 | resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
1446 | hasBin: true
1447 | dependencies:
1448 | minimist: 1.2.8
1449 | dev: true
1450 |
1451 | /mri@1.2.0:
1452 | resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
1453 | engines: {node: '>=4'}
1454 | dev: true
1455 |
1456 | /mrmime@1.0.1:
1457 | resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==}
1458 | engines: {node: '>=10'}
1459 | dev: true
1460 |
1461 | /ms@2.1.2:
1462 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
1463 | dev: true
1464 |
1465 | /nanoid@3.3.6:
1466 | resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
1467 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
1468 | hasBin: true
1469 | dev: true
1470 |
1471 | /natural-compare-lite@1.4.0:
1472 | resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
1473 | dev: true
1474 |
1475 | /natural-compare@1.4.0:
1476 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
1477 | dev: true
1478 |
1479 | /normalize-path@3.0.0:
1480 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
1481 | engines: {node: '>=0.10.0'}
1482 | dev: true
1483 |
1484 | /once@1.4.0:
1485 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
1486 | dependencies:
1487 | wrappy: 1.0.2
1488 | dev: true
1489 |
1490 | /optionator@0.9.3:
1491 | resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
1492 | engines: {node: '>= 0.8.0'}
1493 | dependencies:
1494 | '@aashutoshrathi/word-wrap': 1.2.6
1495 | deep-is: 0.1.4
1496 | fast-levenshtein: 2.0.6
1497 | levn: 0.4.1
1498 | prelude-ls: 1.2.1
1499 | type-check: 0.4.0
1500 | dev: true
1501 |
1502 | /p-limit@3.1.0:
1503 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
1504 | engines: {node: '>=10'}
1505 | dependencies:
1506 | yocto-queue: 0.1.0
1507 | dev: true
1508 |
1509 | /p-locate@5.0.0:
1510 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
1511 | engines: {node: '>=10'}
1512 | dependencies:
1513 | p-limit: 3.1.0
1514 | dev: true
1515 |
1516 | /parent-module@1.0.1:
1517 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
1518 | engines: {node: '>=6'}
1519 | dependencies:
1520 | callsites: 3.1.0
1521 | dev: true
1522 |
1523 | /path-exists@4.0.0:
1524 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
1525 | engines: {node: '>=8'}
1526 | dev: true
1527 |
1528 | /path-is-absolute@1.0.1:
1529 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
1530 | engines: {node: '>=0.10.0'}
1531 | dev: true
1532 |
1533 | /path-key@3.1.1:
1534 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
1535 | engines: {node: '>=8'}
1536 | dev: true
1537 |
1538 | /path-type@4.0.0:
1539 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
1540 | engines: {node: '>=8'}
1541 | dev: true
1542 |
1543 | /periscopic@3.1.0:
1544 | resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==}
1545 | dependencies:
1546 | '@types/estree': 1.0.1
1547 | estree-walker: 3.0.3
1548 | is-reference: 3.0.1
1549 | dev: true
1550 |
1551 | /picocolors@1.0.0:
1552 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
1553 | dev: true
1554 |
1555 | /picomatch@2.3.1:
1556 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
1557 | engines: {node: '>=8.6'}
1558 | dev: true
1559 |
1560 | /playwright-core@1.37.1:
1561 | resolution: {integrity: sha512-17EuQxlSIYCmEMwzMqusJ2ztDgJePjrbttaefgdsiqeLWidjYz9BxXaTaZWxH1J95SHGk6tjE+dwgWILJoUZfA==}
1562 | engines: {node: '>=16'}
1563 | hasBin: true
1564 | dev: true
1565 |
1566 | /postcss@8.4.28:
1567 | resolution: {integrity: sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==}
1568 | engines: {node: ^10 || ^12 || >=14}
1569 | dependencies:
1570 | nanoid: 3.3.6
1571 | picocolors: 1.0.0
1572 | source-map-js: 1.0.2
1573 | dev: true
1574 |
1575 | /prelude-ls@1.2.1:
1576 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
1577 | engines: {node: '>= 0.8.0'}
1578 | dev: true
1579 |
1580 | /prettier-plugin-svelte@2.10.1(prettier@2.8.8)(svelte@4.0.0):
1581 | resolution: {integrity: sha512-Wlq7Z5v2ueCubWo0TZzKc9XHcm7TDxqcuzRuGd0gcENfzfT4JZ9yDlCbEgxWgiPmLHkBjfOtpAWkcT28MCDpUQ==}
1582 | peerDependencies:
1583 | prettier: ^1.16.4 || ^2.0.0
1584 | svelte: ^3.2.0 || ^4.0.0-next.0
1585 | dependencies:
1586 | prettier: 2.8.8
1587 | svelte: 4.0.0
1588 | dev: true
1589 |
1590 | /prettier@2.8.8:
1591 | resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
1592 | engines: {node: '>=10.13.0'}
1593 | hasBin: true
1594 | dev: true
1595 |
1596 | /punycode@2.3.0:
1597 | resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
1598 | engines: {node: '>=6'}
1599 | dev: true
1600 |
1601 | /queue-microtask@1.2.3:
1602 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
1603 | dev: true
1604 |
1605 | /readdirp@3.6.0:
1606 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
1607 | engines: {node: '>=8.10.0'}
1608 | dependencies:
1609 | picomatch: 2.3.1
1610 | dev: true
1611 |
1612 | /redis-errors@1.2.0:
1613 | resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
1614 | engines: {node: '>=4'}
1615 | dev: true
1616 |
1617 | /redis-parser@3.0.0:
1618 | resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
1619 | engines: {node: '>=4'}
1620 | dependencies:
1621 | redis-errors: 1.2.0
1622 | dev: true
1623 |
1624 | /redis@4.6.10:
1625 | resolution: {integrity: sha512-mmbyhuKgDiJ5TWUhiKhBssz+mjsuSI/lSZNPI9QvZOYzWvYGejtb+W3RlDDf8LD6Bdl5/mZeG8O1feUGhXTxEg==}
1626 | dependencies:
1627 | '@redis/bloom': 1.2.0(@redis/client@1.5.11)
1628 | '@redis/client': 1.5.11
1629 | '@redis/graph': 1.1.0(@redis/client@1.5.11)
1630 | '@redis/json': 1.0.6(@redis/client@1.5.11)
1631 | '@redis/search': 1.1.5(@redis/client@1.5.11)
1632 | '@redis/time-series': 1.0.5(@redis/client@1.5.11)
1633 | dev: false
1634 |
1635 | /resolve-from@4.0.0:
1636 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
1637 | engines: {node: '>=4'}
1638 | dev: true
1639 |
1640 | /reusify@1.0.4:
1641 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
1642 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
1643 | dev: true
1644 |
1645 | /rimraf@2.7.1:
1646 | resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
1647 | hasBin: true
1648 | dependencies:
1649 | glob: 7.2.3
1650 | dev: true
1651 |
1652 | /rimraf@3.0.2:
1653 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
1654 | hasBin: true
1655 | dependencies:
1656 | glob: 7.2.3
1657 | dev: true
1658 |
1659 | /rollup@3.28.1:
1660 | resolution: {integrity: sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==}
1661 | engines: {node: '>=14.18.0', npm: '>=8.0.0'}
1662 | hasBin: true
1663 | optionalDependencies:
1664 | fsevents: 2.3.3
1665 | dev: true
1666 |
1667 | /run-parallel@1.2.0:
1668 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
1669 | dependencies:
1670 | queue-microtask: 1.2.3
1671 | dev: true
1672 |
1673 | /sade@1.8.1:
1674 | resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
1675 | engines: {node: '>=6'}
1676 | dependencies:
1677 | mri: 1.2.0
1678 | dev: true
1679 |
1680 | /sander@0.5.1:
1681 | resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==}
1682 | dependencies:
1683 | es6-promise: 3.3.1
1684 | graceful-fs: 4.2.11
1685 | mkdirp: 0.5.6
1686 | rimraf: 2.7.1
1687 | dev: true
1688 |
1689 | /semver@7.5.4:
1690 | resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
1691 | engines: {node: '>=10'}
1692 | hasBin: true
1693 | dependencies:
1694 | lru-cache: 6.0.0
1695 | dev: true
1696 |
1697 | /set-cookie-parser@2.6.0:
1698 | resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
1699 | dev: true
1700 |
1701 | /shebang-command@2.0.0:
1702 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
1703 | engines: {node: '>=8'}
1704 | dependencies:
1705 | shebang-regex: 3.0.0
1706 | dev: true
1707 |
1708 | /shebang-regex@3.0.0:
1709 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
1710 | engines: {node: '>=8'}
1711 | dev: true
1712 |
1713 | /sirv@2.0.3:
1714 | resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==}
1715 | engines: {node: '>= 10'}
1716 | dependencies:
1717 | '@polka/url': 1.0.0-next.21
1718 | mrmime: 1.0.1
1719 | totalist: 3.0.1
1720 | dev: true
1721 |
1722 | /slash@3.0.0:
1723 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
1724 | engines: {node: '>=8'}
1725 | dev: true
1726 |
1727 | /sorcery@0.11.0:
1728 | resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==}
1729 | hasBin: true
1730 | dependencies:
1731 | '@jridgewell/sourcemap-codec': 1.4.15
1732 | buffer-crc32: 0.2.13
1733 | minimist: 1.2.8
1734 | sander: 0.5.1
1735 | dev: true
1736 |
1737 | /source-map-js@1.0.2:
1738 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
1739 | engines: {node: '>=0.10.0'}
1740 | dev: true
1741 |
1742 | /standard-as-callback@2.1.0:
1743 | resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
1744 | dev: true
1745 |
1746 | /streamsearch@1.1.0:
1747 | resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
1748 | engines: {node: '>=10.0.0'}
1749 | dev: true
1750 |
1751 | /strip-ansi@6.0.1:
1752 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
1753 | engines: {node: '>=8'}
1754 | dependencies:
1755 | ansi-regex: 5.0.1
1756 | dev: true
1757 |
1758 | /strip-indent@3.0.0:
1759 | resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
1760 | engines: {node: '>=8'}
1761 | dependencies:
1762 | min-indent: 1.0.1
1763 | dev: true
1764 |
1765 | /strip-json-comments@3.1.1:
1766 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
1767 | engines: {node: '>=8'}
1768 | dev: true
1769 |
1770 | /supports-color@7.2.0:
1771 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
1772 | engines: {node: '>=8'}
1773 | dependencies:
1774 | has-flag: 4.0.0
1775 | dev: true
1776 |
1777 | /svelte-check@3.5.0(svelte@4.0.0):
1778 | resolution: {integrity: sha512-KHujbn4k17xKYLmtCwv0sKKM7uiHTYcQvXnvrCcNU6a7hcszh99zFTIoiu/Sp/ewAw5aJmillJ1Cs8gKLmcX4A==}
1779 | hasBin: true
1780 | peerDependencies:
1781 | svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0
1782 | dependencies:
1783 | '@jridgewell/trace-mapping': 0.3.19
1784 | chokidar: 3.5.3
1785 | fast-glob: 3.3.1
1786 | import-fresh: 3.3.0
1787 | picocolors: 1.0.0
1788 | sade: 1.8.1
1789 | svelte: 4.0.0
1790 | svelte-preprocess: 5.0.4(svelte@4.0.0)(typescript@5.2.2)
1791 | typescript: 5.2.2
1792 | transitivePeerDependencies:
1793 | - '@babel/core'
1794 | - coffeescript
1795 | - less
1796 | - postcss
1797 | - postcss-load-config
1798 | - pug
1799 | - sass
1800 | - stylus
1801 | - sugarss
1802 | dev: true
1803 |
1804 | /svelte-french-toast@1.2.0(svelte@4.0.0):
1805 | resolution: {integrity: sha512-5PW+6RFX3xQPbR44CngYAP1Sd9oCq9P2FOox4FZffzJuZI2mHOB7q5gJBVnOiLF5y3moVGZ7u2bYt7+yPAgcEQ==}
1806 | peerDependencies:
1807 | svelte: ^3.57.0 || ^4.0.0
1808 | dependencies:
1809 | svelte: 4.0.0
1810 | svelte-writable-derived: 3.1.0(svelte@4.0.0)
1811 | dev: true
1812 |
1813 | /svelte-hmr@0.15.3(svelte@4.0.0):
1814 | resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==}
1815 | engines: {node: ^12.20 || ^14.13.1 || >= 16}
1816 | peerDependencies:
1817 | svelte: ^3.19.0 || ^4.0.0
1818 | dependencies:
1819 | svelte: 4.0.0
1820 | dev: true
1821 |
1822 | /svelte-preprocess@5.0.4(svelte@4.0.0)(typescript@5.2.2):
1823 | resolution: {integrity: sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==}
1824 | engines: {node: '>= 14.10.0'}
1825 | requiresBuild: true
1826 | peerDependencies:
1827 | '@babel/core': ^7.10.2
1828 | coffeescript: ^2.5.1
1829 | less: ^3.11.3 || ^4.0.0
1830 | postcss: ^7 || ^8
1831 | postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0
1832 | pug: ^3.0.0
1833 | sass: ^1.26.8
1834 | stylus: ^0.55.0
1835 | sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0
1836 | svelte: ^3.23.0 || ^4.0.0-next.0 || ^4.0.0
1837 | typescript: '>=3.9.5 || ^4.0.0 || ^5.0.0'
1838 | peerDependenciesMeta:
1839 | '@babel/core':
1840 | optional: true
1841 | coffeescript:
1842 | optional: true
1843 | less:
1844 | optional: true
1845 | postcss:
1846 | optional: true
1847 | postcss-load-config:
1848 | optional: true
1849 | pug:
1850 | optional: true
1851 | sass:
1852 | optional: true
1853 | stylus:
1854 | optional: true
1855 | sugarss:
1856 | optional: true
1857 | typescript:
1858 | optional: true
1859 | dependencies:
1860 | '@types/pug': 2.0.6
1861 | detect-indent: 6.1.0
1862 | magic-string: 0.27.0
1863 | sorcery: 0.11.0
1864 | strip-indent: 3.0.0
1865 | svelte: 4.0.0
1866 | typescript: 5.2.2
1867 | dev: true
1868 |
1869 | /svelte-writable-derived@3.1.0(svelte@4.0.0):
1870 | resolution: {integrity: sha512-cTvaVFNIJ036vSDIyPxJYivKC7ZLtcFOPm1Iq6qWBDo1fOHzfk6ZSbwaKrxhjgy52Rbl5IHzRcWgos6Zqn9/rg==}
1871 | peerDependencies:
1872 | svelte: ^3.2.1 || ^4.0.0-next.1
1873 | dependencies:
1874 | svelte: 4.0.0
1875 | dev: true
1876 |
1877 | /svelte@4.0.0:
1878 | resolution: {integrity: sha512-+yCYu3AEUu9n91dnQNGIbnVp8EmNQtuF/YImW4+FTXRHard7NMo+yTsWzggPAbj3fUEJ1FBJLkql/jkp6YB5pg==}
1879 | engines: {node: '>=16'}
1880 | dependencies:
1881 | '@ampproject/remapping': 2.2.1
1882 | '@jridgewell/sourcemap-codec': 1.4.15
1883 | '@jridgewell/trace-mapping': 0.3.19
1884 | acorn: 8.10.0
1885 | aria-query: 5.3.0
1886 | axobject-query: 3.2.1
1887 | code-red: 1.0.4
1888 | css-tree: 2.3.1
1889 | estree-walker: 3.0.3
1890 | is-reference: 3.0.1
1891 | locate-character: 3.0.0
1892 | magic-string: 0.30.3
1893 | periscopic: 3.1.0
1894 | dev: true
1895 |
1896 | /text-table@0.2.0:
1897 | resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
1898 | dev: true
1899 |
1900 | /to-regex-range@5.0.1:
1901 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
1902 | engines: {node: '>=8.0'}
1903 | dependencies:
1904 | is-number: 7.0.0
1905 | dev: true
1906 |
1907 | /totalist@3.0.1:
1908 | resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
1909 | engines: {node: '>=6'}
1910 | dev: true
1911 |
1912 | /tslib@1.14.1:
1913 | resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
1914 | dev: true
1915 |
1916 | /tslib@2.6.2:
1917 | resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
1918 | dev: true
1919 |
1920 | /tsutils@3.21.0(typescript@5.2.2):
1921 | resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
1922 | engines: {node: '>= 6'}
1923 | peerDependencies:
1924 | typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
1925 | dependencies:
1926 | tslib: 1.14.1
1927 | typescript: 5.2.2
1928 | dev: true
1929 |
1930 | /type-check@0.4.0:
1931 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
1932 | engines: {node: '>= 0.8.0'}
1933 | dependencies:
1934 | prelude-ls: 1.2.1
1935 | dev: true
1936 |
1937 | /type-fest@0.20.2:
1938 | resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
1939 | engines: {node: '>=10'}
1940 | dev: true
1941 |
1942 | /typescript@5.2.2:
1943 | resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==}
1944 | engines: {node: '>=14.17'}
1945 | hasBin: true
1946 | dev: true
1947 |
1948 | /undici@5.23.0:
1949 | resolution: {integrity: sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==}
1950 | engines: {node: '>=14.0'}
1951 | dependencies:
1952 | busboy: 1.6.0
1953 | dev: true
1954 |
1955 | /uri-js@4.4.1:
1956 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
1957 | dependencies:
1958 | punycode: 2.3.0
1959 | dev: true
1960 |
1961 | /vite@4.4.9:
1962 | resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==}
1963 | engines: {node: ^14.18.0 || >=16.0.0}
1964 | hasBin: true
1965 | peerDependencies:
1966 | '@types/node': '>= 14'
1967 | less: '*'
1968 | lightningcss: ^1.21.0
1969 | sass: '*'
1970 | stylus: '*'
1971 | sugarss: '*'
1972 | terser: ^5.4.0
1973 | peerDependenciesMeta:
1974 | '@types/node':
1975 | optional: true
1976 | less:
1977 | optional: true
1978 | lightningcss:
1979 | optional: true
1980 | sass:
1981 | optional: true
1982 | stylus:
1983 | optional: true
1984 | sugarss:
1985 | optional: true
1986 | terser:
1987 | optional: true
1988 | dependencies:
1989 | esbuild: 0.18.20
1990 | postcss: 8.4.28
1991 | rollup: 3.28.1
1992 | optionalDependencies:
1993 | fsevents: 2.3.3
1994 | dev: true
1995 |
1996 | /vitefu@0.2.4(vite@4.4.9):
1997 | resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==}
1998 | peerDependencies:
1999 | vite: ^3.0.0 || ^4.0.0
2000 | peerDependenciesMeta:
2001 | vite:
2002 | optional: true
2003 | dependencies:
2004 | vite: 4.4.9
2005 | dev: true
2006 |
2007 | /which@2.0.2:
2008 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
2009 | engines: {node: '>= 8'}
2010 | hasBin: true
2011 | dependencies:
2012 | isexe: 2.0.0
2013 | dev: true
2014 |
2015 | /wrappy@1.0.2:
2016 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
2017 | dev: true
2018 |
2019 | /yallist@4.0.0:
2020 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
2021 |
2022 | /yocto-queue@0.1.0:
2023 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
2024 | engines: {node: '>=10'}
2025 | dev: true
2026 |
--------------------------------------------------------------------------------
/examples/node/src/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/examples/node/src/app.css
--------------------------------------------------------------------------------
/examples/node/src/app.d.ts:
--------------------------------------------------------------------------------
1 | // See https://kit.svelte.dev/docs/types#app
2 | // for information about these interfaces
3 | // and what to do when importing types
4 | declare global {
5 | namespace App {
6 | // interface Error {}
7 | interface Locals {
8 | isUserLoggedIn: boolean;
9 | user: {
10 | email: string;
11 | name: string;
12 | } | null;
13 | }
14 | // interface PageData {}
15 | // interface Platform {}
16 | }
17 | }
18 |
19 | export {};
20 |
--------------------------------------------------------------------------------
/examples/node/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %sveltekit.head%
8 |
9 |
10 | %sveltekit.body%
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/node/src/hooks.server.ts:
--------------------------------------------------------------------------------
1 | import type { Handle } from '@sveltejs/kit';
2 | import { sessionManager } from '$lib/session';
3 | import { redirect } from '@sveltejs/kit';
4 |
5 | export const handle: Handle = async ({ event, resolve }) => {
6 | const userSession = await sessionManager.getSession(await event.cookies);
7 |
8 | event.locals = {
9 | isUserLoggedIn: false,
10 | user: null
11 | };
12 | if (userSession.error) {
13 | await sessionManager.deleteCookie(await event.cookies);
14 | return resolve(event);
15 | }
16 | if (userSession && userSession.data) {
17 | event.locals = {
18 | isUserLoggedIn: true,
19 | user: userSession?.data
20 | };
21 | }
22 | return resolve(event);
23 | };
24 |
--------------------------------------------------------------------------------
/examples/node/src/lib/session.ts:
--------------------------------------------------------------------------------
1 | import {
2 | RedisSessionStore,
3 | type nodeRedisSessionOptions
4 | } from '@ethercorps/sveltekit-redis-session';
5 | import { SECRET, REDIS_URL } from '$env/static/private';
6 | import { createClient } from 'redis';
7 |
8 | const redisClient = createClient({ url: REDIS_URL });
9 | await redisClient.connect();
10 |
11 | const sessionOptions: nodeRedisSessionOptions = {
12 | redisClient: redisClient,
13 | secret: SECRET,
14 | sessionPrefix: 'netlify-node-srs-example-session',
15 | userSessionsPrefix: 'netlify-node-srs-example-user',
16 | cookieName: 'session',
17 | cookiesOptions: {
18 | maxAge: 10 * 60
19 | }
20 | };
21 | export const sessionManager = new RedisSessionStore(sessionOptions);
22 |
--------------------------------------------------------------------------------
/examples/node/src/routes/+layout.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/node/src/routes/+page.server.ts:
--------------------------------------------------------------------------------
1 | import type { Actions } from '@sveltejs/kit';
2 | import { fail } from '@sveltejs/kit';
3 | import { sessionManager } from '$lib/session';
4 | import type { PageServerLoad } from './$types';
5 |
6 | export let ssr = true;
7 | export const load: PageServerLoad = async ({ locals }) => {
8 | return {
9 | user: locals.user,
10 | isAuthenticated: locals.isUserLoggedIn
11 | };
12 | };
13 |
14 | export const actions: Actions = {
15 | default: async ({ request, cookies }) => {
16 | const formData = await request.formData();
17 | if (
18 | formData.get('email') !== 'shivam@example.com' ||
19 | formData.get('password') !== 'Shivam@Meena'
20 | ) {
21 | return fail(400, {
22 | data: Object.fromEntries(formData),
23 | message: 'Check form for errors'
24 | });
25 | }
26 |
27 | const { data, error, message } = await sessionManager.createSession(
28 | cookies,
29 | { email: formData.get('email') },
30 | '1'
31 | );
32 | if (error) {
33 | console.log(message);
34 | return fail(400, {
35 | data: Object.fromEntries(formData),
36 | message
37 | });
38 | }
39 | console.log(data);
40 | return { success: true, message };
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/examples/node/src/routes/+page.svelte:
--------------------------------------------------------------------------------
1 |
52 |
53 |
54 |
55 |
56 | {#if show}
57 |
58 |
59 |
64 |
65 |
66 |
67 |
68 | {#if $page.data.user?.name} {$page.data.user.name} • {/if}
69 | Session is valid for only 10 Mins
70 |
71 |
72 | {#if $page.data.user?.email} {$page.data.user.email} {/if}
73 |
74 |
75 | You are testing for sveltekit redis session manager by ethercorps.
76 |
77 |
78 |
79 |
80 |
83 |
updateCookieData()}
85 | type="button"
86 | class="inline-flex items-center bg-amber-500 px-4 py-2.5 text-center text-sm font-medium text-amber-100 shadow-sm hover:bg-amber-100 hover:text-amber-900 transition easy-in-out duration-500"
87 | >
88 |
96 |
101 |
102 |
103 | Update Cookie Data
104 |
105 |
logoutUser()}
107 | type="button"
108 | class="inline-flex items-center bg-red-500 px-4 py-2.5 text-center text-sm font-medium text-red-100 shadow-sm hover:bg-red-100 hover:text-red-900 transition easy-in-out duration-500"
109 | >
110 |
118 |
123 |
124 | Logout
125 |
126 |
127 |
128 | {:else}
129 |
177 | {/if}
178 |
179 |
180 |
181 |
182 |
190 |
--------------------------------------------------------------------------------
/examples/node/src/routes/api/login/+server.ts:
--------------------------------------------------------------------------------
1 | import { fail, json, redirect, type RequestHandler } from '@sveltejs/kit';
2 | import { sessionManager } from '$lib/session';
3 |
4 | export const POST: RequestHandler = async ({ request, locals, cookies }) => {
5 | if (locals && locals.isUserLoggedIn) {
6 | const { email, password } = await request.json();
7 | if (email !== 'shivam@example.com' || password !== 'Shivam@Meena') {
8 | return fail(400, {
9 | email,
10 | password,
11 | message: 'Invalid credentials'
12 | });
13 | }
14 | const { error, message } = await sessionManager.createSession(
15 | cookies,
16 | {
17 | email
18 | },
19 | '2'
20 | );
21 | if (error) {
22 | return fail(400, {
23 | email,
24 | password,
25 | message
26 | });
27 | }
28 | return json({ success: true, message });
29 | }
30 | throw redirect(302, '/');
31 | };
32 |
--------------------------------------------------------------------------------
/examples/node/src/routes/api/logout/+server.ts:
--------------------------------------------------------------------------------
1 | import { json, redirect } from '@sveltejs/kit';
2 | import type { RequestHandler } from './$types';
3 | import { sessionManager } from '$lib/session';
4 |
5 | export const POST = (async ({ request, locals, cookies }) => {
6 | if (locals && locals.isUserLoggedIn) {
7 | const { email } = await request.json();
8 | const deleteData = await sessionManager.deleteSession(cookies);
9 | if (deleteData.error) await sessionManager.deleteCookie(cookies);
10 | return json({ loggedIn: false, message: 'Successfully logged out' });
11 | }
12 | throw redirect(302, '/');
13 | }) satisfies RequestHandler;
14 |
--------------------------------------------------------------------------------
/examples/node/src/routes/api/updateCookieData/+server.ts:
--------------------------------------------------------------------------------
1 | import type { RequestHandler } from '@sveltejs/kit';
2 | import { fail, json, redirect } from '@sveltejs/kit';
3 | import { sessionManager } from '$lib/session';
4 |
5 | export const POST = (async ({ request, locals, cookies }) => {
6 | if (locals && locals.isUserLoggedIn) {
7 | const additionalData = await request.json();
8 | const newSessionData = { ...locals.user, ...additionalData };
9 | const { data, error, message } = await sessionManager.updateSession(cookies, newSessionData);
10 | if (!error) {
11 | locals.user = newSessionData;
12 | }
13 | return json({
14 | success: !error,
15 | message,
16 | sessionData: await sessionManager.getSession(cookies)
17 | });
18 | }
19 | throw redirect(302, '/');
20 | }) satisfies RequestHandler;
21 |
--------------------------------------------------------------------------------
/examples/node/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/examples/node/static/favicon.png
--------------------------------------------------------------------------------
/examples/node/static/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/node/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from '@sveltejs/adapter-netlify';
2 | import { vitePreprocess } from '@sveltejs/kit/vite';
3 |
4 | /** @type {import('@sveltejs/kit').Config} */
5 | const config = {
6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors
7 | // for more information about preprocessors
8 | preprocess: vitePreprocess(),
9 |
10 | kit: {
11 | adapter: adapter()
12 | }
13 | };
14 |
15 | export default config;
16 |
--------------------------------------------------------------------------------
/examples/node/tests/test.ts:
--------------------------------------------------------------------------------
1 | import { expect, test } from '@playwright/test';
2 |
3 | test('index page has expected h1', async ({ page }) => {
4 | await page.goto('/');
5 | expect(await page.textContent('h1')).toBe('Welcome to SvelteKit');
6 | });
7 |
--------------------------------------------------------------------------------
/examples/node/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "checkJs": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "resolveJsonModule": true,
9 | "skipLibCheck": true,
10 | "sourceMap": true,
11 | "strict": true
12 | }
13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
14 | //
15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
16 | // from the referenced tsconfig.json - TypeScript does not merge them in
17 | }
18 |
--------------------------------------------------------------------------------
/examples/node/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { sveltekit } from '@sveltejs/kit/vite';
2 | import type { UserConfig } from 'vite';
3 |
4 | const config: UserConfig = {
5 | plugins: [sveltekit()]
6 | };
7 |
8 | export default config;
9 |
--------------------------------------------------------------------------------
/examples/upstash/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /dist
5 | /.svelte-kit
6 | /package
7 | .env
8 | .env.*
9 | !.env.example
10 | vite.config.js.timestamp-*
11 | vite.config.ts.timestamp-*
12 | .idea
13 | .netlify
14 |
--------------------------------------------------------------------------------
/examples/upstash/README.md:
--------------------------------------------------------------------------------
1 | # create-svelte
2 |
3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
4 |
5 | ## Creating a project
6 |
7 | If you're seeing this, you've probably already done this step. Congrats!
8 |
9 | ```bash
10 | # create a new project in the current directory
11 | npm create svelte@latest
12 |
13 | # create a new project in my-app
14 | npm create svelte@latest my-app
15 | ```
16 |
17 | ## Developing
18 |
19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
20 |
21 | ```bash
22 | npm run dev
23 |
24 | # or start the server and open the app in a new browser tab
25 | npm run dev -- --open
26 | ```
27 |
28 | ## Building
29 |
30 | To create a production version of your app:
31 |
32 | ```bash
33 | npm run build
34 | ```
35 |
36 | You can preview the production build with `npm run preview`.
37 |
38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
39 |
--------------------------------------------------------------------------------
/examples/upstash/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-netlify",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vite dev --host",
7 | "build": "vite build",
8 | "build:pac": "cd ../.. && pnpm install && pnpm build && cd examples/node && pnpm build",
9 | "preview": "vite preview",
10 | "test": "playwright test",
11 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
13 | "lint": "prettier --plugin-search-dir . --check . && eslint .",
14 | "format": "prettier --plugin-search-dir . --write ."
15 | },
16 | "devDependencies": {
17 | "@playwright/test": "^1.37.1",
18 | "@sveltejs/adapter-netlify": "^2.0.8",
19 | "@sveltejs/kit": "^1.23.0",
20 | "@typescript-eslint/eslint-plugin": "^5.62.0",
21 | "@typescript-eslint/parser": "^5.62.0",
22 | "eslint": "^8.48.0",
23 | "eslint-config-prettier": "^8.10.0",
24 | "eslint-plugin-svelte3": "^4.0.0",
25 | "ioredis": "^5.3.2",
26 | "prettier": "^2.8.8",
27 | "prettier-plugin-svelte": "^2.10.1",
28 | "svelte": "^4.0.0",
29 | "svelte-check": "^3.5.0",
30 | "svelte-french-toast": "^1.2.0",
31 | "tslib": "^2.6.2",
32 | "typescript": "^5.0.0",
33 | "vite": "^4.4.9"
34 | },
35 | "type": "module",
36 | "dependencies": {
37 | "@ethercorps/sveltekit-redis-session": "link:../../",
38 | "@upstash/redis": "^1.25.1",
39 | "redis": "^4.6.10"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/upstash/playwright.config.ts:
--------------------------------------------------------------------------------
1 | import type { PlaywrightTestConfig } from '@playwright/test';
2 |
3 | const config: PlaywrightTestConfig = {
4 | webServer: {
5 | command: 'npm run build && npm run preview',
6 | port: 4173
7 | },
8 | testDir: 'tests'
9 | };
10 |
11 | export default config;
12 |
--------------------------------------------------------------------------------
/examples/upstash/src/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/examples/upstash/src/app.css
--------------------------------------------------------------------------------
/examples/upstash/src/app.d.ts:
--------------------------------------------------------------------------------
1 | // See https://kit.svelte.dev/docs/types#app
2 | // for information about these interfaces
3 | // and what to do when importing types
4 | declare global {
5 | namespace App {
6 | // interface Error {}
7 | interface Locals {
8 | isUserLoggedIn: boolean;
9 | user: {
10 | email: string;
11 | name: string;
12 | } | null;
13 | }
14 | // interface PageData {}
15 | // interface Platform {}
16 | }
17 | }
18 |
19 | export {};
20 |
--------------------------------------------------------------------------------
/examples/upstash/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %sveltekit.head%
8 |
9 |
10 | %sveltekit.body%
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/upstash/src/hooks.server.ts:
--------------------------------------------------------------------------------
1 | import type { Handle } from '@sveltejs/kit';
2 | import { sessionManager } from '$lib/session';
3 | import { redirect } from '@sveltejs/kit';
4 |
5 | export const handle: Handle = async ({ event, resolve }) => {
6 | const userSession = await sessionManager.getSession(await event.cookies);
7 |
8 | event.locals = {
9 | isUserLoggedIn: false,
10 | user: null
11 | };
12 | if (userSession.error) {
13 | await sessionManager.deleteCookie(await event.cookies);
14 | return resolve(event);
15 | }
16 | if (userSession && userSession.data) {
17 | event.locals = {
18 | isUserLoggedIn: true,
19 | user: userSession?.data
20 | };
21 | }
22 | return resolve(event);
23 | };
24 |
--------------------------------------------------------------------------------
/examples/upstash/src/lib/session.ts:
--------------------------------------------------------------------------------
1 | import {
2 | upstashSessionStore,
3 | type upstashRedisSessionOptions
4 | } from '@ethercorps/sveltekit-redis-session';
5 | import { SECRET, REDIS_URL, TOKEN } from '$env/static/private';
6 | import {Redis} from "@upstash/redis"
7 |
8 |
9 | const redisClient = new Redis({
10 | url: REDIS_URL,
11 | token: TOKEN,
12 | });
13 |
14 | const sessionOptions: upstashRedisSessionOptions = {
15 | redisClient: redisClient,
16 | secret: SECRET,
17 | sessionPrefix: 'netlify-node-srs-example-session',
18 | userSessionsPrefix: 'netlify-node-srs-example-user',
19 | cookieName: 'session',
20 | cookiesOptions: {
21 | maxAge: 10 * 60
22 | }
23 | };
24 | export const sessionManager = new upstashSessionStore(sessionOptions);
25 |
--------------------------------------------------------------------------------
/examples/upstash/src/routes/+layout.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/upstash/src/routes/+page.server.ts:
--------------------------------------------------------------------------------
1 | import type { Actions } from '@sveltejs/kit';
2 | import { fail } from '@sveltejs/kit';
3 | import { sessionManager } from '$lib/session';
4 | import type { PageServerLoad } from './$types';
5 |
6 | export let ssr = true;
7 | export const load: PageServerLoad = async ({ locals }) => {
8 | return {
9 | user: locals.user,
10 | isAuthenticated: locals.isUserLoggedIn
11 | };
12 | };
13 |
14 | export const actions: Actions = {
15 | default: async ({ request, cookies }) => {
16 | const formData = await request.formData();
17 | if (
18 | formData.get('email') !== 'shivam@example.com' ||
19 | formData.get('password') !== 'Shivam@Meena'
20 | ) {
21 | return fail(400, {
22 | data: Object.fromEntries(formData),
23 | message: 'Check form for errors'
24 | });
25 | }
26 |
27 | const { data, error, message } = await sessionManager.createSession(
28 | cookies,
29 | { email: formData.get('email') },
30 | '1'
31 | );
32 | if (error) {
33 | console.log(message);
34 | return fail(400, {
35 | data: Object.fromEntries(formData),
36 | message
37 | });
38 | }
39 | console.log(data);
40 | return { success: true, message };
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/examples/upstash/src/routes/+page.svelte:
--------------------------------------------------------------------------------
1 |
52 |
53 |
54 |
55 |
56 | {#if show}
57 |
58 |
59 |
64 |
65 |
66 |
67 |
68 | {#if $page.data.user?.name} {$page.data.user.name} • {/if}
69 | Session is valid for only 10 Mins
70 |
71 |
72 | {#if $page.data.user?.email} {$page.data.user.email} {/if}
73 |
74 |
75 | You are testing for sveltekit redis session manager by ethercorps.
76 |
77 |
78 |
79 |
80 |
83 |
updateCookieData()}
85 | type="button"
86 | class="inline-flex items-center bg-amber-500 px-4 py-2.5 text-center text-sm font-medium text-amber-100 shadow-sm hover:bg-amber-100 hover:text-amber-900 transition easy-in-out duration-500"
87 | >
88 |
96 |
101 |
102 |
103 | Update Cookie Data
104 |
105 |
logoutUser()}
107 | type="button"
108 | class="inline-flex items-center bg-red-500 px-4 py-2.5 text-center text-sm font-medium text-red-100 shadow-sm hover:bg-red-100 hover:text-red-900 transition easy-in-out duration-500"
109 | >
110 |
118 |
123 |
124 | Logout
125 |
126 |
127 |
128 | {:else}
129 |
177 | {/if}
178 |
179 |
180 |
181 |
182 |
190 |
--------------------------------------------------------------------------------
/examples/upstash/src/routes/api/login/+server.ts:
--------------------------------------------------------------------------------
1 | import { fail, json, redirect, type RequestHandler } from '@sveltejs/kit';
2 | import { sessionManager } from '$lib/session';
3 |
4 | export const POST: RequestHandler = async ({ request, locals, cookies }) => {
5 | if (locals && locals.isUserLoggedIn) {
6 | const { email, password } = await request.json();
7 | if (email !== 'shivam@example.com' || password !== 'Shivam@Meena') {
8 | return fail(400, {
9 | email,
10 | password,
11 | message: 'Invalid credentials'
12 | });
13 | }
14 | const { error, message } = await sessionManager.createSession(
15 | cookies,
16 | {
17 | email
18 | },
19 | '2'
20 | );
21 | if (error) {
22 | return fail(400, {
23 | email,
24 | password,
25 | message
26 | });
27 | }
28 | return json({ success: true, message });
29 | }
30 | throw redirect(302, '/');
31 | };
32 |
--------------------------------------------------------------------------------
/examples/upstash/src/routes/api/logout/+server.ts:
--------------------------------------------------------------------------------
1 | import { json, redirect } from '@sveltejs/kit';
2 | import type { RequestHandler } from './$types';
3 | import { sessionManager } from '$lib/session';
4 |
5 | export const POST = (async ({ request, locals, cookies }) => {
6 | if (locals && locals.isUserLoggedIn) {
7 | const { email } = await request.json();
8 | const deleteData = await sessionManager.deleteSession(cookies);
9 | if (deleteData.error) await sessionManager.deleteCookie(cookies);
10 | return json({ loggedIn: false, message: 'Successfully logged out' });
11 | }
12 | throw redirect(302, '/');
13 | }) satisfies RequestHandler;
14 |
--------------------------------------------------------------------------------
/examples/upstash/src/routes/api/updateCookieData/+server.ts:
--------------------------------------------------------------------------------
1 | import type { RequestHandler } from '@sveltejs/kit';
2 | import { fail, json, redirect } from '@sveltejs/kit';
3 | import { sessionManager } from '$lib/session';
4 |
5 | export const POST = (async ({ request, locals, cookies }) => {
6 | if (locals && locals.isUserLoggedIn) {
7 | const additionalData = await request.json();
8 | const newSessionData = { ...locals.user, ...additionalData };
9 | const { data, error, message } = await sessionManager.updateSession(cookies, newSessionData);
10 | if (!error) {
11 | locals.user = newSessionData;
12 | }
13 | return json({
14 | success: !error,
15 | message,
16 | sessionData: await sessionManager.getSession(cookies)
17 | });
18 | }
19 | throw redirect(302, '/');
20 | }) satisfies RequestHandler;
21 |
--------------------------------------------------------------------------------
/examples/upstash/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/examples/upstash/static/favicon.png
--------------------------------------------------------------------------------
/examples/upstash/static/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/upstash/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from '@sveltejs/adapter-netlify';
2 | import { vitePreprocess } from '@sveltejs/kit/vite';
3 |
4 | /** @type {import('@sveltejs/kit').Config} */
5 | const config = {
6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors
7 | // for more information about preprocessors
8 | preprocess: vitePreprocess(),
9 |
10 | kit: {
11 | adapter: adapter()
12 | }
13 | };
14 |
15 | export default config;
16 |
--------------------------------------------------------------------------------
/examples/upstash/tests/test.ts:
--------------------------------------------------------------------------------
1 | import { expect, test } from '@playwright/test';
2 |
3 | test('index page has expected h1', async ({ page }) => {
4 | await page.goto('/');
5 | expect(await page.textContent('h1')).toBe('Welcome to SvelteKit');
6 | });
7 |
--------------------------------------------------------------------------------
/examples/upstash/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "checkJs": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "resolveJsonModule": true,
9 | "skipLibCheck": true,
10 | "sourceMap": true,
11 | "strict": true
12 | }
13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
14 | //
15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
16 | // from the referenced tsconfig.json - TypeScript does not merge them in
17 | }
18 |
--------------------------------------------------------------------------------
/examples/upstash/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { sveltekit } from '@sveltejs/kit/vite';
2 | import type { UserConfig } from 'vite';
3 |
4 | const config: UserConfig = {
5 | plugins: [sveltekit()]
6 | };
7 |
8 | export default config;
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@ethercorps/sveltekit-redis-session",
3 | "version": "1.3.1",
4 | "private": false,
5 | "description": "A library which uses svelte compiler to convert html & css to jsx. Useful for using satori with svelte & Kit",
6 | "homepage": "https://github.com/etherCorps/SK-Redis-SessionManager#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/etherCorps/SK-Redis-SessionManager"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/etherCorps/SK-Redis-SessionManager/issues"
13 | },
14 | "author": [
15 | {
16 | "name": "Shivam Meena",
17 | "email": "shivam@theether.in",
18 | "url": "https://twitter.com/theether0"
19 | }
20 | ],
21 | "license": "MIT",
22 | "keywords": [
23 | "SvelteKit",
24 | "Redis",
25 | "Session",
26 | "SvelteKit Redis",
27 | "SvelteKit Session",
28 | "SvelteKit Redis Session Manager",
29 | "Redis Session SvelteKit Adapter",
30 | "SvelteKit Authentication Redis"
31 | ],
32 | "scripts": {
33 | "dev": "vite dev",
34 | "build": "vite build && npm run package",
35 | "preview": "vite preview",
36 | "package": "svelte-kit sync && svelte-package && publint",
37 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
38 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
39 | "test": "vitest",
40 | "lint": "prettier --plugin-search-dir . --check . && eslint .",
41 | "format": "prettier --plugin-search-dir . --write ."
42 | },
43 | "exports": {
44 | ".": {
45 | "types": "./dist/index.d.ts",
46 | "svelte": "./dist/index.js"
47 | }
48 | },
49 | "files": [
50 | "dist"
51 | ],
52 | "peerDependencies": {
53 | "@sveltejs/kit": "^1.23.0 || ^2.0.0",
54 | "@upstash/redis": "^1.22.0",
55 | "ioredis": "^5.3.2",
56 | "redis": "^4.6.8"
57 | },
58 | "devDependencies": {
59 | "@sveltejs/kit": "^2.5.18",
60 | "@sveltejs/adapter-auto": "^3.2.2",
61 | "@sveltejs/package": "^2.3.2",
62 | "@sveltejs/vite-plugin-svelte": "^3.1.1",
63 | "@typescript-eslint/eslint-plugin": "^5.62.0",
64 | "@typescript-eslint/parser": "^5.62.0",
65 | "@upstash/redis": "^1.31.6",
66 | "eslint": "^8.57.0",
67 | "eslint-config-prettier": "^8.10.0",
68 | "eslint-plugin-svelte": "^2.41.0",
69 | "ioredis": "^5.4.1",
70 | "prettier": "^2.8.8",
71 | "prettier-plugin-svelte": "^2.10.1",
72 | "publint": "^0.1.16",
73 | "redis": "^4.6.14",
74 | "svelte": "^4.2.18",
75 | "svelte-check": "^3.8.4",
76 | "tslib": "^2.6.3",
77 | "typescript": "^5.5.2",
78 | "vite": "^5.3.2",
79 | "vitest": "^0.34.6"
80 | },
81 | "types": "./dist/index.d.ts",
82 | "type": "module",
83 | "peerDependenciesMeta": {
84 | "redis": {
85 | "optional": true
86 | },
87 | "@upstash/redis": {
88 | "optional": true
89 | },
90 | "ioredis": {
91 | "optional": true
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/app.d.ts:
--------------------------------------------------------------------------------
1 | // See https://kit.svelte.dev/docs/types#app
2 | // for information about these interfaces
3 | declare global {
4 | namespace App {
5 | // interface Error {}
6 | // interface Locals {}
7 | // interface PageData {}
8 | // interface Platform {}
9 | }
10 | }
11 |
12 | export {};
13 |
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %sveltekit.head%
8 |
9 |
10 | %sveltekit.body%
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/index.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, it, expect } from 'vitest';
2 |
3 | describe('sum test', () => {
4 | it('adds 1 + 2 to equal 3', () => {
5 | expect(1 + 2).toBe(3);
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | export { IoRedisSessionStore } from './providers/ioredis.js';
2 | export { RedisSessionStore } from './providers/redis.js';
3 | export { upstashSessionStore } from './providers/upstash.js';
4 | export type {
5 | ioRedisSessionOptions,
6 | nodeRedisSessionOptions,
7 | upstashRedisSessionOptions,
8 | CookieSerializeOptions
9 | } from './shared.js';
10 |
--------------------------------------------------------------------------------
/src/lib/providers/ioredis.ts:
--------------------------------------------------------------------------------
1 | import type { Redis } from 'ioredis';
2 | import type { CookieSerializeOptions, ioRedisSessionOptions, Serializer } from '$lib/shared.js';
3 | import {
4 | defaultCookiesOption,
5 | defaultRenewBeforeSeconds,
6 | formattedReturn,
7 | generateRandomString,
8 | getSessionKey,
9 | getUserSessionKey,
10 | signSessionKey,
11 | validateCookie
12 | } from '$lib/shared.js';
13 | import type { Cookies } from '@sveltejs/kit';
14 |
15 | export class IoRedisSessionStore {
16 | private readonly redisClient: Redis;
17 | private readonly secret: string;
18 | private readonly cookieName: string;
19 | private readonly uniqueIdGenerator = generateRandomString;
20 | private readonly sessionPrefix: string;
21 | private readonly userSessionsPrefix: string;
22 | private readonly signedCookies: boolean;
23 | private readonly useTTL: boolean;
24 | private readonly ttlSeconds: number | undefined;
25 | private readonly renewSessionBeforeExpire: boolean;
26 | private readonly renewBeforeSeconds: number;
27 | private readonly serializer: Serializer;
28 | private readonly cookieOptions: CookieSerializeOptions;
29 |
30 | constructor({
31 | redisClient,
32 | secret,
33 | cookieName = 'session',
34 | sessionPrefix = 'sk_ioredis_session',
35 | userSessionsPrefix = 'sk_ioredis_user_sessions',
36 | signed = true,
37 | useTTL = true,
38 | renewSessionBeforeExpire = false,
39 | renewBeforeSeconds = defaultRenewBeforeSeconds,
40 | serializer = JSON,
41 | cookiesOptions = {}
42 | }: ioRedisSessionOptions) {
43 | if (!redisClient) {
44 | throw new Error('A pre-initiated redis client must be provided to the RedisStore');
45 | }
46 |
47 | redisClient.on('connect', () => {
48 | console.log('Connected to Redis');
49 | });
50 |
51 | redisClient.on('error', (error: any) => {
52 | console.error(`Error connecting to Redis: ${error}`);
53 | throw new Error('Unable to connect with RedisClient');
54 | });
55 | if (cookiesOptions && cookiesOptions.maxAge && cookiesOptions.maxAge < 1) {
56 | console.log('Please define a valid time in cookies maxAge parameter');
57 | throw new Error('Invalid maxAge in cookies options');
58 | }
59 |
60 | if (renewSessionBeforeExpire && renewBeforeSeconds && renewBeforeSeconds < 1) {
61 | console.log('Please define a valid time in renewBeforeSeconds');
62 | throw new Error('Invalid renewBeforeSeconds in options');
63 | }
64 | this.redisClient = redisClient;
65 | this.secret = secret;
66 | this.cookieName = cookieName;
67 | this.uniqueIdGenerator = generateRandomString;
68 | this.sessionPrefix = sessionPrefix;
69 | this.userSessionsPrefix = userSessionsPrefix;
70 | this.signedCookies = signed;
71 | this.useTTL = useTTL;
72 | this.renewSessionBeforeExpire = renewSessionBeforeExpire || false;
73 | this.renewBeforeSeconds = renewBeforeSeconds || defaultRenewBeforeSeconds;
74 | this.serializer = serializer || JSON;
75 | this.cookieOptions = { ...defaultCookiesOption, ...cookiesOptions };
76 | this.ttlSeconds = this.cookieOptions.maxAge;
77 | }
78 | createSession = async (
79 | cookies: Cookies,
80 | sessionData: any,
81 | userId: string
82 | ): Promise<{ data: any; error: boolean; message: string }> => {
83 | let sessionKey = this.uniqueIdGenerator();
84 |
85 | let serializedSessionData;
86 | try {
87 | serializedSessionData = this.serializer.stringify(sessionData);
88 | } catch (er) {
89 | console.log('Error in Set Session while serializing', er);
90 | return formattedReturn(null, true, 'Unable to stringify session data.');
91 | }
92 |
93 | const prefixedSessionKey = getSessionKey(this.sessionPrefix, sessionKey);
94 | const redisPipeline = this.redisClient.pipeline();
95 | redisPipeline.set(prefixedSessionKey, serializedSessionData);
96 | redisPipeline.sadd(getUserSessionKey(this.userSessionsPrefix, userId), sessionKey);
97 | if (this.useTTL && this.ttlSeconds) {
98 | redisPipeline.expire(prefixedSessionKey, this.ttlSeconds);
99 | }
100 | await redisPipeline.exec();
101 | if (this.signedCookies) {
102 | sessionKey = await signSessionKey(sessionKey, this.secret);
103 | }
104 | cookies.set(this.cookieName, sessionKey, this.cookieOptions);
105 | return formattedReturn(sessionKey, false, 'Successfully created new session.');
106 | };
107 |
108 | getSession = async (cookies: Cookies) => {
109 | const {
110 | data: sessionId,
111 | error,
112 | message
113 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
114 | if (error) return formattedReturn(sessionId, error, message);
115 | const sessionData = await this.redisClient.get(getSessionKey(this.sessionPrefix, sessionId));
116 |
117 | if (!sessionData)
118 | return formattedReturn(null, true, `Unable to find data for the provided key - ${sessionId}`);
119 |
120 | let parsedSession;
121 | try {
122 | parsedSession = this.serializer.parse(sessionData);
123 | } catch (err) {
124 | console.log(err);
125 | return formattedReturn(null, true, 'Unable to parse the session data.');
126 | }
127 |
128 | if (this.renewSessionBeforeExpire) {
129 | const sessionValidity = await this.redisClient.ttl(
130 | getSessionKey(this.sessionPrefix, sessionId)
131 | );
132 | if (sessionValidity < this.renewBeforeSeconds && this.ttlSeconds) {
133 | const { error, message } = await this.updateSessionExpiry(cookies, true, sessionId);
134 | if (error) {
135 | console.log(message);
136 | }
137 | }
138 | }
139 | return formattedReturn(parsedSession, false, 'Session Data'); // return session data
140 | };
141 |
142 | // From lucia auth & made my own changes
143 | getSessionsByUserId = async (userId: string) => {
144 | const sessionIds = await this.redisClient.smembers(
145 | getUserSessionKey(this.userSessionsPrefix, userId)
146 | );
147 | if (!sessionIds)
148 | return formattedReturn(null, true, `Unable to find session for user: ${userId}.`);
149 | const sessionData = await Promise.all(
150 | sessionIds.map((sessionId) =>
151 | this.redisClient.get(getSessionKey(this.sessionPrefix, sessionId))
152 | )
153 | );
154 | const sessions = sessionData
155 | .filter((val): val is string => val !== null)
156 | .map((val) => this.serializer.parse(val) as any);
157 | return formattedReturn(
158 | sessions,
159 | false,
160 | `We found ${sessionData.length} active session for user: ${userId}`
161 | );
162 | };
163 | // till here
164 |
165 | deleteSession = async (cookies: Cookies, userId = null) => {
166 | const {
167 | data: sessionId,
168 | error,
169 | message
170 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
171 | if (error) {
172 | console.log('Error in delSession method', message);
173 | return formattedReturn(sessionId, error, 'Unable to validate key while deleting');
174 | }
175 | const prefixedSessionKey = getSessionKey(this.sessionPrefix, sessionId);
176 | const sessionData = await this.redisClient.get(prefixedSessionKey);
177 | if (!sessionData) return formattedReturn(sessionId, true, `Not a valid session key`);
178 |
179 | if (userId) {
180 | const redisPipeline = this.redisClient.pipeline();
181 | redisPipeline.del(prefixedSessionKey);
182 | redisPipeline.srem(getUserSessionKey(this.userSessionsPrefix, userId), sessionId);
183 | await redisPipeline.exec();
184 | } else {
185 | await this.redisClient.del(prefixedSessionKey);
186 | }
187 |
188 | await this.deleteCookie(cookies);
189 | return formattedReturn(sessionId, false, `Key successfully deleted`); // Returns unique key without prefix which is deleted from redis
190 | };
191 |
192 | deleteSessionsByUserId = async (userId: string) => {
193 | const sessionIds = await this.redisClient.smembers(
194 | getUserSessionKey(this.userSessionsPrefix, userId)
195 | );
196 | if (!sessionIds)
197 | return formattedReturn(null, true, `Unable to find session for user: ${userId}.`);
198 | await Promise.all([
199 | ...sessionIds.map((sessionId) =>
200 | this.redisClient.del(getSessionKey(this.sessionPrefix, sessionId))
201 | ),
202 | this.redisClient.del(getUserSessionKey(this.userSessionsPrefix, userId))
203 | ]);
204 | return formattedReturn(userId, false, `Successfully deleted`); // Returns userId without prefix which is deleted from redis
205 | };
206 |
207 | deleteCookie = async (cookies: Cookies) => {
208 | const allCookieOptionsCopy = { ...this.cookieOptions };
209 | delete allCookieOptionsCopy.maxAge;
210 | try {
211 | cookies.delete(this.cookieName, allCookieOptionsCopy);
212 | } catch (err) {
213 | console.log('error while deleting cookies in deleteCookie method', err);
214 | }
215 | };
216 |
217 | async updateSession(
218 | cookies: Cookies,
219 | sessionData = {}
220 | ): Promise<{ data: any; error: boolean; message: string }> {
221 | const {
222 | data: sessionId,
223 | error,
224 | message
225 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
226 | if (error) {
227 | console.log('Error in updateSessionExpiry method', message);
228 | return formattedReturn(sessionId, error, 'Unable to validate key while updating session');
229 | }
230 | const keyWithPrefix = getSessionKey(this.sessionPrefix, sessionId);
231 | let serializedSessionData;
232 | try {
233 | serializedSessionData = this.serializer.stringify(sessionData);
234 | } catch (er) {
235 | console.log('Error in Set Session while serializing', er);
236 | return formattedReturn(null, true, 'Unable to stringify session data.');
237 | }
238 | const redisPipe = this.redisClient.pipeline();
239 | redisPipe.set(keyWithPrefix, serializedSessionData);
240 | if (this.useTTL && this.ttlSeconds) {
241 | redisPipe.expire(keyWithPrefix, this.ttlSeconds);
242 | }
243 | await redisPipe.exec();
244 | return formattedReturn(sessionId, false, 'Cookie data has been updated');
245 | }
246 |
247 | updateSessionExpiry = async (
248 | cookies: Cookies,
249 | skipValidation = false,
250 | key = ''
251 | ): Promise<{ data: any; error: boolean; message: string }> => {
252 | let uniqueKey = key;
253 | if (!skipValidation) {
254 | const {
255 | data: sessionKey,
256 | error,
257 | message
258 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
259 | if (error) {
260 | console.log('Error in updateSessionExpiry method', message);
261 | return formattedReturn(sessionKey, error, 'Unable to validate key while updating session');
262 | }
263 | uniqueKey = sessionKey;
264 | }
265 | let isExpireTimeUpdated = 1;
266 | if (this.useTTL && this.ttlSeconds) {
267 | isExpireTimeUpdated = await this.redisClient.expire(
268 | getSessionKey(this.sessionPrefix, uniqueKey),
269 | this.ttlSeconds as number
270 | );
271 | }
272 | if (isExpireTimeUpdated) {
273 | if (this.signedCookies) uniqueKey = await signSessionKey(uniqueKey, this.secret);
274 | cookies.set(this.cookieName, uniqueKey, this.cookieOptions);
275 | return formattedReturn(uniqueKey, false, 'Session validity extended successfully');
276 | }
277 | return formattedReturn(null, true, 'Unable to extended session validity');
278 | };
279 | }
280 |
--------------------------------------------------------------------------------
/src/lib/providers/redis.ts:
--------------------------------------------------------------------------------
1 | import type { RedisClientType } from 'redis';
2 | import type { CookieSerializeOptions, nodeRedisSessionOptions, Serializer } from '$lib/shared.js';
3 | import {
4 | defaultCookiesOption,
5 | defaultRenewBeforeSeconds,
6 | formattedReturn,
7 | generateRandomString,
8 | getSessionKey,
9 | getUserSessionKey,
10 | signSessionKey,
11 | validateCookie
12 | } from '$lib/shared.js';
13 | import type { Cookies } from '@sveltejs/kit';
14 |
15 | export class RedisSessionStore {
16 | private readonly redisClient: RedisClientType;
17 | private readonly secret: string;
18 | private readonly cookieName: string;
19 | private readonly uniqueIdGenerator = generateRandomString;
20 | private readonly sessionPrefix: string;
21 | private readonly userSessionsPrefix: string;
22 | private readonly signedCookies: boolean;
23 | private readonly useTTL: boolean;
24 | private readonly ttlSeconds: number | undefined;
25 | private readonly renewSessionBeforeExpire: boolean;
26 | private readonly renewBeforeSeconds: number;
27 | private readonly serializer: Serializer;
28 | private readonly cookieOptions: CookieSerializeOptions;
29 |
30 | constructor({
31 | redisClient,
32 | secret,
33 | cookieName = 'session',
34 | sessionPrefix = 'sk_ioredis_session',
35 | userSessionsPrefix = 'sk_ioredis_user_sessions',
36 | signed = true,
37 | useTTL = true,
38 | renewSessionBeforeExpire = false,
39 | renewBeforeSeconds = defaultRenewBeforeSeconds,
40 | serializer = JSON,
41 | cookiesOptions = {}
42 | }: nodeRedisSessionOptions) {
43 | if (!redisClient) {
44 | throw new Error('A pre-initiated redis client must be provided to the RedisStore');
45 | }
46 |
47 | redisClient.on('connect', () => {
48 | console.log('Connected to Redis');
49 | });
50 |
51 | redisClient.on('error', (error: any) => {
52 | console.error(`Error connecting to Redis: ${error}`);
53 | throw new Error('Unable to connect with RedisClient');
54 | });
55 | if (cookiesOptions && cookiesOptions.maxAge && cookiesOptions.maxAge < 1) {
56 | console.log('Please define a valid time in cookies maxAge parameter');
57 | throw new Error('Invalid maxAge in cookies options');
58 | }
59 |
60 | if (renewSessionBeforeExpire && renewBeforeSeconds && renewBeforeSeconds < 1) {
61 | console.log('Please define a valid time in renewBeforeSeconds');
62 | throw new Error('Invalid renewBeforeSeconds in options');
63 | }
64 | this.redisClient = redisClient;
65 | this.secret = secret;
66 | this.cookieName = cookieName;
67 | this.uniqueIdGenerator = generateRandomString;
68 | this.sessionPrefix = sessionPrefix;
69 | this.userSessionsPrefix = userSessionsPrefix;
70 | this.signedCookies = signed;
71 | this.useTTL = useTTL;
72 | this.renewSessionBeforeExpire = renewSessionBeforeExpire || false;
73 | this.renewBeforeSeconds = renewBeforeSeconds || defaultRenewBeforeSeconds;
74 | this.serializer = serializer || JSON;
75 | this.cookieOptions = { ...defaultCookiesOption, ...cookiesOptions };
76 | this.ttlSeconds = this.cookieOptions.maxAge;
77 | }
78 | createSession = async (
79 | cookies: Cookies,
80 | sessionData: any,
81 | userId: string
82 | ): Promise<{ data: any; error: boolean; message: string }> => {
83 | let sessionKey = this.uniqueIdGenerator();
84 |
85 | let serializedSessionData;
86 | try {
87 | serializedSessionData = this.serializer.stringify(sessionData);
88 | } catch (er) {
89 | console.log('Error in Set Session while serializing', er);
90 | return formattedReturn(null, true, 'Unable to stringify session data.');
91 | }
92 | const prefixedSessionKey = getSessionKey(this.sessionPrefix, sessionKey);
93 | await Promise.all([
94 | this.redisClient.set(prefixedSessionKey, serializedSessionData, serializedSessionData),
95 | this.redisClient.sAdd(getUserSessionKey(this.userSessionsPrefix, userId), sessionKey)
96 | ]);
97 | if (this.useTTL && this.ttlSeconds) {
98 | await this.redisClient.expire(prefixedSessionKey, this.ttlSeconds);
99 | }
100 | if (this.signedCookies) {
101 | sessionKey = await signSessionKey(sessionKey, this.secret);
102 | }
103 | cookies.set(this.cookieName, sessionKey, this.cookieOptions);
104 | return formattedReturn(sessionKey, false, 'Successfully created new session.');
105 | };
106 |
107 | getSession = async (cookies: Cookies) => {
108 | const {
109 | data: sessionId,
110 | error,
111 | message
112 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
113 | if (error) return formattedReturn(sessionId, error, message);
114 | const sessionData = await this.redisClient.get(getSessionKey(this.sessionPrefix, sessionId));
115 | if (!sessionData)
116 | return formattedReturn(null, true, `Unable to find data for the provided key - ${sessionId}`);
117 | let parsedSession;
118 | try {
119 | parsedSession = this.serializer.parse(sessionData);
120 | } catch (err) {
121 | console.log(err);
122 | return formattedReturn(null, true, 'Unable to parse the session data.');
123 | }
124 |
125 | if (this.renewSessionBeforeExpire) {
126 | const sessionValidity = await this.redisClient.ttl(
127 | getSessionKey(this.sessionPrefix, sessionId)
128 | );
129 | if (sessionValidity < this.renewBeforeSeconds && this.ttlSeconds) {
130 | const { error, message } = await this.updateSessionExpiry(cookies, true, sessionId);
131 | if (error) {
132 | console.log(message);
133 | }
134 | }
135 | }
136 | return formattedReturn(parsedSession, false, 'Session Data'); // return session data
137 | };
138 |
139 | // From lucia auth & made my own changes
140 | getSessionsByUserId = async (userId: string) => {
141 | const sessionIds = await this.redisClient.sMembers(
142 | getUserSessionKey(this.userSessionsPrefix, userId)
143 | );
144 | if (!sessionIds)
145 | return formattedReturn(null, true, `Unable to find session for user: ${userId}.`);
146 | const sessionData = await Promise.all(
147 | sessionIds.map((sessionId) =>
148 | this.redisClient.get(getSessionKey(this.sessionPrefix, sessionId))
149 | )
150 | );
151 | const sessions = sessionData
152 | .filter((val): val is string => val !== null)
153 | .map((val) => this.serializer.parse(val) as any);
154 | return formattedReturn(
155 | sessions,
156 | false,
157 | `We found ${sessionData.length} active session for user: ${userId}`
158 | );
159 | };
160 | // till here
161 |
162 | deleteSession = async (cookies: Cookies, userId = null) => {
163 | const {
164 | data: sessionId,
165 | error,
166 | message
167 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
168 | if (error) {
169 | console.log('Error in delSession method', message);
170 | return formattedReturn(sessionId, error, 'Unable to validate key while deleting');
171 | }
172 |
173 | const prefixedSessionKey = getSessionKey(this.sessionPrefix, sessionId);
174 | const sessionData = await this.redisClient.get(prefixedSessionKey);
175 | if (!sessionData) return formattedReturn(sessionId, true, `Not a valid session key`);
176 |
177 | if (userId) {
178 | await Promise.all([
179 | this.redisClient.del(prefixedSessionKey),
180 | this.redisClient.sRem(getUserSessionKey(this.userSessionsPrefix, userId), sessionId)
181 | ]);
182 | } else {
183 | await this.redisClient.del(prefixedSessionKey);
184 | }
185 | await this.deleteCookie(cookies);
186 | return formattedReturn(sessionId, false, `Key successfully deleted`); // Returns unique key without prefix which is deleted from redis
187 | };
188 |
189 | deleteSessionsByUserId = async (userId: string) => {
190 | const sessionIds = await this.redisClient.sMembers(
191 | getUserSessionKey(this.userSessionsPrefix, userId)
192 | );
193 | if (!sessionIds)
194 | return formattedReturn(null, true, `Unable to find session for user: ${userId}.`);
195 | await Promise.all([
196 | ...sessionIds.map((sessionId) =>
197 | this.redisClient.del(getSessionKey(this.sessionPrefix, sessionId))
198 | ),
199 | this.redisClient.del(getUserSessionKey(this.userSessionsPrefix, userId))
200 | ]);
201 | return formattedReturn(userId, false, `Successfully deleted`); // Returns userId without prefix which is deleted from redis
202 | };
203 |
204 | deleteCookie = async (cookies: Cookies) => {
205 | const allCookieOptionsCopy = { ...this.cookieOptions };
206 | delete allCookieOptionsCopy.maxAge;
207 | try {
208 | cookies.delete(this.cookieName, allCookieOptionsCopy);
209 | } catch (err) {
210 | console.log('error while deleting cookies in deleteCookie method', err);
211 | }
212 | };
213 |
214 | async updateSession(
215 | cookies: Cookies,
216 | sessionData = {}
217 | ): Promise<{ data: any; error: boolean; message: string }> {
218 | const {
219 | data: sessionId,
220 | error,
221 | message
222 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
223 | if (error) {
224 | console.log('Error in updateSessionExpiry method', message);
225 | return formattedReturn(sessionId, error, 'Unable to validate key while updating session');
226 | }
227 | const keyWithPrefix = getSessionKey(this.sessionPrefix, sessionId);
228 | let serializedSessionData;
229 | try {
230 | serializedSessionData = this.serializer.stringify(sessionData);
231 | } catch (er) {
232 | console.log('Error in Set Session while serializing', er);
233 | return formattedReturn(null, true, 'Unable to stringify session data.');
234 | }
235 | await this.redisClient.set(keyWithPrefix, serializedSessionData);
236 | if (this.useTTL && this.ttlSeconds) {
237 | await this.redisClient.expire(keyWithPrefix, this.ttlSeconds);
238 | }
239 | return formattedReturn(sessionId, false, 'Cookie data has been updated');
240 | }
241 |
242 | updateSessionExpiry = async (
243 | cookies: Cookies,
244 | skipValidation = false,
245 | key = ''
246 | ): Promise<{ data: any; error: boolean; message: string }> => {
247 | let uniqueKey = key;
248 | if (!skipValidation) {
249 | const {
250 | data: sessionKey,
251 | error,
252 | message
253 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
254 | if (error) {
255 | console.log('Error in updateSessionExpiry method', message);
256 | return formattedReturn(sessionKey, error, 'Unable to validate key while updating session');
257 | }
258 | uniqueKey = sessionKey;
259 | }
260 | let isExpireTimeUpdated = true;
261 | if (this.useTTL && this.ttlSeconds) {
262 | isExpireTimeUpdated = await this.redisClient.expire(
263 | getSessionKey(this.sessionPrefix, uniqueKey),
264 | this.ttlSeconds as number
265 | );
266 | }
267 | if (isExpireTimeUpdated) {
268 | if (this.signedCookies) uniqueKey = await signSessionKey(uniqueKey, this.secret);
269 | cookies.set(this.cookieName, uniqueKey, this.cookieOptions);
270 | return formattedReturn(uniqueKey, false, 'Session validity extended successfully');
271 | }
272 | return formattedReturn(null, true, 'Unable to extended session validity');
273 | };
274 | }
275 |
--------------------------------------------------------------------------------
/src/lib/providers/upstash.ts:
--------------------------------------------------------------------------------
1 | import type { Redis } from '@upstash/redis';
2 | import type {
3 | CookieSerializeOptions,
4 | upstashRedisSessionOptions,
5 | Serializer
6 | } from '$lib/shared.js';
7 | import {
8 | defaultCookiesOption,
9 | defaultRenewBeforeSeconds,
10 | formattedReturn,
11 | generateRandomString,
12 | getSessionKey,
13 | getUserSessionKey,
14 | signSessionKey,
15 | validateCookie
16 | } from '$lib/shared.js';
17 | import type { Cookies } from '@sveltejs/kit';
18 |
19 | export class upstashSessionStore {
20 | private readonly redisClient: Redis;
21 | private readonly secret: string;
22 | private readonly cookieName: string;
23 | private readonly uniqueIdGenerator = generateRandomString;
24 | private readonly sessionPrefix: string;
25 | private readonly userSessionsPrefix: string;
26 | private readonly signedCookies: boolean;
27 | private readonly useTTL: boolean;
28 | private readonly ttlSeconds: number | undefined;
29 | private readonly renewSessionBeforeExpire: boolean;
30 | private readonly renewBeforeSeconds: number;
31 | private readonly serializer: Serializer;
32 | private readonly cookieOptions: CookieSerializeOptions;
33 |
34 | constructor({
35 | redisClient,
36 | secret,
37 | cookieName = 'session',
38 | sessionPrefix = 'sk_ioredis_session',
39 | userSessionsPrefix = 'sk_ioredis_user_sessions',
40 | signed = true,
41 | useTTL = true,
42 | renewSessionBeforeExpire = false,
43 | renewBeforeSeconds = defaultRenewBeforeSeconds,
44 | serializer = JSON,
45 | cookiesOptions = {}
46 | }: upstashRedisSessionOptions) {
47 | if (!redisClient) {
48 | throw new Error('A pre-initiated redis client must be provided to the RedisStore');
49 | }
50 |
51 | if (cookiesOptions && cookiesOptions.maxAge && cookiesOptions.maxAge < 1) {
52 | console.log('Please define a valid time in cookies maxAge parameter');
53 | throw new Error('Invalid maxAge in cookies options');
54 | }
55 |
56 | if (renewSessionBeforeExpire && renewBeforeSeconds && renewBeforeSeconds < 1) {
57 | console.log('Please define a valid time in renewBeforeSeconds');
58 | throw new Error('Invalid renewBeforeSeconds in options');
59 | }
60 | this.redisClient = redisClient;
61 | this.secret = secret;
62 | this.cookieName = cookieName;
63 | this.uniqueIdGenerator = generateRandomString;
64 | this.sessionPrefix = sessionPrefix;
65 | this.userSessionsPrefix = userSessionsPrefix;
66 | this.signedCookies = signed;
67 | this.useTTL = useTTL;
68 | this.renewSessionBeforeExpire = renewSessionBeforeExpire || false;
69 | this.renewBeforeSeconds = renewBeforeSeconds || defaultRenewBeforeSeconds;
70 | this.serializer = serializer || JSON;
71 | this.cookieOptions = { ...defaultCookiesOption, ...cookiesOptions };
72 | this.ttlSeconds = this.cookieOptions.maxAge;
73 | }
74 | createSession = async (
75 | cookies: Cookies,
76 | sessionData: any,
77 | userId: string
78 | ): Promise<{ data: any; error: boolean; message: string }> => {
79 | let sessionKey = this.uniqueIdGenerator();
80 |
81 | let serializedSessionData;
82 | try {
83 | serializedSessionData = this.serializer.stringify(sessionData);
84 | } catch (er) {
85 | console.log('Error in Set Session while serializing', er);
86 | return formattedReturn(null, true, 'Unable to stringify session data.');
87 | }
88 | const prefixedSessionKey = getSessionKey(this.sessionPrefix, sessionKey);
89 |
90 | const redisPipeline = this.redisClient.pipeline();
91 | redisPipeline.set(prefixedSessionKey, serializedSessionData);
92 | redisPipeline.sadd(getUserSessionKey(this.userSessionsPrefix, userId), sessionKey);
93 | if (this.useTTL && this.ttlSeconds) {
94 | redisPipeline.expire(prefixedSessionKey, this.ttlSeconds);
95 | }
96 | await redisPipeline.exec();
97 |
98 | if (this.signedCookies) {
99 | sessionKey = await signSessionKey(sessionKey, this.secret);
100 | }
101 | cookies.set(this.cookieName, sessionKey, this.cookieOptions);
102 | return formattedReturn(sessionKey, false, 'Successfully created new session.');
103 | };
104 |
105 | getSession = async (cookies: Cookies) => {
106 | const {
107 | data: sessionId,
108 | error,
109 | message
110 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
111 | if (error) return formattedReturn(sessionId, error, message);
112 | const sessionData = await this.redisClient.get(getSessionKey(this.sessionPrefix, sessionId));
113 | if (!sessionData)
114 | return formattedReturn(null, true, `Unable to find data for the provided key - ${sessionId}`);
115 |
116 | if (this.renewSessionBeforeExpire) {
117 | const sessionValidity = await this.redisClient.ttl(
118 | getSessionKey(this.sessionPrefix, sessionId)
119 | );
120 | if (sessionValidity < this.renewBeforeSeconds && this.ttlSeconds) {
121 | const { error, message } = await this.updateSessionExpiry(cookies, true, sessionId);
122 | if (error) {
123 | console.log(message);
124 | }
125 | }
126 | }
127 | return formattedReturn(sessionData, false, 'Session Data'); // return session data
128 | };
129 |
130 | // From lucia auth & made my own changes
131 | getSessionsByUserId = async (userId: string) => {
132 | const sessionIds = await this.redisClient.smembers(
133 | getUserSessionKey(this.userSessionsPrefix, userId)
134 | );
135 | if (!sessionIds)
136 | return formattedReturn(null, true, `Unable to find session for user: ${userId}.`);
137 | const sessionData = await Promise.all(
138 | sessionIds.map((sessionId) =>
139 | this.redisClient.get(getSessionKey(this.sessionPrefix, sessionId))
140 | )
141 | );
142 | const sessions = sessionData
143 | .filter((val): val is string => val !== null)
144 | .map((val) => this.serializer.parse(val) as any);
145 | return formattedReturn(
146 | sessions,
147 | false,
148 | `We found ${sessionData.length} active session for user: ${userId}`
149 | );
150 | };
151 | // till here
152 |
153 | deleteSession = async (cookies: Cookies, userId = null) => {
154 | const {
155 | data: sessionId,
156 | error,
157 | message
158 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
159 | if (error) {
160 | console.log('Error in delSession method', message);
161 | return formattedReturn(sessionId, error, 'Unable to validate key while deleting');
162 | }
163 |
164 | const prefixedSessionKey = getSessionKey(this.sessionPrefix, sessionId);
165 | const sessionData = await this.redisClient.get(prefixedSessionKey);
166 | if (!sessionData) return formattedReturn(sessionId, true, `Not a valid session key`);
167 |
168 | if (userId) {
169 | const redisPipeline = this.redisClient.pipeline();
170 | redisPipeline.del(prefixedSessionKey);
171 | redisPipeline.srem(getUserSessionKey(this.userSessionsPrefix, userId), sessionId);
172 | await redisPipeline.exec();
173 | } else {
174 | await this.redisClient.del(prefixedSessionKey);
175 | }
176 |
177 | await this.deleteCookie(cookies);
178 | return formattedReturn(sessionId, false, `Key successfully deleted`); // Returns unique key without prefix which is deleted from redis
179 | };
180 |
181 | deleteSessionsByUserId = async (userId: string) => {
182 | const sessionIds = await this.redisClient.smembers(
183 | getUserSessionKey(this.userSessionsPrefix, userId)
184 | );
185 | if (!sessionIds)
186 | return formattedReturn(null, true, `Unable to find session for user: ${userId}.`);
187 | await Promise.all([
188 | ...sessionIds.map((sessionId) =>
189 | this.redisClient.del(getSessionKey(this.sessionPrefix, sessionId))
190 | ),
191 | this.redisClient.del(getUserSessionKey(this.userSessionsPrefix, userId))
192 | ]);
193 | return formattedReturn(userId, false, `Successfully deleted`); // Returns userId without prefix which is deleted from redis
194 | };
195 |
196 | deleteCookie = async (cookies: Cookies) => {
197 | const allCookieOptionsCopy = { ...this.cookieOptions };
198 | delete allCookieOptionsCopy.maxAge;
199 | try {
200 | cookies.delete(this.cookieName, allCookieOptionsCopy);
201 | } catch (err) {
202 | console.log('error while deleting cookies in deleteCookie method', err);
203 | }
204 | };
205 |
206 | async updateSession(
207 | cookies: Cookies,
208 | sessionData = {}
209 | ): Promise<{ data: any; error: boolean; message: string }> {
210 | const {
211 | data: sessionId,
212 | error,
213 | message
214 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
215 | if (error) {
216 | console.log('Error in updateSessionExpiry method', message);
217 | return formattedReturn(sessionId, error, 'Unable to validate key while updating session');
218 | }
219 | const keyWithPrefix = getSessionKey(this.sessionPrefix, sessionId);
220 | let serializedSessionData;
221 | try {
222 | serializedSessionData = this.serializer.stringify(sessionData);
223 | } catch (er) {
224 | console.log('Error in Set Session while serializing', er);
225 | return formattedReturn(null, true, 'Unable to stringify session data.');
226 | }
227 | const redisPipe = this.redisClient.pipeline();
228 | redisPipe.set(keyWithPrefix, serializedSessionData);
229 | if (this.useTTL && this.ttlSeconds) {
230 | redisPipe.expire(keyWithPrefix, this.ttlSeconds);
231 | }
232 | await redisPipe.exec();
233 | return formattedReturn(sessionId, false, 'Cookie data has been updated');
234 | }
235 |
236 | updateSessionExpiry = async (
237 | cookies: Cookies,
238 | skipValidation = false,
239 | key = ''
240 | ): Promise<{ data: any; error: boolean; message: string }> => {
241 | let uniqueKey = key;
242 | if (!skipValidation) {
243 | const {
244 | data: sessionKey,
245 | error,
246 | message
247 | } = await validateCookie(cookies, this.cookieName, this.secret, this.signedCookies);
248 | if (error) {
249 | console.log('Error in updateSessionExpiry method', message);
250 | return formattedReturn(sessionKey, error, 'Unable to validate key while updating session');
251 | }
252 | uniqueKey = sessionKey;
253 | }
254 | let isExpireTimeUpdated = 1;
255 | if (this.useTTL && this.ttlSeconds) {
256 | isExpireTimeUpdated = await this.redisClient.expire(
257 | getSessionKey(this.sessionPrefix, uniqueKey),
258 | this.ttlSeconds as number
259 | );
260 | }
261 | if (isExpireTimeUpdated) {
262 | if (this.signedCookies) uniqueKey = await signSessionKey(uniqueKey, this.secret);
263 | cookies.set(this.cookieName, uniqueKey, this.cookieOptions);
264 | return formattedReturn(uniqueKey, false, 'Session validity extended successfully');
265 | }
266 | return formattedReturn(null, true, 'Unable to extended session validity');
267 | };
268 | }
269 |
--------------------------------------------------------------------------------
/src/lib/shared.ts:
--------------------------------------------------------------------------------
1 | import type { Redis } from 'ioredis';
2 | import type { RedisClientType } from 'redis';
3 | import type { Redis as upstashRedisClient } from '@upstash/redis';
4 | import { dev } from '$app/environment';
5 | import type { Cookies } from '@sveltejs/kit';
6 |
7 | // code copied from Nanoid:
8 | // https://github.com/ai/nanoid/blob/9b748729f8ad5409503b508b65958636e55bd87a/index.browser.js
9 | // nanoid uses Node dependencies on default bundler settings
10 |
11 | const getRandomValues = (bytes: number) => crypto.getRandomValues(new Uint8Array(bytes));
12 |
13 | const DEFAULT_ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
14 |
15 | export const generateRandomString = (size = 36, alphabet = DEFAULT_ALPHABET) => {
16 | const mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1;
17 | const step = -~((1.6 * mask * size) / alphabet.length);
18 |
19 | let bytes = getRandomValues(step);
20 | let id = '';
21 | let index = 0;
22 |
23 | while (id.length !== size) {
24 | id += alphabet[bytes[index] & mask] ?? '';
25 | index += 1;
26 | if (index > bytes.length) {
27 | bytes = getRandomValues(step);
28 | index = 0;
29 | }
30 | }
31 | return id;
32 | };
33 |
34 | export const getSessionKey = (sessionPrefix: string, sessionId: string): string => {
35 | return [sessionPrefix, sessionId].join(':');
36 | };
37 |
38 | export const getUserSessionKey = (userSessionsPrefix: string, userId: string): string => {
39 | return [userSessionsPrefix, userId].join(':');
40 | };
41 |
42 | export const formattedReturn = (data: any, error: boolean, message: string) => {
43 | return { data, error, message };
44 | };
45 |
46 | const importKey = async (secret: string) => {
47 | return crypto.subtle.importKey(
48 | 'raw',
49 | new TextEncoder().encode(secret),
50 | { name: 'HMAC', hash: 'SHA-256' },
51 | false,
52 | ['sign', 'verify']
53 | );
54 | };
55 |
56 | export const signSessionKey = async (key: string, secret: string) => {
57 | const secretKeyEncoded = await importKey(secret);
58 |
59 | const signature = await crypto.subtle.sign(
60 | 'HMAC',
61 | secretKeyEncoded,
62 | new TextEncoder().encode(key)
63 | );
64 |
65 | const newDigest = btoa(String.fromCharCode(...new Uint8Array(signature)));
66 | return `${key}.${newDigest}`;
67 | };
68 |
69 | export const verifySignature = async (signedCookie: string, secret: string) => {
70 | const valueWithSignature = signedCookie.split('.');
71 | try {
72 | const value = valueWithSignature[0];
73 | const signature = valueWithSignature[1];
74 | const key = await importKey(secret);
75 | const sigBuf = Uint8Array.from(atob(signature), (c) => c.charCodeAt(0));
76 |
77 | const isValidSignature = await crypto.subtle.verify(
78 | 'HMAC',
79 | key,
80 | sigBuf,
81 | new TextEncoder().encode(value)
82 | );
83 | if (!isValidSignature) {
84 | return null;
85 | }
86 | return value;
87 | } catch (e) {
88 | console.log('decryption error: ', e);
89 | return null;
90 | }
91 | };
92 |
93 | export const validateCookie = async (
94 | cookies: Cookies,
95 | cookieName: string,
96 | secret: string,
97 | signedCookies: boolean
98 | ) => {
99 | const cookiesSessionKey = cookies.get(cookieName);
100 | if (!cookiesSessionKey) return formattedReturn(null, true, 'No session found in cookies.');
101 | let verifiedSessionKey = cookiesSessionKey;
102 | if (signedCookies)
103 | verifiedSessionKey = (await verifySignature(verifiedSessionKey, secret)) as string;
104 | if (!verifiedSessionKey) return formattedReturn(null, true, 'Cookies session is not verified.');
105 | return formattedReturn(verifiedSessionKey, false, 'Successfully validated cookies');
106 | };
107 |
108 | export interface CookieSerializeOptions {
109 | domain?: string | undefined;
110 | encode?(value: string): string;
111 | expires?: Date | undefined;
112 | httpOnly?: boolean | undefined;
113 | maxAge?: number | undefined;
114 | path?: string | undefined;
115 | priority?: 'low' | 'medium' | 'high' | undefined;
116 | sameSite?: true | false | 'lax' | 'strict' | 'none' | undefined;
117 | secure?: boolean | undefined;
118 | }
119 |
120 | export interface ioRedisSessionOptions extends redisSessionOptions {
121 | redisClient: Redis;
122 | }
123 |
124 | export interface nodeRedisSessionOptions extends redisSessionOptions {
125 | redisClient: RedisClientType;
126 | }
127 |
128 | export interface upstashRedisSessionOptions extends redisSessionOptions {
129 | redisClient: upstashRedisClient;
130 | }
131 |
132 | interface redisSessionOptions {
133 | secret: string;
134 | cookieName?: string;
135 | userSessionsPrefix?: string;
136 | sessionPrefix?: string;
137 | signed?: boolean;
138 | useTTL?: boolean;
139 | renewSessionBeforeExpire?: boolean;
140 | renewBeforeSeconds?: number;
141 | serializer?: Serializer | JSON;
142 | cookiesOptions?: CookieSerializeOptions;
143 | }
144 |
145 | export const defaultExpireSeconds: number = 60 * 60 * 24; // One day in seconds
146 | export const defaultRenewBeforeSeconds: number = 30 * 60; // 30 minutes in seconds
147 | export const defaultCookiesOption: CookieSerializeOptions = {
148 | path: '/',
149 | httpOnly: true,
150 | sameSite: 'strict',
151 | secure: !dev,
152 | maxAge: defaultExpireSeconds
153 | };
154 |
155 | export type Serializer = {
156 | // eslint-disable-next-line @typescript-eslint/ban-types
157 | stringify: Function;
158 | // eslint-disable-next-line @typescript-eslint/ban-types
159 | parse: Function;
160 | };
161 |
--------------------------------------------------------------------------------
/src/routes/+page.server.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/src/routes/+page.server.ts
--------------------------------------------------------------------------------
/src/routes/+page.svelte:
--------------------------------------------------------------------------------
1 | Welcome to your library project
2 | Create your package using @sveltejs/package and preview/showcase your work with SvelteKit
3 | Visit kit.svelte.dev to read the documentation
4 |
--------------------------------------------------------------------------------
/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/etherCorps/SK-Redis-SessionManager/d134b04321cc0039940058b1baaf4ae1d2681dbb/static/favicon.png
--------------------------------------------------------------------------------
/static/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from '@sveltejs/adapter-auto';
2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
3 |
4 | /** @type {import('@sveltejs/kit').Config} */
5 | const config = {
6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors
7 | // for more information about preprocessors
8 | preprocess: vitePreprocess(),
9 |
10 | kit: {
11 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
12 | // If your environment is not supported or you settled on a specific environment, switch out the adapter.
13 | // See https://kit.svelte.dev/docs/adapters for more information about adapters.
14 | adapter: adapter()
15 | }
16 | };
17 |
18 | export default config;
19 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "checkJs": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "resolveJsonModule": true,
9 | "skipLibCheck": true,
10 | "sourceMap": true,
11 | "strict": true,
12 | "moduleResolution": "NodeNext"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { sveltekit } from '@sveltejs/kit/vite';
2 | import { defineConfig } from 'vitest/config';
3 |
4 | export default defineConfig({
5 | plugins: [sveltekit()],
6 | test: {
7 | include: ['src/**/*.{test,spec}.{js,ts}']
8 | }
9 | });
10 |
--------------------------------------------------------------------------------