├── .env ├── .eslintrc.cjs ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public └── ztm-notes.png ├── src ├── App.tsx ├── Node │ ├── BasicNode.tsx │ ├── CommandPanel.module.css │ ├── CommandPanel.tsx │ ├── ImageNode.tsx │ ├── Node.module.css │ ├── NodeContainer.module.css │ ├── NodeContainer.tsx │ ├── NodeTypeSwitcher.tsx │ ├── PageNode.tsx │ └── useOverflowsScreenBottom.ts ├── Page │ ├── Cover.module.css │ ├── Cover.tsx │ ├── Page.module.css │ ├── Page.tsx │ ├── Spacer.module.css │ ├── Spacer.tsx │ ├── Title.module.css │ ├── Title.tsx │ └── useFocusedNodeIndex.ts ├── auth │ ├── Auth.tsx │ ├── AuthSessionContext.tsx │ └── Private.tsx ├── components │ ├── FileImage.tsx │ ├── Loader.module.css │ └── Loader.tsx ├── index.css ├── main.tsx ├── state │ ├── AppStateContext.tsx │ ├── startPageScaffold.json │ ├── usePageState.ts │ ├── useSyncedState.ts │ └── withInitialState.tsx ├── supabaseClient.ts ├── utils.module.css ├── utils │ ├── createPage.ts │ ├── debounce.ts │ ├── types.ts │ ├── updatePage.ts │ └── uploadImage.ts └── vite-env.d.ts ├── supabase ├── .gitignore ├── config.toml ├── functions │ └── .vscode │ │ ├── extensions.json │ │ └── settings.json └── seed.sql ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts └── ztm-notion-clone.code-workspace /.env: -------------------------------------------------------------------------------- 1 | VITE_SUPABASE_URL=https://dmthattvhhsxbigzttgv.supabase.co 2 | VITE_SUPABASE_API_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImRtdGhhdHR2aGhzeGJpZ3p0dGd2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTA3MTI0OTEsImV4cCI6MTk2NjI4ODQ5MX0.UtqLymPOdk2FiVJSW3OWpf03CWcs22zu3FS7hdOxfUI 3 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | ignorePatterns: ['dist', '.eslintrc.cjs'], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': [ 14 | 'warn', 15 | { allowConstantExport: true }, 16 | ], 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | # Local Netlify folder 27 | .netlify 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zero To Mastery - React TypeScript Course. Notion Clone. 2 | 3 | ![05 Basic Implementation-cropped](https://github.com/satansdeer/ztm-notion-clone/assets/450319/2940d0fb-2de9-42cb-815f-8383d0904ae4) 4 | 5 | Notion-like app that allows users to create notes and organize them in a tree structure. 6 | 7 | ## Features 8 | 9 | - Authentication 10 | - Create, update and delete notes 11 | - Create, update and delete images 12 | - Reorder notes 13 | - Change page title 14 | - Change page cover image 15 | - Create, update and delete pages 16 | 17 | ## Tech Stack 18 | 19 | The app is generated with Vite and uses the following technologies: 20 | 21 | - React 22 | - TypeScript 23 | - DndKit (drag and drop) 24 | - CSS Modules 25 | - Supabase (database, authentication, storage) 26 | - Netlify (hosting) 27 | 28 | ## Running the app 29 | 30 | To run the app locally, you need to create a Supabase project and add the following environment variables to your `.env` file: 31 | 32 | ``` 33 | VITE_SUPABASE_URL="" 34 | VITE_SUPABASE_API_KEY="" 35 | ``` 36 | 37 | Then run the following commands: 38 | 39 | ``` 40 | npm install 41 | npm run dev 42 | ``` 43 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Notion Clone 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ztm-notion-clone", 3 | "version": "0.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "ztm-notion-clone", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "@dnd-kit/core": "^6.0.8", 12 | "@dnd-kit/sortable": "^7.0.2", 13 | "@supabase/supabase-js": "^2.31.0", 14 | "classnames": "^2.3.2", 15 | "eslint-plugin-immer": "^0.0.1", 16 | "nanoid": "^4.0.2", 17 | "react": "^18.2.0", 18 | "react-dom": "^18.2.0", 19 | "react-router-dom": "^6.14.2", 20 | "use-immer": "^0.9.0" 21 | }, 22 | "devDependencies": { 23 | "@types/react": "^18.2.15", 24 | "@types/react-dom": "^18.2.7", 25 | "@typescript-eslint/eslint-plugin": "^6.0.0", 26 | "@typescript-eslint/parser": "^6.0.0", 27 | "@vitejs/plugin-react-swc": "^3.3.2", 28 | "eslint": "^8.45.0", 29 | "eslint-plugin-react-hooks": "^4.6.0", 30 | "eslint-plugin-react-refresh": "^0.4.3", 31 | "supabase": "^1.82.5", 32 | "typescript": "^5.0.2", 33 | "vite": "^4.4.5" 34 | } 35 | }, 36 | "node_modules/@aashutoshrathi/word-wrap": { 37 | "version": "1.2.6", 38 | "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", 39 | "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", 40 | "dev": true, 41 | "engines": { 42 | "node": ">=0.10.0" 43 | } 44 | }, 45 | "node_modules/@dnd-kit/accessibility": { 46 | "version": "3.0.1", 47 | "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.0.1.tgz", 48 | "integrity": "sha512-HXRrwS9YUYQO9lFRc/49uO/VICbM+O+ZRpFDe9Pd1rwVv2PCNkRiTZRdxrDgng/UkvdC3Re9r2vwPpXXrWeFzg==", 49 | "dependencies": { 50 | "tslib": "^2.0.0" 51 | }, 52 | "peerDependencies": { 53 | "react": ">=16.8.0" 54 | } 55 | }, 56 | "node_modules/@dnd-kit/core": { 57 | "version": "6.0.8", 58 | "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.0.8.tgz", 59 | "integrity": "sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==", 60 | "dependencies": { 61 | "@dnd-kit/accessibility": "^3.0.0", 62 | "@dnd-kit/utilities": "^3.2.1", 63 | "tslib": "^2.0.0" 64 | }, 65 | "peerDependencies": { 66 | "react": ">=16.8.0", 67 | "react-dom": ">=16.8.0" 68 | } 69 | }, 70 | "node_modules/@dnd-kit/sortable": { 71 | "version": "7.0.2", 72 | "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-7.0.2.tgz", 73 | "integrity": "sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==", 74 | "dependencies": { 75 | "@dnd-kit/utilities": "^3.2.0", 76 | "tslib": "^2.0.0" 77 | }, 78 | "peerDependencies": { 79 | "@dnd-kit/core": "^6.0.7", 80 | "react": ">=16.8.0" 81 | } 82 | }, 83 | "node_modules/@dnd-kit/utilities": { 84 | "version": "3.2.1", 85 | "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.1.tgz", 86 | "integrity": "sha512-OOXqISfvBw/1REtkSK2N3Fi2EQiLMlWUlqnOK/UpOISqBZPWpE6TqL+jcPtMOkE8TqYGiURvRdPSI9hltNUjEA==", 87 | "dependencies": { 88 | "tslib": "^2.0.0" 89 | }, 90 | "peerDependencies": { 91 | "react": ">=16.8.0" 92 | } 93 | }, 94 | "node_modules/@esbuild/android-arm": { 95 | "version": "0.18.17", 96 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz", 97 | "integrity": "sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==", 98 | "cpu": [ 99 | "arm" 100 | ], 101 | "dev": true, 102 | "optional": true, 103 | "os": [ 104 | "android" 105 | ], 106 | "engines": { 107 | "node": ">=12" 108 | } 109 | }, 110 | "node_modules/@esbuild/android-arm64": { 111 | "version": "0.18.17", 112 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz", 113 | "integrity": "sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==", 114 | "cpu": [ 115 | "arm64" 116 | ], 117 | "dev": true, 118 | "optional": true, 119 | "os": [ 120 | "android" 121 | ], 122 | "engines": { 123 | "node": ">=12" 124 | } 125 | }, 126 | "node_modules/@esbuild/android-x64": { 127 | "version": "0.18.17", 128 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz", 129 | "integrity": "sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==", 130 | "cpu": [ 131 | "x64" 132 | ], 133 | "dev": true, 134 | "optional": true, 135 | "os": [ 136 | "android" 137 | ], 138 | "engines": { 139 | "node": ">=12" 140 | } 141 | }, 142 | "node_modules/@esbuild/darwin-arm64": { 143 | "version": "0.18.17", 144 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz", 145 | "integrity": "sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==", 146 | "cpu": [ 147 | "arm64" 148 | ], 149 | "dev": true, 150 | "optional": true, 151 | "os": [ 152 | "darwin" 153 | ], 154 | "engines": { 155 | "node": ">=12" 156 | } 157 | }, 158 | "node_modules/@esbuild/darwin-x64": { 159 | "version": "0.18.17", 160 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz", 161 | "integrity": "sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==", 162 | "cpu": [ 163 | "x64" 164 | ], 165 | "dev": true, 166 | "optional": true, 167 | "os": [ 168 | "darwin" 169 | ], 170 | "engines": { 171 | "node": ">=12" 172 | } 173 | }, 174 | "node_modules/@esbuild/freebsd-arm64": { 175 | "version": "0.18.17", 176 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz", 177 | "integrity": "sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==", 178 | "cpu": [ 179 | "arm64" 180 | ], 181 | "dev": true, 182 | "optional": true, 183 | "os": [ 184 | "freebsd" 185 | ], 186 | "engines": { 187 | "node": ">=12" 188 | } 189 | }, 190 | "node_modules/@esbuild/freebsd-x64": { 191 | "version": "0.18.17", 192 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz", 193 | "integrity": "sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==", 194 | "cpu": [ 195 | "x64" 196 | ], 197 | "dev": true, 198 | "optional": true, 199 | "os": [ 200 | "freebsd" 201 | ], 202 | "engines": { 203 | "node": ">=12" 204 | } 205 | }, 206 | "node_modules/@esbuild/linux-arm": { 207 | "version": "0.18.17", 208 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz", 209 | "integrity": "sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==", 210 | "cpu": [ 211 | "arm" 212 | ], 213 | "dev": true, 214 | "optional": true, 215 | "os": [ 216 | "linux" 217 | ], 218 | "engines": { 219 | "node": ">=12" 220 | } 221 | }, 222 | "node_modules/@esbuild/linux-arm64": { 223 | "version": "0.18.17", 224 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz", 225 | "integrity": "sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==", 226 | "cpu": [ 227 | "arm64" 228 | ], 229 | "dev": true, 230 | "optional": true, 231 | "os": [ 232 | "linux" 233 | ], 234 | "engines": { 235 | "node": ">=12" 236 | } 237 | }, 238 | "node_modules/@esbuild/linux-ia32": { 239 | "version": "0.18.17", 240 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz", 241 | "integrity": "sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==", 242 | "cpu": [ 243 | "ia32" 244 | ], 245 | "dev": true, 246 | "optional": true, 247 | "os": [ 248 | "linux" 249 | ], 250 | "engines": { 251 | "node": ">=12" 252 | } 253 | }, 254 | "node_modules/@esbuild/linux-loong64": { 255 | "version": "0.18.17", 256 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz", 257 | "integrity": "sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==", 258 | "cpu": [ 259 | "loong64" 260 | ], 261 | "dev": true, 262 | "optional": true, 263 | "os": [ 264 | "linux" 265 | ], 266 | "engines": { 267 | "node": ">=12" 268 | } 269 | }, 270 | "node_modules/@esbuild/linux-mips64el": { 271 | "version": "0.18.17", 272 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz", 273 | "integrity": "sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==", 274 | "cpu": [ 275 | "mips64el" 276 | ], 277 | "dev": true, 278 | "optional": true, 279 | "os": [ 280 | "linux" 281 | ], 282 | "engines": { 283 | "node": ">=12" 284 | } 285 | }, 286 | "node_modules/@esbuild/linux-ppc64": { 287 | "version": "0.18.17", 288 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz", 289 | "integrity": "sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==", 290 | "cpu": [ 291 | "ppc64" 292 | ], 293 | "dev": true, 294 | "optional": true, 295 | "os": [ 296 | "linux" 297 | ], 298 | "engines": { 299 | "node": ">=12" 300 | } 301 | }, 302 | "node_modules/@esbuild/linux-riscv64": { 303 | "version": "0.18.17", 304 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz", 305 | "integrity": "sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==", 306 | "cpu": [ 307 | "riscv64" 308 | ], 309 | "dev": true, 310 | "optional": true, 311 | "os": [ 312 | "linux" 313 | ], 314 | "engines": { 315 | "node": ">=12" 316 | } 317 | }, 318 | "node_modules/@esbuild/linux-s390x": { 319 | "version": "0.18.17", 320 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz", 321 | "integrity": "sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==", 322 | "cpu": [ 323 | "s390x" 324 | ], 325 | "dev": true, 326 | "optional": true, 327 | "os": [ 328 | "linux" 329 | ], 330 | "engines": { 331 | "node": ">=12" 332 | } 333 | }, 334 | "node_modules/@esbuild/linux-x64": { 335 | "version": "0.18.17", 336 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz", 337 | "integrity": "sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==", 338 | "cpu": [ 339 | "x64" 340 | ], 341 | "dev": true, 342 | "optional": true, 343 | "os": [ 344 | "linux" 345 | ], 346 | "engines": { 347 | "node": ">=12" 348 | } 349 | }, 350 | "node_modules/@esbuild/netbsd-x64": { 351 | "version": "0.18.17", 352 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz", 353 | "integrity": "sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==", 354 | "cpu": [ 355 | "x64" 356 | ], 357 | "dev": true, 358 | "optional": true, 359 | "os": [ 360 | "netbsd" 361 | ], 362 | "engines": { 363 | "node": ">=12" 364 | } 365 | }, 366 | "node_modules/@esbuild/openbsd-x64": { 367 | "version": "0.18.17", 368 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz", 369 | "integrity": "sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==", 370 | "cpu": [ 371 | "x64" 372 | ], 373 | "dev": true, 374 | "optional": true, 375 | "os": [ 376 | "openbsd" 377 | ], 378 | "engines": { 379 | "node": ">=12" 380 | } 381 | }, 382 | "node_modules/@esbuild/sunos-x64": { 383 | "version": "0.18.17", 384 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz", 385 | "integrity": "sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==", 386 | "cpu": [ 387 | "x64" 388 | ], 389 | "dev": true, 390 | "optional": true, 391 | "os": [ 392 | "sunos" 393 | ], 394 | "engines": { 395 | "node": ">=12" 396 | } 397 | }, 398 | "node_modules/@esbuild/win32-arm64": { 399 | "version": "0.18.17", 400 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz", 401 | "integrity": "sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==", 402 | "cpu": [ 403 | "arm64" 404 | ], 405 | "dev": true, 406 | "optional": true, 407 | "os": [ 408 | "win32" 409 | ], 410 | "engines": { 411 | "node": ">=12" 412 | } 413 | }, 414 | "node_modules/@esbuild/win32-ia32": { 415 | "version": "0.18.17", 416 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz", 417 | "integrity": "sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==", 418 | "cpu": [ 419 | "ia32" 420 | ], 421 | "dev": true, 422 | "optional": true, 423 | "os": [ 424 | "win32" 425 | ], 426 | "engines": { 427 | "node": ">=12" 428 | } 429 | }, 430 | "node_modules/@esbuild/win32-x64": { 431 | "version": "0.18.17", 432 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz", 433 | "integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==", 434 | "cpu": [ 435 | "x64" 436 | ], 437 | "dev": true, 438 | "optional": true, 439 | "os": [ 440 | "win32" 441 | ], 442 | "engines": { 443 | "node": ">=12" 444 | } 445 | }, 446 | "node_modules/@eslint-community/eslint-utils": { 447 | "version": "4.4.0", 448 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", 449 | "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", 450 | "dev": true, 451 | "dependencies": { 452 | "eslint-visitor-keys": "^3.3.0" 453 | }, 454 | "engines": { 455 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 456 | }, 457 | "peerDependencies": { 458 | "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" 459 | } 460 | }, 461 | "node_modules/@eslint-community/regexpp": { 462 | "version": "4.6.2", 463 | "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", 464 | "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", 465 | "dev": true, 466 | "engines": { 467 | "node": "^12.0.0 || ^14.0.0 || >=16.0.0" 468 | } 469 | }, 470 | "node_modules/@eslint/eslintrc": { 471 | "version": "2.1.0", 472 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", 473 | "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", 474 | "dev": true, 475 | "dependencies": { 476 | "ajv": "^6.12.4", 477 | "debug": "^4.3.2", 478 | "espree": "^9.6.0", 479 | "globals": "^13.19.0", 480 | "ignore": "^5.2.0", 481 | "import-fresh": "^3.2.1", 482 | "js-yaml": "^4.1.0", 483 | "minimatch": "^3.1.2", 484 | "strip-json-comments": "^3.1.1" 485 | }, 486 | "engines": { 487 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 488 | }, 489 | "funding": { 490 | "url": "https://opencollective.com/eslint" 491 | } 492 | }, 493 | "node_modules/@eslint/js": { 494 | "version": "8.44.0", 495 | "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", 496 | "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", 497 | "dev": true, 498 | "engines": { 499 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 500 | } 501 | }, 502 | "node_modules/@humanwhocodes/config-array": { 503 | "version": "0.11.10", 504 | "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", 505 | "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", 506 | "dev": true, 507 | "dependencies": { 508 | "@humanwhocodes/object-schema": "^1.2.1", 509 | "debug": "^4.1.1", 510 | "minimatch": "^3.0.5" 511 | }, 512 | "engines": { 513 | "node": ">=10.10.0" 514 | } 515 | }, 516 | "node_modules/@humanwhocodes/module-importer": { 517 | "version": "1.0.1", 518 | "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", 519 | "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", 520 | "dev": true, 521 | "engines": { 522 | "node": ">=12.22" 523 | }, 524 | "funding": { 525 | "type": "github", 526 | "url": "https://github.com/sponsors/nzakas" 527 | } 528 | }, 529 | "node_modules/@humanwhocodes/object-schema": { 530 | "version": "1.2.1", 531 | "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", 532 | "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", 533 | "dev": true 534 | }, 535 | "node_modules/@nodelib/fs.scandir": { 536 | "version": "2.1.5", 537 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 538 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 539 | "dev": true, 540 | "dependencies": { 541 | "@nodelib/fs.stat": "2.0.5", 542 | "run-parallel": "^1.1.9" 543 | }, 544 | "engines": { 545 | "node": ">= 8" 546 | } 547 | }, 548 | "node_modules/@nodelib/fs.stat": { 549 | "version": "2.0.5", 550 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 551 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 552 | "dev": true, 553 | "engines": { 554 | "node": ">= 8" 555 | } 556 | }, 557 | "node_modules/@nodelib/fs.walk": { 558 | "version": "1.2.8", 559 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 560 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 561 | "dev": true, 562 | "dependencies": { 563 | "@nodelib/fs.scandir": "2.1.5", 564 | "fastq": "^1.6.0" 565 | }, 566 | "engines": { 567 | "node": ">= 8" 568 | } 569 | }, 570 | "node_modules/@remix-run/router": { 571 | "version": "1.7.2", 572 | "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.2.tgz", 573 | "integrity": "sha512-7Lcn7IqGMV+vizMPoEl5F0XDshcdDYtMI6uJLQdQz5CfZAwy3vvGKYSUk789qndt5dEC4HfSjviSYlSoHGL2+A==", 574 | "engines": { 575 | "node": ">=14" 576 | } 577 | }, 578 | "node_modules/@supabase/functions-js": { 579 | "version": "2.1.2", 580 | "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.1.2.tgz", 581 | "integrity": "sha512-QCR6pwJs9exCl37bmpMisUd6mf+0SUBJ6mUpiAjEkSJ/+xW8TCuO14bvkWHADd5hElJK9MxNlMQXxSA4DRz9nQ==", 582 | "dependencies": { 583 | "cross-fetch": "^3.1.5" 584 | } 585 | }, 586 | "node_modules/@supabase/gotrue-js": { 587 | "version": "2.46.1", 588 | "resolved": "https://registry.npmjs.org/@supabase/gotrue-js/-/gotrue-js-2.46.1.tgz", 589 | "integrity": "sha512-tebFX3XvPqEJKHOVgkXTN20g9iUhLx6tebIYQvTggYTrqOT2af8oTpSBdgYzbwJ291G6P6CSpR6KY0cT9ade5A==", 590 | "dependencies": { 591 | "cross-fetch": "^3.1.5" 592 | } 593 | }, 594 | "node_modules/@supabase/postgrest-js": { 595 | "version": "1.7.2", 596 | "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.7.2.tgz", 597 | "integrity": "sha512-GK80JpRq8l6Qll85erICypAfQCied8tdlXfsDN14W844HqXCSOisk8AaE01DAwGJanieaoN5fuqhzA2yKxDvEQ==", 598 | "dependencies": { 599 | "cross-fetch": "^3.1.5" 600 | } 601 | }, 602 | "node_modules/@supabase/realtime-js": { 603 | "version": "2.7.3", 604 | "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.7.3.tgz", 605 | "integrity": "sha512-c7TzL81sx2kqyxsxcDduJcHL9KJdCOoKimGP6lQSqiZKX42ATlBZpWbyy9KFGFBjAP4nyopMf5JhPi2ZH9jyNw==", 606 | "dependencies": { 607 | "@types/phoenix": "^1.5.4", 608 | "@types/websocket": "^1.0.3", 609 | "websocket": "^1.0.34" 610 | } 611 | }, 612 | "node_modules/@supabase/storage-js": { 613 | "version": "2.5.1", 614 | "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.5.1.tgz", 615 | "integrity": "sha512-nkR0fQA9ScAtIKA3vNoPEqbZv1k5B5HVRYEvRWdlP6mUpFphM9TwPL2jZ/ztNGMTG5xT6SrHr+H7Ykz8qzbhjw==", 616 | "dependencies": { 617 | "cross-fetch": "^3.1.5" 618 | } 619 | }, 620 | "node_modules/@supabase/supabase-js": { 621 | "version": "2.31.0", 622 | "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.31.0.tgz", 623 | "integrity": "sha512-W9/4s+KnSUX67wJKBn/3yLq+ieycnMzVjK3nNTLX5Wko3ypNT/081l2iFYrf+nsLQ1CiT4mA92I3dxCy6CmxTg==", 624 | "dependencies": { 625 | "@supabase/functions-js": "^2.1.0", 626 | "@supabase/gotrue-js": "^2.46.1", 627 | "@supabase/postgrest-js": "^1.7.0", 628 | "@supabase/realtime-js": "^2.7.3", 629 | "@supabase/storage-js": "^2.5.1", 630 | "cross-fetch": "^3.1.5" 631 | } 632 | }, 633 | "node_modules/@swc/core": { 634 | "version": "1.3.71", 635 | "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.71.tgz", 636 | "integrity": "sha512-T8dqj+SV/S8laW/FGmKHhCGw1o4GRUvJ2jHfbYgEwiJpeutT9uavHvG02t39HJvObBJ52EZs/krGtni4U5928Q==", 637 | "dev": true, 638 | "hasInstallScript": true, 639 | "engines": { 640 | "node": ">=10" 641 | }, 642 | "funding": { 643 | "type": "opencollective", 644 | "url": "https://opencollective.com/swc" 645 | }, 646 | "optionalDependencies": { 647 | "@swc/core-darwin-arm64": "1.3.71", 648 | "@swc/core-darwin-x64": "1.3.71", 649 | "@swc/core-linux-arm-gnueabihf": "1.3.71", 650 | "@swc/core-linux-arm64-gnu": "1.3.71", 651 | "@swc/core-linux-arm64-musl": "1.3.71", 652 | "@swc/core-linux-x64-gnu": "1.3.71", 653 | "@swc/core-linux-x64-musl": "1.3.71", 654 | "@swc/core-win32-arm64-msvc": "1.3.71", 655 | "@swc/core-win32-ia32-msvc": "1.3.71", 656 | "@swc/core-win32-x64-msvc": "1.3.71" 657 | }, 658 | "peerDependencies": { 659 | "@swc/helpers": "^0.5.0" 660 | }, 661 | "peerDependenciesMeta": { 662 | "@swc/helpers": { 663 | "optional": true 664 | } 665 | } 666 | }, 667 | "node_modules/@swc/core-darwin-arm64": { 668 | "version": "1.3.71", 669 | "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.71.tgz", 670 | "integrity": "sha512-xOm0hDbcO2ShwQu1CjLtq3fwrG9AvhuE0s8vtBc8AsamYExHmR8bo6GQHJUtfPG1FVPk5a8xoQSd1fs09FQjLg==", 671 | "cpu": [ 672 | "arm64" 673 | ], 674 | "dev": true, 675 | "optional": true, 676 | "os": [ 677 | "darwin" 678 | ], 679 | "engines": { 680 | "node": ">=10" 681 | } 682 | }, 683 | "node_modules/@swc/core-darwin-x64": { 684 | "version": "1.3.71", 685 | "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.71.tgz", 686 | "integrity": "sha512-9sbDXBWgM22w/3Ll5kPhXMPkOiHRoqwMOyxLJBfGtIMnFlh5O+NRN3umRerK3pe4Q6/7hj2M5V+crEHYrXmuxg==", 687 | "cpu": [ 688 | "x64" 689 | ], 690 | "dev": true, 691 | "optional": true, 692 | "os": [ 693 | "darwin" 694 | ], 695 | "engines": { 696 | "node": ">=10" 697 | } 698 | }, 699 | "node_modules/@swc/core-linux-arm-gnueabihf": { 700 | "version": "1.3.71", 701 | "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.71.tgz", 702 | "integrity": "sha512-boKdMZsfKvhBs0FDeqH7KQj0lfYe0wCtrL1lv50oYMEeLajY9o4U5xSmc61Sg4HRXjlbR6dlM2cFfL84t7NpAA==", 703 | "cpu": [ 704 | "arm" 705 | ], 706 | "dev": true, 707 | "optional": true, 708 | "os": [ 709 | "linux" 710 | ], 711 | "engines": { 712 | "node": ">=10" 713 | } 714 | }, 715 | "node_modules/@swc/core-linux-arm64-gnu": { 716 | "version": "1.3.71", 717 | "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.71.tgz", 718 | "integrity": "sha512-yDatyHYMiOVwhyIA/LBwknPs2CUtLYWEMzPZjgLc+56PbgPs3oiEbNWeVUND5onPrfDQgK7NK1y8JeiXZqTgGQ==", 719 | "cpu": [ 720 | "arm64" 721 | ], 722 | "dev": true, 723 | "optional": true, 724 | "os": [ 725 | "linux" 726 | ], 727 | "engines": { 728 | "node": ">=10" 729 | } 730 | }, 731 | "node_modules/@swc/core-linux-arm64-musl": { 732 | "version": "1.3.71", 733 | "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.71.tgz", 734 | "integrity": "sha512-xAdCA0L/hoa0ULL5SR4sMZCxkWk7C90DOU7wJalNVG9qNWYICfq3G7AR0E9Ohphzqyahfb5QJED/nA7N0+XwbQ==", 735 | "cpu": [ 736 | "arm64" 737 | ], 738 | "dev": true, 739 | "optional": true, 740 | "os": [ 741 | "linux" 742 | ], 743 | "engines": { 744 | "node": ">=10" 745 | } 746 | }, 747 | "node_modules/@swc/core-linux-x64-gnu": { 748 | "version": "1.3.71", 749 | "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.71.tgz", 750 | "integrity": "sha512-j94qLXP/yqhu2afnABAq/xrJIU8TEqcNkp1TlsAeO3R2nVLYL1w4XX8GW71SPnXmd2bwF102c3Cfv/2ilf2y2A==", 751 | "cpu": [ 752 | "x64" 753 | ], 754 | "dev": true, 755 | "optional": true, 756 | "os": [ 757 | "linux" 758 | ], 759 | "engines": { 760 | "node": ">=10" 761 | } 762 | }, 763 | "node_modules/@swc/core-linux-x64-musl": { 764 | "version": "1.3.71", 765 | "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.71.tgz", 766 | "integrity": "sha512-YiyU848ql6dLlmt0BHccGAaZ36Cf61VzCAMDKID/gd72snvzWcMCHrwSRW0gEFNXHsjBJrmNl+SLYZHfqoGwUA==", 767 | "cpu": [ 768 | "x64" 769 | ], 770 | "dev": true, 771 | "optional": true, 772 | "os": [ 773 | "linux" 774 | ], 775 | "engines": { 776 | "node": ">=10" 777 | } 778 | }, 779 | "node_modules/@swc/core-win32-arm64-msvc": { 780 | "version": "1.3.71", 781 | "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.71.tgz", 782 | "integrity": "sha512-1UsJ+6hnIRe/PVdgDPexvgGaN4KpBncT/bAOqlWc9XC7KeBXAWcGA08LrPUz2Ei00DJXzR622IGZVEYOHNkUOw==", 783 | "cpu": [ 784 | "arm64" 785 | ], 786 | "dev": true, 787 | "optional": true, 788 | "os": [ 789 | "win32" 790 | ], 791 | "engines": { 792 | "node": ">=10" 793 | } 794 | }, 795 | "node_modules/@swc/core-win32-ia32-msvc": { 796 | "version": "1.3.71", 797 | "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.71.tgz", 798 | "integrity": "sha512-KnuI89+zojR9lDFELdQYZpxzPZ6pBfLwJfWTSGatnpL1ZHhIsV3tK1jwqIdJK1zkRxpBwc6p6FzSZdZwCSpnJw==", 799 | "cpu": [ 800 | "ia32" 801 | ], 802 | "dev": true, 803 | "optional": true, 804 | "os": [ 805 | "win32" 806 | ], 807 | "engines": { 808 | "node": ">=10" 809 | } 810 | }, 811 | "node_modules/@swc/core-win32-x64-msvc": { 812 | "version": "1.3.71", 813 | "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.71.tgz", 814 | "integrity": "sha512-Pcw7fFirpaBOZsU8fhO48ZCb7NxIjuLnLRPrHqWQ4Mapx1+w9ZNdGya2DKP9n8EAiUrJO20WDsrBNMT2MQSWkA==", 815 | "cpu": [ 816 | "x64" 817 | ], 818 | "dev": true, 819 | "optional": true, 820 | "os": [ 821 | "win32" 822 | ], 823 | "engines": { 824 | "node": ">=10" 825 | } 826 | }, 827 | "node_modules/@types/json-schema": { 828 | "version": "7.0.12", 829 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", 830 | "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", 831 | "dev": true 832 | }, 833 | "node_modules/@types/node": { 834 | "version": "20.4.5", 835 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", 836 | "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==" 837 | }, 838 | "node_modules/@types/phoenix": { 839 | "version": "1.6.0", 840 | "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.0.tgz", 841 | "integrity": "sha512-qwfpsHmFuhAS/dVd4uBIraMxRd56vwBUYQGZ6GpXnFuM2XMRFJbIyruFKKlW2daQliuYZwe0qfn/UjFCDKic5g==" 842 | }, 843 | "node_modules/@types/prop-types": { 844 | "version": "15.7.5", 845 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", 846 | "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", 847 | "dev": true 848 | }, 849 | "node_modules/@types/react": { 850 | "version": "18.2.16", 851 | "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.16.tgz", 852 | "integrity": "sha512-LLFWr12ZhBJ4YVw7neWLe6Pk7Ey5R9OCydfuMsz1L8bZxzaawJj2p06Q8/EFEHDeTBQNFLF62X+CG7B2zIyu0Q==", 853 | "dev": true, 854 | "dependencies": { 855 | "@types/prop-types": "*", 856 | "@types/scheduler": "*", 857 | "csstype": "^3.0.2" 858 | } 859 | }, 860 | "node_modules/@types/react-dom": { 861 | "version": "18.2.7", 862 | "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", 863 | "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", 864 | "dev": true, 865 | "dependencies": { 866 | "@types/react": "*" 867 | } 868 | }, 869 | "node_modules/@types/scheduler": { 870 | "version": "0.16.3", 871 | "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", 872 | "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", 873 | "dev": true 874 | }, 875 | "node_modules/@types/semver": { 876 | "version": "7.5.0", 877 | "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", 878 | "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", 879 | "dev": true 880 | }, 881 | "node_modules/@types/websocket": { 882 | "version": "1.0.5", 883 | "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.5.tgz", 884 | "integrity": "sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==", 885 | "dependencies": { 886 | "@types/node": "*" 887 | } 888 | }, 889 | "node_modules/@typescript-eslint/eslint-plugin": { 890 | "version": "6.2.0", 891 | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.2.0.tgz", 892 | "integrity": "sha512-rClGrMuyS/3j0ETa1Ui7s6GkLhfZGKZL3ZrChLeAiACBE/tRc1wq8SNZESUuluxhLj9FkUefRs2l6bCIArWBiQ==", 893 | "dev": true, 894 | "dependencies": { 895 | "@eslint-community/regexpp": "^4.5.1", 896 | "@typescript-eslint/scope-manager": "6.2.0", 897 | "@typescript-eslint/type-utils": "6.2.0", 898 | "@typescript-eslint/utils": "6.2.0", 899 | "@typescript-eslint/visitor-keys": "6.2.0", 900 | "debug": "^4.3.4", 901 | "graphemer": "^1.4.0", 902 | "ignore": "^5.2.4", 903 | "natural-compare": "^1.4.0", 904 | "natural-compare-lite": "^1.4.0", 905 | "semver": "^7.5.4", 906 | "ts-api-utils": "^1.0.1" 907 | }, 908 | "engines": { 909 | "node": "^16.0.0 || >=18.0.0" 910 | }, 911 | "funding": { 912 | "type": "opencollective", 913 | "url": "https://opencollective.com/typescript-eslint" 914 | }, 915 | "peerDependencies": { 916 | "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", 917 | "eslint": "^7.0.0 || ^8.0.0" 918 | }, 919 | "peerDependenciesMeta": { 920 | "typescript": { 921 | "optional": true 922 | } 923 | } 924 | }, 925 | "node_modules/@typescript-eslint/parser": { 926 | "version": "6.2.0", 927 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.2.0.tgz", 928 | "integrity": "sha512-igVYOqtiK/UsvKAmmloQAruAdUHihsOCvplJpplPZ+3h4aDkC/UKZZNKgB6h93ayuYLuEymU3h8nF1xMRbh37g==", 929 | "dev": true, 930 | "dependencies": { 931 | "@typescript-eslint/scope-manager": "6.2.0", 932 | "@typescript-eslint/types": "6.2.0", 933 | "@typescript-eslint/typescript-estree": "6.2.0", 934 | "@typescript-eslint/visitor-keys": "6.2.0", 935 | "debug": "^4.3.4" 936 | }, 937 | "engines": { 938 | "node": "^16.0.0 || >=18.0.0" 939 | }, 940 | "funding": { 941 | "type": "opencollective", 942 | "url": "https://opencollective.com/typescript-eslint" 943 | }, 944 | "peerDependencies": { 945 | "eslint": "^7.0.0 || ^8.0.0" 946 | }, 947 | "peerDependenciesMeta": { 948 | "typescript": { 949 | "optional": true 950 | } 951 | } 952 | }, 953 | "node_modules/@typescript-eslint/scope-manager": { 954 | "version": "6.2.0", 955 | "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.2.0.tgz", 956 | "integrity": "sha512-1ZMNVgm5nnHURU8ZSJ3snsHzpFeNK84rdZjluEVBGNu7jDymfqceB3kdIZ6A4xCfEFFhRIB6rF8q/JIqJd2R0Q==", 957 | "dev": true, 958 | "dependencies": { 959 | "@typescript-eslint/types": "6.2.0", 960 | "@typescript-eslint/visitor-keys": "6.2.0" 961 | }, 962 | "engines": { 963 | "node": "^16.0.0 || >=18.0.0" 964 | }, 965 | "funding": { 966 | "type": "opencollective", 967 | "url": "https://opencollective.com/typescript-eslint" 968 | } 969 | }, 970 | "node_modules/@typescript-eslint/type-utils": { 971 | "version": "6.2.0", 972 | "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.2.0.tgz", 973 | "integrity": "sha512-DnGZuNU2JN3AYwddYIqrVkYW0uUQdv0AY+kz2M25euVNlujcN2u+rJgfJsBFlUEzBB6OQkUqSZPyuTLf2bP5mw==", 974 | "dev": true, 975 | "dependencies": { 976 | "@typescript-eslint/typescript-estree": "6.2.0", 977 | "@typescript-eslint/utils": "6.2.0", 978 | "debug": "^4.3.4", 979 | "ts-api-utils": "^1.0.1" 980 | }, 981 | "engines": { 982 | "node": "^16.0.0 || >=18.0.0" 983 | }, 984 | "funding": { 985 | "type": "opencollective", 986 | "url": "https://opencollective.com/typescript-eslint" 987 | }, 988 | "peerDependencies": { 989 | "eslint": "^7.0.0 || ^8.0.0" 990 | }, 991 | "peerDependenciesMeta": { 992 | "typescript": { 993 | "optional": true 994 | } 995 | } 996 | }, 997 | "node_modules/@typescript-eslint/types": { 998 | "version": "6.2.0", 999 | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.2.0.tgz", 1000 | "integrity": "sha512-1nRRaDlp/XYJQLvkQJG5F3uBTno5SHPT7XVcJ5n1/k2WfNI28nJsvLakxwZRNY5spuatEKO7d5nZWsQpkqXwBA==", 1001 | "dev": true, 1002 | "engines": { 1003 | "node": "^16.0.0 || >=18.0.0" 1004 | }, 1005 | "funding": { 1006 | "type": "opencollective", 1007 | "url": "https://opencollective.com/typescript-eslint" 1008 | } 1009 | }, 1010 | "node_modules/@typescript-eslint/typescript-estree": { 1011 | "version": "6.2.0", 1012 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.2.0.tgz", 1013 | "integrity": "sha512-Mts6+3HQMSM+LZCglsc2yMIny37IhUgp1Qe8yJUYVyO6rHP7/vN0vajKu3JvHCBIy8TSiKddJ/Zwu80jhnGj1w==", 1014 | "dev": true, 1015 | "dependencies": { 1016 | "@typescript-eslint/types": "6.2.0", 1017 | "@typescript-eslint/visitor-keys": "6.2.0", 1018 | "debug": "^4.3.4", 1019 | "globby": "^11.1.0", 1020 | "is-glob": "^4.0.3", 1021 | "semver": "^7.5.4", 1022 | "ts-api-utils": "^1.0.1" 1023 | }, 1024 | "engines": { 1025 | "node": "^16.0.0 || >=18.0.0" 1026 | }, 1027 | "funding": { 1028 | "type": "opencollective", 1029 | "url": "https://opencollective.com/typescript-eslint" 1030 | }, 1031 | "peerDependenciesMeta": { 1032 | "typescript": { 1033 | "optional": true 1034 | } 1035 | } 1036 | }, 1037 | "node_modules/@typescript-eslint/utils": { 1038 | "version": "6.2.0", 1039 | "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.2.0.tgz", 1040 | "integrity": "sha512-RCFrC1lXiX1qEZN8LmLrxYRhOkElEsPKTVSNout8DMzf8PeWoQG7Rxz2SadpJa3VSh5oYKGwt7j7X/VRg+Y3OQ==", 1041 | "dev": true, 1042 | "dependencies": { 1043 | "@eslint-community/eslint-utils": "^4.4.0", 1044 | "@types/json-schema": "^7.0.12", 1045 | "@types/semver": "^7.5.0", 1046 | "@typescript-eslint/scope-manager": "6.2.0", 1047 | "@typescript-eslint/types": "6.2.0", 1048 | "@typescript-eslint/typescript-estree": "6.2.0", 1049 | "semver": "^7.5.4" 1050 | }, 1051 | "engines": { 1052 | "node": "^16.0.0 || >=18.0.0" 1053 | }, 1054 | "funding": { 1055 | "type": "opencollective", 1056 | "url": "https://opencollective.com/typescript-eslint" 1057 | }, 1058 | "peerDependencies": { 1059 | "eslint": "^7.0.0 || ^8.0.0" 1060 | } 1061 | }, 1062 | "node_modules/@typescript-eslint/visitor-keys": { 1063 | "version": "6.2.0", 1064 | "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.2.0.tgz", 1065 | "integrity": "sha512-QbaYUQVKKo9bgCzpjz45llCfwakyoxHetIy8CAvYCtd16Zu1KrpzNHofwF8kGkpPOxZB2o6kz+0nqH8ZkIzuoQ==", 1066 | "dev": true, 1067 | "dependencies": { 1068 | "@typescript-eslint/types": "6.2.0", 1069 | "eslint-visitor-keys": "^3.4.1" 1070 | }, 1071 | "engines": { 1072 | "node": "^16.0.0 || >=18.0.0" 1073 | }, 1074 | "funding": { 1075 | "type": "opencollective", 1076 | "url": "https://opencollective.com/typescript-eslint" 1077 | } 1078 | }, 1079 | "node_modules/@vitejs/plugin-react-swc": { 1080 | "version": "3.3.2", 1081 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.3.2.tgz", 1082 | "integrity": "sha512-VJFWY5sfoZerQRvJrh518h3AcQt6f/yTuWn4/TRB+dqmYU0NX1qz7qM5Wfd+gOQqUzQW4gxKqKN3KpE/P3+zrA==", 1083 | "dev": true, 1084 | "dependencies": { 1085 | "@swc/core": "^1.3.61" 1086 | }, 1087 | "peerDependencies": { 1088 | "vite": "^4" 1089 | } 1090 | }, 1091 | "node_modules/acorn": { 1092 | "version": "8.10.0", 1093 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", 1094 | "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", 1095 | "dev": true, 1096 | "bin": { 1097 | "acorn": "bin/acorn" 1098 | }, 1099 | "engines": { 1100 | "node": ">=0.4.0" 1101 | } 1102 | }, 1103 | "node_modules/acorn-jsx": { 1104 | "version": "5.3.2", 1105 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 1106 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 1107 | "dev": true, 1108 | "peerDependencies": { 1109 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 1110 | } 1111 | }, 1112 | "node_modules/ajv": { 1113 | "version": "6.12.6", 1114 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 1115 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 1116 | "dev": true, 1117 | "dependencies": { 1118 | "fast-deep-equal": "^3.1.1", 1119 | "fast-json-stable-stringify": "^2.0.0", 1120 | "json-schema-traverse": "^0.4.1", 1121 | "uri-js": "^4.2.2" 1122 | }, 1123 | "funding": { 1124 | "type": "github", 1125 | "url": "https://github.com/sponsors/epoberezkin" 1126 | } 1127 | }, 1128 | "node_modules/ansi-regex": { 1129 | "version": "5.0.1", 1130 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1131 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1132 | "dev": true, 1133 | "engines": { 1134 | "node": ">=8" 1135 | } 1136 | }, 1137 | "node_modules/ansi-styles": { 1138 | "version": "4.3.0", 1139 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1140 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1141 | "dev": true, 1142 | "dependencies": { 1143 | "color-convert": "^2.0.1" 1144 | }, 1145 | "engines": { 1146 | "node": ">=8" 1147 | }, 1148 | "funding": { 1149 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1150 | } 1151 | }, 1152 | "node_modules/argparse": { 1153 | "version": "2.0.1", 1154 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 1155 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 1156 | "dev": true 1157 | }, 1158 | "node_modules/array-union": { 1159 | "version": "2.1.0", 1160 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 1161 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 1162 | "dev": true, 1163 | "engines": { 1164 | "node": ">=8" 1165 | } 1166 | }, 1167 | "node_modules/balanced-match": { 1168 | "version": "1.0.2", 1169 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1170 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1171 | "dev": true 1172 | }, 1173 | "node_modules/bin-links": { 1174 | "version": "4.0.2", 1175 | "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.2.tgz", 1176 | "integrity": "sha512-jxJ0PbXR8eQyPlExCvCs3JFnikvs1Yp4gUJt6nmgathdOwvur+q22KWC3h20gvWl4T/14DXKj2IlkJwwZkZPOw==", 1177 | "dev": true, 1178 | "dependencies": { 1179 | "cmd-shim": "^6.0.0", 1180 | "npm-normalize-package-bin": "^3.0.0", 1181 | "read-cmd-shim": "^4.0.0", 1182 | "write-file-atomic": "^5.0.0" 1183 | }, 1184 | "engines": { 1185 | "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 1186 | } 1187 | }, 1188 | "node_modules/brace-expansion": { 1189 | "version": "1.1.11", 1190 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1191 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1192 | "dev": true, 1193 | "dependencies": { 1194 | "balanced-match": "^1.0.0", 1195 | "concat-map": "0.0.1" 1196 | } 1197 | }, 1198 | "node_modules/braces": { 1199 | "version": "3.0.2", 1200 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 1201 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 1202 | "dev": true, 1203 | "dependencies": { 1204 | "fill-range": "^7.0.1" 1205 | }, 1206 | "engines": { 1207 | "node": ">=8" 1208 | } 1209 | }, 1210 | "node_modules/bufferutil": { 1211 | "version": "4.0.7", 1212 | "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", 1213 | "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", 1214 | "hasInstallScript": true, 1215 | "dependencies": { 1216 | "node-gyp-build": "^4.3.0" 1217 | }, 1218 | "engines": { 1219 | "node": ">=6.14.2" 1220 | } 1221 | }, 1222 | "node_modules/callsites": { 1223 | "version": "3.1.0", 1224 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 1225 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 1226 | "dev": true, 1227 | "engines": { 1228 | "node": ">=6" 1229 | } 1230 | }, 1231 | "node_modules/chalk": { 1232 | "version": "4.1.2", 1233 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 1234 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1235 | "dev": true, 1236 | "dependencies": { 1237 | "ansi-styles": "^4.1.0", 1238 | "supports-color": "^7.1.0" 1239 | }, 1240 | "engines": { 1241 | "node": ">=10" 1242 | }, 1243 | "funding": { 1244 | "url": "https://github.com/chalk/chalk?sponsor=1" 1245 | } 1246 | }, 1247 | "node_modules/chownr": { 1248 | "version": "2.0.0", 1249 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", 1250 | "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", 1251 | "dev": true, 1252 | "engines": { 1253 | "node": ">=10" 1254 | } 1255 | }, 1256 | "node_modules/classnames": { 1257 | "version": "2.3.2", 1258 | "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", 1259 | "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" 1260 | }, 1261 | "node_modules/cmd-shim": { 1262 | "version": "6.0.1", 1263 | "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.1.tgz", 1264 | "integrity": "sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q==", 1265 | "dev": true, 1266 | "engines": { 1267 | "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 1268 | } 1269 | }, 1270 | "node_modules/color-convert": { 1271 | "version": "2.0.1", 1272 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1273 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1274 | "dev": true, 1275 | "dependencies": { 1276 | "color-name": "~1.1.4" 1277 | }, 1278 | "engines": { 1279 | "node": ">=7.0.0" 1280 | } 1281 | }, 1282 | "node_modules/color-name": { 1283 | "version": "1.1.4", 1284 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1285 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1286 | "dev": true 1287 | }, 1288 | "node_modules/concat-map": { 1289 | "version": "0.0.1", 1290 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1291 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 1292 | "dev": true 1293 | }, 1294 | "node_modules/cross-fetch": { 1295 | "version": "3.1.8", 1296 | "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", 1297 | "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", 1298 | "dependencies": { 1299 | "node-fetch": "^2.6.12" 1300 | } 1301 | }, 1302 | "node_modules/cross-spawn": { 1303 | "version": "7.0.3", 1304 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 1305 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 1306 | "dev": true, 1307 | "dependencies": { 1308 | "path-key": "^3.1.0", 1309 | "shebang-command": "^2.0.0", 1310 | "which": "^2.0.1" 1311 | }, 1312 | "engines": { 1313 | "node": ">= 8" 1314 | } 1315 | }, 1316 | "node_modules/csstype": { 1317 | "version": "3.1.2", 1318 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", 1319 | "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", 1320 | "dev": true 1321 | }, 1322 | "node_modules/d": { 1323 | "version": "1.0.1", 1324 | "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", 1325 | "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", 1326 | "dependencies": { 1327 | "es5-ext": "^0.10.50", 1328 | "type": "^1.0.1" 1329 | } 1330 | }, 1331 | "node_modules/data-uri-to-buffer": { 1332 | "version": "4.0.1", 1333 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", 1334 | "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", 1335 | "dev": true, 1336 | "engines": { 1337 | "node": ">= 12" 1338 | } 1339 | }, 1340 | "node_modules/debug": { 1341 | "version": "4.3.4", 1342 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 1343 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 1344 | "dev": true, 1345 | "dependencies": { 1346 | "ms": "2.1.2" 1347 | }, 1348 | "engines": { 1349 | "node": ">=6.0" 1350 | }, 1351 | "peerDependenciesMeta": { 1352 | "supports-color": { 1353 | "optional": true 1354 | } 1355 | } 1356 | }, 1357 | "node_modules/deep-is": { 1358 | "version": "0.1.4", 1359 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 1360 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 1361 | "dev": true 1362 | }, 1363 | "node_modules/dir-glob": { 1364 | "version": "3.0.1", 1365 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 1366 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 1367 | "dev": true, 1368 | "dependencies": { 1369 | "path-type": "^4.0.0" 1370 | }, 1371 | "engines": { 1372 | "node": ">=8" 1373 | } 1374 | }, 1375 | "node_modules/doctrine": { 1376 | "version": "3.0.0", 1377 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 1378 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 1379 | "dev": true, 1380 | "dependencies": { 1381 | "esutils": "^2.0.2" 1382 | }, 1383 | "engines": { 1384 | "node": ">=6.0.0" 1385 | } 1386 | }, 1387 | "node_modules/es5-ext": { 1388 | "version": "0.10.62", 1389 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", 1390 | "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", 1391 | "hasInstallScript": true, 1392 | "dependencies": { 1393 | "es6-iterator": "^2.0.3", 1394 | "es6-symbol": "^3.1.3", 1395 | "next-tick": "^1.1.0" 1396 | }, 1397 | "engines": { 1398 | "node": ">=0.10" 1399 | } 1400 | }, 1401 | "node_modules/es6-iterator": { 1402 | "version": "2.0.3", 1403 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", 1404 | "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", 1405 | "dependencies": { 1406 | "d": "1", 1407 | "es5-ext": "^0.10.35", 1408 | "es6-symbol": "^3.1.1" 1409 | } 1410 | }, 1411 | "node_modules/es6-symbol": { 1412 | "version": "3.1.3", 1413 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", 1414 | "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", 1415 | "dependencies": { 1416 | "d": "^1.0.1", 1417 | "ext": "^1.1.2" 1418 | } 1419 | }, 1420 | "node_modules/esbuild": { 1421 | "version": "0.18.17", 1422 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz", 1423 | "integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==", 1424 | "dev": true, 1425 | "hasInstallScript": true, 1426 | "bin": { 1427 | "esbuild": "bin/esbuild" 1428 | }, 1429 | "engines": { 1430 | "node": ">=12" 1431 | }, 1432 | "optionalDependencies": { 1433 | "@esbuild/android-arm": "0.18.17", 1434 | "@esbuild/android-arm64": "0.18.17", 1435 | "@esbuild/android-x64": "0.18.17", 1436 | "@esbuild/darwin-arm64": "0.18.17", 1437 | "@esbuild/darwin-x64": "0.18.17", 1438 | "@esbuild/freebsd-arm64": "0.18.17", 1439 | "@esbuild/freebsd-x64": "0.18.17", 1440 | "@esbuild/linux-arm": "0.18.17", 1441 | "@esbuild/linux-arm64": "0.18.17", 1442 | "@esbuild/linux-ia32": "0.18.17", 1443 | "@esbuild/linux-loong64": "0.18.17", 1444 | "@esbuild/linux-mips64el": "0.18.17", 1445 | "@esbuild/linux-ppc64": "0.18.17", 1446 | "@esbuild/linux-riscv64": "0.18.17", 1447 | "@esbuild/linux-s390x": "0.18.17", 1448 | "@esbuild/linux-x64": "0.18.17", 1449 | "@esbuild/netbsd-x64": "0.18.17", 1450 | "@esbuild/openbsd-x64": "0.18.17", 1451 | "@esbuild/sunos-x64": "0.18.17", 1452 | "@esbuild/win32-arm64": "0.18.17", 1453 | "@esbuild/win32-ia32": "0.18.17", 1454 | "@esbuild/win32-x64": "0.18.17" 1455 | } 1456 | }, 1457 | "node_modules/escape-string-regexp": { 1458 | "version": "4.0.0", 1459 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1460 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 1461 | "dev": true, 1462 | "engines": { 1463 | "node": ">=10" 1464 | }, 1465 | "funding": { 1466 | "url": "https://github.com/sponsors/sindresorhus" 1467 | } 1468 | }, 1469 | "node_modules/eslint": { 1470 | "version": "8.45.0", 1471 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", 1472 | "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", 1473 | "dev": true, 1474 | "dependencies": { 1475 | "@eslint-community/eslint-utils": "^4.2.0", 1476 | "@eslint-community/regexpp": "^4.4.0", 1477 | "@eslint/eslintrc": "^2.1.0", 1478 | "@eslint/js": "8.44.0", 1479 | "@humanwhocodes/config-array": "^0.11.10", 1480 | "@humanwhocodes/module-importer": "^1.0.1", 1481 | "@nodelib/fs.walk": "^1.2.8", 1482 | "ajv": "^6.10.0", 1483 | "chalk": "^4.0.0", 1484 | "cross-spawn": "^7.0.2", 1485 | "debug": "^4.3.2", 1486 | "doctrine": "^3.0.0", 1487 | "escape-string-regexp": "^4.0.0", 1488 | "eslint-scope": "^7.2.0", 1489 | "eslint-visitor-keys": "^3.4.1", 1490 | "espree": "^9.6.0", 1491 | "esquery": "^1.4.2", 1492 | "esutils": "^2.0.2", 1493 | "fast-deep-equal": "^3.1.3", 1494 | "file-entry-cache": "^6.0.1", 1495 | "find-up": "^5.0.0", 1496 | "glob-parent": "^6.0.2", 1497 | "globals": "^13.19.0", 1498 | "graphemer": "^1.4.0", 1499 | "ignore": "^5.2.0", 1500 | "imurmurhash": "^0.1.4", 1501 | "is-glob": "^4.0.0", 1502 | "is-path-inside": "^3.0.3", 1503 | "js-yaml": "^4.1.0", 1504 | "json-stable-stringify-without-jsonify": "^1.0.1", 1505 | "levn": "^0.4.1", 1506 | "lodash.merge": "^4.6.2", 1507 | "minimatch": "^3.1.2", 1508 | "natural-compare": "^1.4.0", 1509 | "optionator": "^0.9.3", 1510 | "strip-ansi": "^6.0.1", 1511 | "text-table": "^0.2.0" 1512 | }, 1513 | "bin": { 1514 | "eslint": "bin/eslint.js" 1515 | }, 1516 | "engines": { 1517 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1518 | }, 1519 | "funding": { 1520 | "url": "https://opencollective.com/eslint" 1521 | } 1522 | }, 1523 | "node_modules/eslint-plugin-immer": { 1524 | "version": "0.0.1", 1525 | "resolved": "https://registry.npmjs.org/eslint-plugin-immer/-/eslint-plugin-immer-0.0.1.tgz", 1526 | "integrity": "sha512-Pb8D9lP4q1fhwefUSElwC1YHvJUWjcz+7saj7n/QPtpPOCwtsEyMK+ypFrLkq99BGGkjAWVJ4xOWEu82JSwKPA==", 1527 | "dependencies": { 1528 | "requireindex": "~1.1.0" 1529 | }, 1530 | "engines": { 1531 | "node": ">=0.10.0" 1532 | } 1533 | }, 1534 | "node_modules/eslint-plugin-react-hooks": { 1535 | "version": "4.6.0", 1536 | "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", 1537 | "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", 1538 | "dev": true, 1539 | "engines": { 1540 | "node": ">=10" 1541 | }, 1542 | "peerDependencies": { 1543 | "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" 1544 | } 1545 | }, 1546 | "node_modules/eslint-plugin-react-refresh": { 1547 | "version": "0.4.3", 1548 | "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.3.tgz", 1549 | "integrity": "sha512-Hh0wv8bUNY877+sI0BlCUlsS0TYYQqvzEwJsJJPM2WF4RnTStSnSR3zdJYa2nPOJgg3UghXi54lVyMSmpCalzA==", 1550 | "dev": true, 1551 | "peerDependencies": { 1552 | "eslint": ">=7" 1553 | } 1554 | }, 1555 | "node_modules/eslint-scope": { 1556 | "version": "7.2.1", 1557 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz", 1558 | "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==", 1559 | "dev": true, 1560 | "dependencies": { 1561 | "esrecurse": "^4.3.0", 1562 | "estraverse": "^5.2.0" 1563 | }, 1564 | "engines": { 1565 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1566 | }, 1567 | "funding": { 1568 | "url": "https://opencollective.com/eslint" 1569 | } 1570 | }, 1571 | "node_modules/eslint-visitor-keys": { 1572 | "version": "3.4.1", 1573 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", 1574 | "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", 1575 | "dev": true, 1576 | "engines": { 1577 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1578 | }, 1579 | "funding": { 1580 | "url": "https://opencollective.com/eslint" 1581 | } 1582 | }, 1583 | "node_modules/espree": { 1584 | "version": "9.6.1", 1585 | "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", 1586 | "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", 1587 | "dev": true, 1588 | "dependencies": { 1589 | "acorn": "^8.9.0", 1590 | "acorn-jsx": "^5.3.2", 1591 | "eslint-visitor-keys": "^3.4.1" 1592 | }, 1593 | "engines": { 1594 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 1595 | }, 1596 | "funding": { 1597 | "url": "https://opencollective.com/eslint" 1598 | } 1599 | }, 1600 | "node_modules/esquery": { 1601 | "version": "1.5.0", 1602 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", 1603 | "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", 1604 | "dev": true, 1605 | "dependencies": { 1606 | "estraverse": "^5.1.0" 1607 | }, 1608 | "engines": { 1609 | "node": ">=0.10" 1610 | } 1611 | }, 1612 | "node_modules/esrecurse": { 1613 | "version": "4.3.0", 1614 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 1615 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 1616 | "dev": true, 1617 | "dependencies": { 1618 | "estraverse": "^5.2.0" 1619 | }, 1620 | "engines": { 1621 | "node": ">=4.0" 1622 | } 1623 | }, 1624 | "node_modules/estraverse": { 1625 | "version": "5.3.0", 1626 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 1627 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 1628 | "dev": true, 1629 | "engines": { 1630 | "node": ">=4.0" 1631 | } 1632 | }, 1633 | "node_modules/esutils": { 1634 | "version": "2.0.3", 1635 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 1636 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 1637 | "dev": true, 1638 | "engines": { 1639 | "node": ">=0.10.0" 1640 | } 1641 | }, 1642 | "node_modules/ext": { 1643 | "version": "1.7.0", 1644 | "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", 1645 | "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", 1646 | "dependencies": { 1647 | "type": "^2.7.2" 1648 | } 1649 | }, 1650 | "node_modules/ext/node_modules/type": { 1651 | "version": "2.7.2", 1652 | "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", 1653 | "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" 1654 | }, 1655 | "node_modules/fast-deep-equal": { 1656 | "version": "3.1.3", 1657 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1658 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 1659 | "dev": true 1660 | }, 1661 | "node_modules/fast-glob": { 1662 | "version": "3.3.1", 1663 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", 1664 | "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", 1665 | "dev": true, 1666 | "dependencies": { 1667 | "@nodelib/fs.stat": "^2.0.2", 1668 | "@nodelib/fs.walk": "^1.2.3", 1669 | "glob-parent": "^5.1.2", 1670 | "merge2": "^1.3.0", 1671 | "micromatch": "^4.0.4" 1672 | }, 1673 | "engines": { 1674 | "node": ">=8.6.0" 1675 | } 1676 | }, 1677 | "node_modules/fast-glob/node_modules/glob-parent": { 1678 | "version": "5.1.2", 1679 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1680 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1681 | "dev": true, 1682 | "dependencies": { 1683 | "is-glob": "^4.0.1" 1684 | }, 1685 | "engines": { 1686 | "node": ">= 6" 1687 | } 1688 | }, 1689 | "node_modules/fast-json-stable-stringify": { 1690 | "version": "2.1.0", 1691 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1692 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 1693 | "dev": true 1694 | }, 1695 | "node_modules/fast-levenshtein": { 1696 | "version": "2.0.6", 1697 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 1698 | "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", 1699 | "dev": true 1700 | }, 1701 | "node_modules/fastq": { 1702 | "version": "1.15.0", 1703 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 1704 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 1705 | "dev": true, 1706 | "dependencies": { 1707 | "reusify": "^1.0.4" 1708 | } 1709 | }, 1710 | "node_modules/fetch-blob": { 1711 | "version": "3.2.0", 1712 | "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", 1713 | "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", 1714 | "dev": true, 1715 | "funding": [ 1716 | { 1717 | "type": "github", 1718 | "url": "https://github.com/sponsors/jimmywarting" 1719 | }, 1720 | { 1721 | "type": "paypal", 1722 | "url": "https://paypal.me/jimmywarting" 1723 | } 1724 | ], 1725 | "dependencies": { 1726 | "node-domexception": "^1.0.0", 1727 | "web-streams-polyfill": "^3.0.3" 1728 | }, 1729 | "engines": { 1730 | "node": "^12.20 || >= 14.13" 1731 | } 1732 | }, 1733 | "node_modules/file-entry-cache": { 1734 | "version": "6.0.1", 1735 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", 1736 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", 1737 | "dev": true, 1738 | "dependencies": { 1739 | "flat-cache": "^3.0.4" 1740 | }, 1741 | "engines": { 1742 | "node": "^10.12.0 || >=12.0.0" 1743 | } 1744 | }, 1745 | "node_modules/fill-range": { 1746 | "version": "7.0.1", 1747 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1748 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1749 | "dev": true, 1750 | "dependencies": { 1751 | "to-regex-range": "^5.0.1" 1752 | }, 1753 | "engines": { 1754 | "node": ">=8" 1755 | } 1756 | }, 1757 | "node_modules/find-up": { 1758 | "version": "5.0.0", 1759 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 1760 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 1761 | "dev": true, 1762 | "dependencies": { 1763 | "locate-path": "^6.0.0", 1764 | "path-exists": "^4.0.0" 1765 | }, 1766 | "engines": { 1767 | "node": ">=10" 1768 | }, 1769 | "funding": { 1770 | "url": "https://github.com/sponsors/sindresorhus" 1771 | } 1772 | }, 1773 | "node_modules/flat-cache": { 1774 | "version": "3.0.4", 1775 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", 1776 | "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", 1777 | "dev": true, 1778 | "dependencies": { 1779 | "flatted": "^3.1.0", 1780 | "rimraf": "^3.0.2" 1781 | }, 1782 | "engines": { 1783 | "node": "^10.12.0 || >=12.0.0" 1784 | } 1785 | }, 1786 | "node_modules/flatted": { 1787 | "version": "3.2.7", 1788 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", 1789 | "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", 1790 | "dev": true 1791 | }, 1792 | "node_modules/formdata-polyfill": { 1793 | "version": "4.0.10", 1794 | "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", 1795 | "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", 1796 | "dev": true, 1797 | "dependencies": { 1798 | "fetch-blob": "^3.1.2" 1799 | }, 1800 | "engines": { 1801 | "node": ">=12.20.0" 1802 | } 1803 | }, 1804 | "node_modules/fs-minipass": { 1805 | "version": "2.1.0", 1806 | "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", 1807 | "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", 1808 | "dev": true, 1809 | "dependencies": { 1810 | "minipass": "^3.0.0" 1811 | }, 1812 | "engines": { 1813 | "node": ">= 8" 1814 | } 1815 | }, 1816 | "node_modules/fs-minipass/node_modules/minipass": { 1817 | "version": "3.3.6", 1818 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", 1819 | "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", 1820 | "dev": true, 1821 | "dependencies": { 1822 | "yallist": "^4.0.0" 1823 | }, 1824 | "engines": { 1825 | "node": ">=8" 1826 | } 1827 | }, 1828 | "node_modules/fs.realpath": { 1829 | "version": "1.0.0", 1830 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1831 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 1832 | "dev": true 1833 | }, 1834 | "node_modules/fsevents": { 1835 | "version": "2.3.2", 1836 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1837 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1838 | "dev": true, 1839 | "hasInstallScript": true, 1840 | "optional": true, 1841 | "os": [ 1842 | "darwin" 1843 | ], 1844 | "engines": { 1845 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1846 | } 1847 | }, 1848 | "node_modules/glob": { 1849 | "version": "7.2.3", 1850 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 1851 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 1852 | "dev": true, 1853 | "dependencies": { 1854 | "fs.realpath": "^1.0.0", 1855 | "inflight": "^1.0.4", 1856 | "inherits": "2", 1857 | "minimatch": "^3.1.1", 1858 | "once": "^1.3.0", 1859 | "path-is-absolute": "^1.0.0" 1860 | }, 1861 | "engines": { 1862 | "node": "*" 1863 | }, 1864 | "funding": { 1865 | "url": "https://github.com/sponsors/isaacs" 1866 | } 1867 | }, 1868 | "node_modules/glob-parent": { 1869 | "version": "6.0.2", 1870 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 1871 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 1872 | "dev": true, 1873 | "dependencies": { 1874 | "is-glob": "^4.0.3" 1875 | }, 1876 | "engines": { 1877 | "node": ">=10.13.0" 1878 | } 1879 | }, 1880 | "node_modules/globals": { 1881 | "version": "13.20.0", 1882 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", 1883 | "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", 1884 | "dev": true, 1885 | "dependencies": { 1886 | "type-fest": "^0.20.2" 1887 | }, 1888 | "engines": { 1889 | "node": ">=8" 1890 | }, 1891 | "funding": { 1892 | "url": "https://github.com/sponsors/sindresorhus" 1893 | } 1894 | }, 1895 | "node_modules/globby": { 1896 | "version": "11.1.0", 1897 | "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", 1898 | "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", 1899 | "dev": true, 1900 | "dependencies": { 1901 | "array-union": "^2.1.0", 1902 | "dir-glob": "^3.0.1", 1903 | "fast-glob": "^3.2.9", 1904 | "ignore": "^5.2.0", 1905 | "merge2": "^1.4.1", 1906 | "slash": "^3.0.0" 1907 | }, 1908 | "engines": { 1909 | "node": ">=10" 1910 | }, 1911 | "funding": { 1912 | "url": "https://github.com/sponsors/sindresorhus" 1913 | } 1914 | }, 1915 | "node_modules/graphemer": { 1916 | "version": "1.4.0", 1917 | "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", 1918 | "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", 1919 | "dev": true 1920 | }, 1921 | "node_modules/has-flag": { 1922 | "version": "4.0.0", 1923 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1924 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1925 | "dev": true, 1926 | "engines": { 1927 | "node": ">=8" 1928 | } 1929 | }, 1930 | "node_modules/ignore": { 1931 | "version": "5.2.4", 1932 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", 1933 | "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", 1934 | "dev": true, 1935 | "engines": { 1936 | "node": ">= 4" 1937 | } 1938 | }, 1939 | "node_modules/immer": { 1940 | "version": "10.0.2", 1941 | "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.2.tgz", 1942 | "integrity": "sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA==", 1943 | "peer": true, 1944 | "funding": { 1945 | "type": "opencollective", 1946 | "url": "https://opencollective.com/immer" 1947 | } 1948 | }, 1949 | "node_modules/import-fresh": { 1950 | "version": "3.3.0", 1951 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 1952 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 1953 | "dev": true, 1954 | "dependencies": { 1955 | "parent-module": "^1.0.0", 1956 | "resolve-from": "^4.0.0" 1957 | }, 1958 | "engines": { 1959 | "node": ">=6" 1960 | }, 1961 | "funding": { 1962 | "url": "https://github.com/sponsors/sindresorhus" 1963 | } 1964 | }, 1965 | "node_modules/imurmurhash": { 1966 | "version": "0.1.4", 1967 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1968 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 1969 | "dev": true, 1970 | "engines": { 1971 | "node": ">=0.8.19" 1972 | } 1973 | }, 1974 | "node_modules/inflight": { 1975 | "version": "1.0.6", 1976 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1977 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 1978 | "dev": true, 1979 | "dependencies": { 1980 | "once": "^1.3.0", 1981 | "wrappy": "1" 1982 | } 1983 | }, 1984 | "node_modules/inherits": { 1985 | "version": "2.0.4", 1986 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1987 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1988 | "dev": true 1989 | }, 1990 | "node_modules/is-extglob": { 1991 | "version": "2.1.1", 1992 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1993 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1994 | "dev": true, 1995 | "engines": { 1996 | "node": ">=0.10.0" 1997 | } 1998 | }, 1999 | "node_modules/is-glob": { 2000 | "version": "4.0.3", 2001 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 2002 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 2003 | "dev": true, 2004 | "dependencies": { 2005 | "is-extglob": "^2.1.1" 2006 | }, 2007 | "engines": { 2008 | "node": ">=0.10.0" 2009 | } 2010 | }, 2011 | "node_modules/is-number": { 2012 | "version": "7.0.0", 2013 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 2014 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 2015 | "dev": true, 2016 | "engines": { 2017 | "node": ">=0.12.0" 2018 | } 2019 | }, 2020 | "node_modules/is-path-inside": { 2021 | "version": "3.0.3", 2022 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", 2023 | "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", 2024 | "dev": true, 2025 | "engines": { 2026 | "node": ">=8" 2027 | } 2028 | }, 2029 | "node_modules/is-typedarray": { 2030 | "version": "1.0.0", 2031 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 2032 | "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" 2033 | }, 2034 | "node_modules/isexe": { 2035 | "version": "2.0.0", 2036 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 2037 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 2038 | "dev": true 2039 | }, 2040 | "node_modules/js-tokens": { 2041 | "version": "4.0.0", 2042 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 2043 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 2044 | }, 2045 | "node_modules/js-yaml": { 2046 | "version": "4.1.0", 2047 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 2048 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 2049 | "dev": true, 2050 | "dependencies": { 2051 | "argparse": "^2.0.1" 2052 | }, 2053 | "bin": { 2054 | "js-yaml": "bin/js-yaml.js" 2055 | } 2056 | }, 2057 | "node_modules/json-schema-traverse": { 2058 | "version": "0.4.1", 2059 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 2060 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 2061 | "dev": true 2062 | }, 2063 | "node_modules/json-stable-stringify-without-jsonify": { 2064 | "version": "1.0.1", 2065 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 2066 | "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", 2067 | "dev": true 2068 | }, 2069 | "node_modules/levn": { 2070 | "version": "0.4.1", 2071 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 2072 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 2073 | "dev": true, 2074 | "dependencies": { 2075 | "prelude-ls": "^1.2.1", 2076 | "type-check": "~0.4.0" 2077 | }, 2078 | "engines": { 2079 | "node": ">= 0.8.0" 2080 | } 2081 | }, 2082 | "node_modules/locate-path": { 2083 | "version": "6.0.0", 2084 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 2085 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 2086 | "dev": true, 2087 | "dependencies": { 2088 | "p-locate": "^5.0.0" 2089 | }, 2090 | "engines": { 2091 | "node": ">=10" 2092 | }, 2093 | "funding": { 2094 | "url": "https://github.com/sponsors/sindresorhus" 2095 | } 2096 | }, 2097 | "node_modules/lodash.merge": { 2098 | "version": "4.6.2", 2099 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 2100 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 2101 | "dev": true 2102 | }, 2103 | "node_modules/loose-envify": { 2104 | "version": "1.4.0", 2105 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 2106 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 2107 | "dependencies": { 2108 | "js-tokens": "^3.0.0 || ^4.0.0" 2109 | }, 2110 | "bin": { 2111 | "loose-envify": "cli.js" 2112 | } 2113 | }, 2114 | "node_modules/lru-cache": { 2115 | "version": "6.0.0", 2116 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 2117 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 2118 | "dev": true, 2119 | "dependencies": { 2120 | "yallist": "^4.0.0" 2121 | }, 2122 | "engines": { 2123 | "node": ">=10" 2124 | } 2125 | }, 2126 | "node_modules/merge2": { 2127 | "version": "1.4.1", 2128 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 2129 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 2130 | "dev": true, 2131 | "engines": { 2132 | "node": ">= 8" 2133 | } 2134 | }, 2135 | "node_modules/micromatch": { 2136 | "version": "4.0.5", 2137 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 2138 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 2139 | "dev": true, 2140 | "dependencies": { 2141 | "braces": "^3.0.2", 2142 | "picomatch": "^2.3.1" 2143 | }, 2144 | "engines": { 2145 | "node": ">=8.6" 2146 | } 2147 | }, 2148 | "node_modules/minimatch": { 2149 | "version": "3.1.2", 2150 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 2151 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 2152 | "dev": true, 2153 | "dependencies": { 2154 | "brace-expansion": "^1.1.7" 2155 | }, 2156 | "engines": { 2157 | "node": "*" 2158 | } 2159 | }, 2160 | "node_modules/minipass": { 2161 | "version": "5.0.0", 2162 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", 2163 | "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", 2164 | "dev": true, 2165 | "engines": { 2166 | "node": ">=8" 2167 | } 2168 | }, 2169 | "node_modules/minizlib": { 2170 | "version": "2.1.2", 2171 | "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", 2172 | "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", 2173 | "dev": true, 2174 | "dependencies": { 2175 | "minipass": "^3.0.0", 2176 | "yallist": "^4.0.0" 2177 | }, 2178 | "engines": { 2179 | "node": ">= 8" 2180 | } 2181 | }, 2182 | "node_modules/minizlib/node_modules/minipass": { 2183 | "version": "3.3.6", 2184 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", 2185 | "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", 2186 | "dev": true, 2187 | "dependencies": { 2188 | "yallist": "^4.0.0" 2189 | }, 2190 | "engines": { 2191 | "node": ">=8" 2192 | } 2193 | }, 2194 | "node_modules/mkdirp": { 2195 | "version": "1.0.4", 2196 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 2197 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", 2198 | "dev": true, 2199 | "bin": { 2200 | "mkdirp": "bin/cmd.js" 2201 | }, 2202 | "engines": { 2203 | "node": ">=10" 2204 | } 2205 | }, 2206 | "node_modules/ms": { 2207 | "version": "2.1.2", 2208 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 2209 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 2210 | "dev": true 2211 | }, 2212 | "node_modules/nanoid": { 2213 | "version": "4.0.2", 2214 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz", 2215 | "integrity": "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==", 2216 | "funding": [ 2217 | { 2218 | "type": "github", 2219 | "url": "https://github.com/sponsors/ai" 2220 | } 2221 | ], 2222 | "bin": { 2223 | "nanoid": "bin/nanoid.js" 2224 | }, 2225 | "engines": { 2226 | "node": "^14 || ^16 || >=18" 2227 | } 2228 | }, 2229 | "node_modules/natural-compare": { 2230 | "version": "1.4.0", 2231 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 2232 | "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", 2233 | "dev": true 2234 | }, 2235 | "node_modules/natural-compare-lite": { 2236 | "version": "1.4.0", 2237 | "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", 2238 | "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", 2239 | "dev": true 2240 | }, 2241 | "node_modules/next-tick": { 2242 | "version": "1.1.0", 2243 | "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", 2244 | "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" 2245 | }, 2246 | "node_modules/node-domexception": { 2247 | "version": "1.0.0", 2248 | "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", 2249 | "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", 2250 | "dev": true, 2251 | "funding": [ 2252 | { 2253 | "type": "github", 2254 | "url": "https://github.com/sponsors/jimmywarting" 2255 | }, 2256 | { 2257 | "type": "github", 2258 | "url": "https://paypal.me/jimmywarting" 2259 | } 2260 | ], 2261 | "engines": { 2262 | "node": ">=10.5.0" 2263 | } 2264 | }, 2265 | "node_modules/node-fetch": { 2266 | "version": "2.6.12", 2267 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", 2268 | "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", 2269 | "dependencies": { 2270 | "whatwg-url": "^5.0.0" 2271 | }, 2272 | "engines": { 2273 | "node": "4.x || >=6.0.0" 2274 | }, 2275 | "peerDependencies": { 2276 | "encoding": "^0.1.0" 2277 | }, 2278 | "peerDependenciesMeta": { 2279 | "encoding": { 2280 | "optional": true 2281 | } 2282 | } 2283 | }, 2284 | "node_modules/node-gyp-build": { 2285 | "version": "4.6.0", 2286 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", 2287 | "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", 2288 | "bin": { 2289 | "node-gyp-build": "bin.js", 2290 | "node-gyp-build-optional": "optional.js", 2291 | "node-gyp-build-test": "build-test.js" 2292 | } 2293 | }, 2294 | "node_modules/npm-normalize-package-bin": { 2295 | "version": "3.0.1", 2296 | "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", 2297 | "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", 2298 | "dev": true, 2299 | "engines": { 2300 | "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 2301 | } 2302 | }, 2303 | "node_modules/once": { 2304 | "version": "1.4.0", 2305 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 2306 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 2307 | "dev": true, 2308 | "dependencies": { 2309 | "wrappy": "1" 2310 | } 2311 | }, 2312 | "node_modules/optionator": { 2313 | "version": "0.9.3", 2314 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", 2315 | "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", 2316 | "dev": true, 2317 | "dependencies": { 2318 | "@aashutoshrathi/word-wrap": "^1.2.3", 2319 | "deep-is": "^0.1.3", 2320 | "fast-levenshtein": "^2.0.6", 2321 | "levn": "^0.4.1", 2322 | "prelude-ls": "^1.2.1", 2323 | "type-check": "^0.4.0" 2324 | }, 2325 | "engines": { 2326 | "node": ">= 0.8.0" 2327 | } 2328 | }, 2329 | "node_modules/p-limit": { 2330 | "version": "3.1.0", 2331 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 2332 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 2333 | "dev": true, 2334 | "dependencies": { 2335 | "yocto-queue": "^0.1.0" 2336 | }, 2337 | "engines": { 2338 | "node": ">=10" 2339 | }, 2340 | "funding": { 2341 | "url": "https://github.com/sponsors/sindresorhus" 2342 | } 2343 | }, 2344 | "node_modules/p-locate": { 2345 | "version": "5.0.0", 2346 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 2347 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 2348 | "dev": true, 2349 | "dependencies": { 2350 | "p-limit": "^3.0.2" 2351 | }, 2352 | "engines": { 2353 | "node": ">=10" 2354 | }, 2355 | "funding": { 2356 | "url": "https://github.com/sponsors/sindresorhus" 2357 | } 2358 | }, 2359 | "node_modules/parent-module": { 2360 | "version": "1.0.1", 2361 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 2362 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 2363 | "dev": true, 2364 | "dependencies": { 2365 | "callsites": "^3.0.0" 2366 | }, 2367 | "engines": { 2368 | "node": ">=6" 2369 | } 2370 | }, 2371 | "node_modules/path-exists": { 2372 | "version": "4.0.0", 2373 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 2374 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 2375 | "dev": true, 2376 | "engines": { 2377 | "node": ">=8" 2378 | } 2379 | }, 2380 | "node_modules/path-is-absolute": { 2381 | "version": "1.0.1", 2382 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 2383 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 2384 | "dev": true, 2385 | "engines": { 2386 | "node": ">=0.10.0" 2387 | } 2388 | }, 2389 | "node_modules/path-key": { 2390 | "version": "3.1.1", 2391 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 2392 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 2393 | "dev": true, 2394 | "engines": { 2395 | "node": ">=8" 2396 | } 2397 | }, 2398 | "node_modules/path-type": { 2399 | "version": "4.0.0", 2400 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 2401 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 2402 | "dev": true, 2403 | "engines": { 2404 | "node": ">=8" 2405 | } 2406 | }, 2407 | "node_modules/picocolors": { 2408 | "version": "1.0.0", 2409 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 2410 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 2411 | "dev": true 2412 | }, 2413 | "node_modules/picomatch": { 2414 | "version": "2.3.1", 2415 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 2416 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 2417 | "dev": true, 2418 | "engines": { 2419 | "node": ">=8.6" 2420 | }, 2421 | "funding": { 2422 | "url": "https://github.com/sponsors/jonschlinkert" 2423 | } 2424 | }, 2425 | "node_modules/postcss": { 2426 | "version": "8.4.27", 2427 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", 2428 | "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", 2429 | "dev": true, 2430 | "funding": [ 2431 | { 2432 | "type": "opencollective", 2433 | "url": "https://opencollective.com/postcss/" 2434 | }, 2435 | { 2436 | "type": "tidelift", 2437 | "url": "https://tidelift.com/funding/github/npm/postcss" 2438 | }, 2439 | { 2440 | "type": "github", 2441 | "url": "https://github.com/sponsors/ai" 2442 | } 2443 | ], 2444 | "dependencies": { 2445 | "nanoid": "^3.3.6", 2446 | "picocolors": "^1.0.0", 2447 | "source-map-js": "^1.0.2" 2448 | }, 2449 | "engines": { 2450 | "node": "^10 || ^12 || >=14" 2451 | } 2452 | }, 2453 | "node_modules/postcss/node_modules/nanoid": { 2454 | "version": "3.3.6", 2455 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 2456 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 2457 | "dev": true, 2458 | "funding": [ 2459 | { 2460 | "type": "github", 2461 | "url": "https://github.com/sponsors/ai" 2462 | } 2463 | ], 2464 | "bin": { 2465 | "nanoid": "bin/nanoid.cjs" 2466 | }, 2467 | "engines": { 2468 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 2469 | } 2470 | }, 2471 | "node_modules/prelude-ls": { 2472 | "version": "1.2.1", 2473 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 2474 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 2475 | "dev": true, 2476 | "engines": { 2477 | "node": ">= 0.8.0" 2478 | } 2479 | }, 2480 | "node_modules/punycode": { 2481 | "version": "2.3.0", 2482 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", 2483 | "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", 2484 | "dev": true, 2485 | "engines": { 2486 | "node": ">=6" 2487 | } 2488 | }, 2489 | "node_modules/queue-microtask": { 2490 | "version": "1.2.3", 2491 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 2492 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 2493 | "dev": true, 2494 | "funding": [ 2495 | { 2496 | "type": "github", 2497 | "url": "https://github.com/sponsors/feross" 2498 | }, 2499 | { 2500 | "type": "patreon", 2501 | "url": "https://www.patreon.com/feross" 2502 | }, 2503 | { 2504 | "type": "consulting", 2505 | "url": "https://feross.org/support" 2506 | } 2507 | ] 2508 | }, 2509 | "node_modules/react": { 2510 | "version": "18.2.0", 2511 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", 2512 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", 2513 | "dependencies": { 2514 | "loose-envify": "^1.1.0" 2515 | }, 2516 | "engines": { 2517 | "node": ">=0.10.0" 2518 | } 2519 | }, 2520 | "node_modules/react-dom": { 2521 | "version": "18.2.0", 2522 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", 2523 | "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", 2524 | "dependencies": { 2525 | "loose-envify": "^1.1.0", 2526 | "scheduler": "^0.23.0" 2527 | }, 2528 | "peerDependencies": { 2529 | "react": "^18.2.0" 2530 | } 2531 | }, 2532 | "node_modules/react-router": { 2533 | "version": "6.14.2", 2534 | "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.2.tgz", 2535 | "integrity": "sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==", 2536 | "dependencies": { 2537 | "@remix-run/router": "1.7.2" 2538 | }, 2539 | "engines": { 2540 | "node": ">=14" 2541 | }, 2542 | "peerDependencies": { 2543 | "react": ">=16.8" 2544 | } 2545 | }, 2546 | "node_modules/react-router-dom": { 2547 | "version": "6.14.2", 2548 | "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.2.tgz", 2549 | "integrity": "sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==", 2550 | "dependencies": { 2551 | "@remix-run/router": "1.7.2", 2552 | "react-router": "6.14.2" 2553 | }, 2554 | "engines": { 2555 | "node": ">=14" 2556 | }, 2557 | "peerDependencies": { 2558 | "react": ">=16.8", 2559 | "react-dom": ">=16.8" 2560 | } 2561 | }, 2562 | "node_modules/read-cmd-shim": { 2563 | "version": "4.0.0", 2564 | "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz", 2565 | "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==", 2566 | "dev": true, 2567 | "engines": { 2568 | "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 2569 | } 2570 | }, 2571 | "node_modules/requireindex": { 2572 | "version": "1.1.0", 2573 | "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", 2574 | "integrity": "sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==", 2575 | "engines": { 2576 | "node": ">=0.10.5" 2577 | } 2578 | }, 2579 | "node_modules/resolve-from": { 2580 | "version": "4.0.0", 2581 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 2582 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 2583 | "dev": true, 2584 | "engines": { 2585 | "node": ">=4" 2586 | } 2587 | }, 2588 | "node_modules/reusify": { 2589 | "version": "1.0.4", 2590 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 2591 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 2592 | "dev": true, 2593 | "engines": { 2594 | "iojs": ">=1.0.0", 2595 | "node": ">=0.10.0" 2596 | } 2597 | }, 2598 | "node_modules/rimraf": { 2599 | "version": "3.0.2", 2600 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 2601 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 2602 | "dev": true, 2603 | "dependencies": { 2604 | "glob": "^7.1.3" 2605 | }, 2606 | "bin": { 2607 | "rimraf": "bin.js" 2608 | }, 2609 | "funding": { 2610 | "url": "https://github.com/sponsors/isaacs" 2611 | } 2612 | }, 2613 | "node_modules/rollup": { 2614 | "version": "3.26.3", 2615 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.3.tgz", 2616 | "integrity": "sha512-7Tin0C8l86TkpcMtXvQu6saWH93nhG3dGQ1/+l5V2TDMceTxO7kDiK6GzbfLWNNxqJXm591PcEZUozZm51ogwQ==", 2617 | "dev": true, 2618 | "bin": { 2619 | "rollup": "dist/bin/rollup" 2620 | }, 2621 | "engines": { 2622 | "node": ">=14.18.0", 2623 | "npm": ">=8.0.0" 2624 | }, 2625 | "optionalDependencies": { 2626 | "fsevents": "~2.3.2" 2627 | } 2628 | }, 2629 | "node_modules/run-parallel": { 2630 | "version": "1.2.0", 2631 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 2632 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 2633 | "dev": true, 2634 | "funding": [ 2635 | { 2636 | "type": "github", 2637 | "url": "https://github.com/sponsors/feross" 2638 | }, 2639 | { 2640 | "type": "patreon", 2641 | "url": "https://www.patreon.com/feross" 2642 | }, 2643 | { 2644 | "type": "consulting", 2645 | "url": "https://feross.org/support" 2646 | } 2647 | ], 2648 | "dependencies": { 2649 | "queue-microtask": "^1.2.2" 2650 | } 2651 | }, 2652 | "node_modules/scheduler": { 2653 | "version": "0.23.0", 2654 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", 2655 | "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", 2656 | "dependencies": { 2657 | "loose-envify": "^1.1.0" 2658 | } 2659 | }, 2660 | "node_modules/semver": { 2661 | "version": "7.5.4", 2662 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", 2663 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", 2664 | "dev": true, 2665 | "dependencies": { 2666 | "lru-cache": "^6.0.0" 2667 | }, 2668 | "bin": { 2669 | "semver": "bin/semver.js" 2670 | }, 2671 | "engines": { 2672 | "node": ">=10" 2673 | } 2674 | }, 2675 | "node_modules/shebang-command": { 2676 | "version": "2.0.0", 2677 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 2678 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 2679 | "dev": true, 2680 | "dependencies": { 2681 | "shebang-regex": "^3.0.0" 2682 | }, 2683 | "engines": { 2684 | "node": ">=8" 2685 | } 2686 | }, 2687 | "node_modules/shebang-regex": { 2688 | "version": "3.0.0", 2689 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 2690 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 2691 | "dev": true, 2692 | "engines": { 2693 | "node": ">=8" 2694 | } 2695 | }, 2696 | "node_modules/signal-exit": { 2697 | "version": "4.1.0", 2698 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 2699 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 2700 | "dev": true, 2701 | "engines": { 2702 | "node": ">=14" 2703 | }, 2704 | "funding": { 2705 | "url": "https://github.com/sponsors/isaacs" 2706 | } 2707 | }, 2708 | "node_modules/slash": { 2709 | "version": "3.0.0", 2710 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 2711 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 2712 | "dev": true, 2713 | "engines": { 2714 | "node": ">=8" 2715 | } 2716 | }, 2717 | "node_modules/source-map-js": { 2718 | "version": "1.0.2", 2719 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 2720 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 2721 | "dev": true, 2722 | "engines": { 2723 | "node": ">=0.10.0" 2724 | } 2725 | }, 2726 | "node_modules/strip-ansi": { 2727 | "version": "6.0.1", 2728 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 2729 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 2730 | "dev": true, 2731 | "dependencies": { 2732 | "ansi-regex": "^5.0.1" 2733 | }, 2734 | "engines": { 2735 | "node": ">=8" 2736 | } 2737 | }, 2738 | "node_modules/strip-json-comments": { 2739 | "version": "3.1.1", 2740 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 2741 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 2742 | "dev": true, 2743 | "engines": { 2744 | "node": ">=8" 2745 | }, 2746 | "funding": { 2747 | "url": "https://github.com/sponsors/sindresorhus" 2748 | } 2749 | }, 2750 | "node_modules/supabase": { 2751 | "version": "1.82.5", 2752 | "resolved": "https://registry.npmjs.org/supabase/-/supabase-1.82.5.tgz", 2753 | "integrity": "sha512-mqLAFNB450NDQC2mG/DKRS09zsRflO8YtUuY+O2NhuUYCuZTMbqRU0XdQmh3ImvKcXWtnZTJtORZ2clAx8NlLA==", 2754 | "dev": true, 2755 | "hasInstallScript": true, 2756 | "dependencies": { 2757 | "bin-links": "^4.0.1", 2758 | "node-fetch": "^3.2.10", 2759 | "tar": "6.1.15" 2760 | }, 2761 | "bin": { 2762 | "supabase": "bin/supabase" 2763 | }, 2764 | "engines": { 2765 | "npm": ">=8" 2766 | } 2767 | }, 2768 | "node_modules/supabase/node_modules/node-fetch": { 2769 | "version": "3.3.2", 2770 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", 2771 | "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", 2772 | "dev": true, 2773 | "dependencies": { 2774 | "data-uri-to-buffer": "^4.0.0", 2775 | "fetch-blob": "^3.1.4", 2776 | "formdata-polyfill": "^4.0.10" 2777 | }, 2778 | "engines": { 2779 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 2780 | }, 2781 | "funding": { 2782 | "type": "opencollective", 2783 | "url": "https://opencollective.com/node-fetch" 2784 | } 2785 | }, 2786 | "node_modules/supports-color": { 2787 | "version": "7.2.0", 2788 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 2789 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 2790 | "dev": true, 2791 | "dependencies": { 2792 | "has-flag": "^4.0.0" 2793 | }, 2794 | "engines": { 2795 | "node": ">=8" 2796 | } 2797 | }, 2798 | "node_modules/tar": { 2799 | "version": "6.1.15", 2800 | "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", 2801 | "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", 2802 | "dev": true, 2803 | "dependencies": { 2804 | "chownr": "^2.0.0", 2805 | "fs-minipass": "^2.0.0", 2806 | "minipass": "^5.0.0", 2807 | "minizlib": "^2.1.1", 2808 | "mkdirp": "^1.0.3", 2809 | "yallist": "^4.0.0" 2810 | }, 2811 | "engines": { 2812 | "node": ">=10" 2813 | } 2814 | }, 2815 | "node_modules/text-table": { 2816 | "version": "0.2.0", 2817 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 2818 | "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", 2819 | "dev": true 2820 | }, 2821 | "node_modules/to-regex-range": { 2822 | "version": "5.0.1", 2823 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 2824 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 2825 | "dev": true, 2826 | "dependencies": { 2827 | "is-number": "^7.0.0" 2828 | }, 2829 | "engines": { 2830 | "node": ">=8.0" 2831 | } 2832 | }, 2833 | "node_modules/tr46": { 2834 | "version": "0.0.3", 2835 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 2836 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 2837 | }, 2838 | "node_modules/ts-api-utils": { 2839 | "version": "1.0.1", 2840 | "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", 2841 | "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", 2842 | "dev": true, 2843 | "engines": { 2844 | "node": ">=16.13.0" 2845 | }, 2846 | "peerDependencies": { 2847 | "typescript": ">=4.2.0" 2848 | } 2849 | }, 2850 | "node_modules/tslib": { 2851 | "version": "2.6.1", 2852 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", 2853 | "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" 2854 | }, 2855 | "node_modules/type": { 2856 | "version": "1.2.0", 2857 | "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", 2858 | "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" 2859 | }, 2860 | "node_modules/type-check": { 2861 | "version": "0.4.0", 2862 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 2863 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 2864 | "dev": true, 2865 | "dependencies": { 2866 | "prelude-ls": "^1.2.1" 2867 | }, 2868 | "engines": { 2869 | "node": ">= 0.8.0" 2870 | } 2871 | }, 2872 | "node_modules/type-fest": { 2873 | "version": "0.20.2", 2874 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 2875 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", 2876 | "dev": true, 2877 | "engines": { 2878 | "node": ">=10" 2879 | }, 2880 | "funding": { 2881 | "url": "https://github.com/sponsors/sindresorhus" 2882 | } 2883 | }, 2884 | "node_modules/typedarray-to-buffer": { 2885 | "version": "3.1.5", 2886 | "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", 2887 | "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", 2888 | "dependencies": { 2889 | "is-typedarray": "^1.0.0" 2890 | } 2891 | }, 2892 | "node_modules/typescript": { 2893 | "version": "5.1.6", 2894 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", 2895 | "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", 2896 | "dev": true, 2897 | "bin": { 2898 | "tsc": "bin/tsc", 2899 | "tsserver": "bin/tsserver" 2900 | }, 2901 | "engines": { 2902 | "node": ">=14.17" 2903 | } 2904 | }, 2905 | "node_modules/uri-js": { 2906 | "version": "4.4.1", 2907 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 2908 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 2909 | "dev": true, 2910 | "dependencies": { 2911 | "punycode": "^2.1.0" 2912 | } 2913 | }, 2914 | "node_modules/use-immer": { 2915 | "version": "0.9.0", 2916 | "resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.9.0.tgz", 2917 | "integrity": "sha512-/L+enLi0nvuZ6j4WlyK0US9/ECUtV5v9RUbtxnn5+WbtaXYUaOBoKHDNL9I5AETdurQ4rIFIj/s+Z5X80ATyKw==", 2918 | "peerDependencies": { 2919 | "immer": ">=2.0.0", 2920 | "react": "^16.8.0 || ^17.0.1 || ^18.0.0" 2921 | } 2922 | }, 2923 | "node_modules/utf-8-validate": { 2924 | "version": "5.0.10", 2925 | "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", 2926 | "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", 2927 | "hasInstallScript": true, 2928 | "dependencies": { 2929 | "node-gyp-build": "^4.3.0" 2930 | }, 2931 | "engines": { 2932 | "node": ">=6.14.2" 2933 | } 2934 | }, 2935 | "node_modules/vite": { 2936 | "version": "4.4.7", 2937 | "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz", 2938 | "integrity": "sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==", 2939 | "dev": true, 2940 | "dependencies": { 2941 | "esbuild": "^0.18.10", 2942 | "postcss": "^8.4.26", 2943 | "rollup": "^3.25.2" 2944 | }, 2945 | "bin": { 2946 | "vite": "bin/vite.js" 2947 | }, 2948 | "engines": { 2949 | "node": "^14.18.0 || >=16.0.0" 2950 | }, 2951 | "funding": { 2952 | "url": "https://github.com/vitejs/vite?sponsor=1" 2953 | }, 2954 | "optionalDependencies": { 2955 | "fsevents": "~2.3.2" 2956 | }, 2957 | "peerDependencies": { 2958 | "@types/node": ">= 14", 2959 | "less": "*", 2960 | "lightningcss": "^1.21.0", 2961 | "sass": "*", 2962 | "stylus": "*", 2963 | "sugarss": "*", 2964 | "terser": "^5.4.0" 2965 | }, 2966 | "peerDependenciesMeta": { 2967 | "@types/node": { 2968 | "optional": true 2969 | }, 2970 | "less": { 2971 | "optional": true 2972 | }, 2973 | "lightningcss": { 2974 | "optional": true 2975 | }, 2976 | "sass": { 2977 | "optional": true 2978 | }, 2979 | "stylus": { 2980 | "optional": true 2981 | }, 2982 | "sugarss": { 2983 | "optional": true 2984 | }, 2985 | "terser": { 2986 | "optional": true 2987 | } 2988 | } 2989 | }, 2990 | "node_modules/web-streams-polyfill": { 2991 | "version": "3.2.1", 2992 | "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", 2993 | "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", 2994 | "dev": true, 2995 | "engines": { 2996 | "node": ">= 8" 2997 | } 2998 | }, 2999 | "node_modules/webidl-conversions": { 3000 | "version": "3.0.1", 3001 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 3002 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 3003 | }, 3004 | "node_modules/websocket": { 3005 | "version": "1.0.34", 3006 | "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", 3007 | "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", 3008 | "dependencies": { 3009 | "bufferutil": "^4.0.1", 3010 | "debug": "^2.2.0", 3011 | "es5-ext": "^0.10.50", 3012 | "typedarray-to-buffer": "^3.1.5", 3013 | "utf-8-validate": "^5.0.2", 3014 | "yaeti": "^0.0.6" 3015 | }, 3016 | "engines": { 3017 | "node": ">=4.0.0" 3018 | } 3019 | }, 3020 | "node_modules/websocket/node_modules/debug": { 3021 | "version": "2.6.9", 3022 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 3023 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 3024 | "dependencies": { 3025 | "ms": "2.0.0" 3026 | } 3027 | }, 3028 | "node_modules/websocket/node_modules/ms": { 3029 | "version": "2.0.0", 3030 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 3031 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 3032 | }, 3033 | "node_modules/whatwg-url": { 3034 | "version": "5.0.0", 3035 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 3036 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 3037 | "dependencies": { 3038 | "tr46": "~0.0.3", 3039 | "webidl-conversions": "^3.0.0" 3040 | } 3041 | }, 3042 | "node_modules/which": { 3043 | "version": "2.0.2", 3044 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 3045 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 3046 | "dev": true, 3047 | "dependencies": { 3048 | "isexe": "^2.0.0" 3049 | }, 3050 | "bin": { 3051 | "node-which": "bin/node-which" 3052 | }, 3053 | "engines": { 3054 | "node": ">= 8" 3055 | } 3056 | }, 3057 | "node_modules/wrappy": { 3058 | "version": "1.0.2", 3059 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 3060 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 3061 | "dev": true 3062 | }, 3063 | "node_modules/write-file-atomic": { 3064 | "version": "5.0.1", 3065 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", 3066 | "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", 3067 | "dev": true, 3068 | "dependencies": { 3069 | "imurmurhash": "^0.1.4", 3070 | "signal-exit": "^4.0.1" 3071 | }, 3072 | "engines": { 3073 | "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 3074 | } 3075 | }, 3076 | "node_modules/yaeti": { 3077 | "version": "0.0.6", 3078 | "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", 3079 | "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", 3080 | "engines": { 3081 | "node": ">=0.10.32" 3082 | } 3083 | }, 3084 | "node_modules/yallist": { 3085 | "version": "4.0.0", 3086 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 3087 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 3088 | "dev": true 3089 | }, 3090 | "node_modules/yocto-queue": { 3091 | "version": "0.1.0", 3092 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 3093 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 3094 | "dev": true, 3095 | "engines": { 3096 | "node": ">=10" 3097 | }, 3098 | "funding": { 3099 | "url": "https://github.com/sponsors/sindresorhus" 3100 | } 3101 | } 3102 | } 3103 | } 3104 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ztm-notion-clone", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview", 11 | "supabase:start": "supabase start", 12 | "supabase:init": "supabase init" 13 | }, 14 | "dependencies": { 15 | "@dnd-kit/core": "^6.0.8", 16 | "@dnd-kit/sortable": "^7.0.2", 17 | "@supabase/supabase-js": "^2.31.0", 18 | "classnames": "^2.3.2", 19 | "eslint-plugin-immer": "^0.0.1", 20 | "nanoid": "^4.0.2", 21 | "react": "^18.2.0", 22 | "react-dom": "^18.2.0", 23 | "react-router-dom": "^6.14.2", 24 | "use-immer": "^0.9.0" 25 | }, 26 | "devDependencies": { 27 | "@types/react": "^18.2.15", 28 | "@types/react-dom": "^18.2.7", 29 | "@typescript-eslint/eslint-plugin": "^6.0.0", 30 | "@typescript-eslint/parser": "^6.0.0", 31 | "@vitejs/plugin-react-swc": "^3.3.2", 32 | "eslint": "^8.45.0", 33 | "eslint-plugin-react-hooks": "^4.6.0", 34 | "eslint-plugin-react-refresh": "^0.4.3", 35 | "supabase": "^1.82.5", 36 | "typescript": "^5.0.2", 37 | "vite": "^4.4.5" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /public/ztm-notes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satansdeer/ztm-notion-clone/83f407169bf413804cd2f0af07278d500e85120f/public/ztm-notes.png -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Page } from "./Page/Page"; 2 | import { AppStateProvider } from "./state/AppStateContext"; 3 | import { Route, Routes } from "react-router-dom"; 4 | import { Auth } from "./auth/Auth"; 5 | import { Private } from "./auth/Private"; 6 | 7 | function App() { 8 | return ( 9 | 10 | } /> 11 | 17 | 18 | 19 | } 20 | /> 21 | } 22 | /> 23 | 29 | 30 | 31 | } 32 | /> 33 | } 34 | /> 35 | 36 | ); 37 | } 38 | 39 | export default App; 40 | -------------------------------------------------------------------------------- /src/Node/BasicNode.tsx: -------------------------------------------------------------------------------- 1 | import { NodeData, NodeType } from "../utils/types"; 2 | import styles from "./Node.module.css"; 3 | import { 4 | useRef, 5 | useEffect, 6 | FormEventHandler, 7 | KeyboardEventHandler, 8 | } from "react"; 9 | import { nanoid } from "nanoid"; 10 | import { useAppState } from "../state/AppStateContext"; 11 | import { CommandPanel } from "./CommandPanel"; 12 | import cx from "classnames" 13 | 14 | type BasicNodeProps = { 15 | node: NodeData; 16 | updateFocusedIndex(index: number): void; 17 | isFocused: boolean; 18 | index: number; 19 | }; 20 | 21 | export const BasicNode = ({ 22 | node, 23 | updateFocusedIndex, 24 | isFocused, 25 | index, 26 | }: BasicNodeProps) => { 27 | const nodeRef = useRef(null); 28 | const showCommandPanel = isFocused && node?.value?.match(/^\//); 29 | 30 | const { changeNodeValue, changeNodeType, removeNodeByIndex, addNode } = 31 | useAppState(); 32 | 33 | useEffect(() => { 34 | if (nodeRef.current && document.activeElement !== nodeRef.current) { 35 | nodeRef.current.textContent = node.value; 36 | } 37 | if (isFocused) { 38 | nodeRef.current?.focus(); 39 | } else { 40 | nodeRef.current?.blur(); 41 | } 42 | }, [node, isFocused]); 43 | 44 | const parseCommand = (nodeType: NodeType) => { 45 | if (nodeRef.current) { 46 | changeNodeType(index, nodeType); 47 | nodeRef.current.textContent = ""; 48 | } 49 | }; 50 | 51 | const handleInput: FormEventHandler = ({ currentTarget }) => { 52 | const { textContent } = currentTarget; 53 | changeNodeValue(index, textContent || ""); 54 | }; 55 | 56 | const handleClick = () => { 57 | updateFocusedIndex(index); 58 | }; 59 | 60 | const onKeyDown: KeyboardEventHandler = (event) => { 61 | const target = event.target as HTMLDivElement; 62 | if (event.key === "Enter") { 63 | event.preventDefault(); 64 | if (target.textContent?.[0] === "/") { 65 | return; 66 | } 67 | addNode({ type: node.type, value: "", id: nanoid() }, index + 1); 68 | updateFocusedIndex(index + 1); 69 | } 70 | if (event.key === "Backspace") { 71 | if (target.textContent?.length === 0) { 72 | event.preventDefault(); 73 | removeNodeByIndex(index); 74 | updateFocusedIndex(index - 1); 75 | } else if (window?.getSelection()?.anchorOffset === 0) { 76 | event.preventDefault(); 77 | removeNodeByIndex(index - 1); 78 | updateFocusedIndex(index - 1); 79 | } 80 | } 81 | }; 82 | 83 | return ( 84 | <> 85 | {showCommandPanel && ( 86 | 87 | )} 88 |
97 | 98 | ); 99 | }; 100 | -------------------------------------------------------------------------------- /src/Node/CommandPanel.module.css: -------------------------------------------------------------------------------- 1 | .panel { 2 | z-index: 10; 3 | position: absolute; 4 | bottom: -10px; 5 | left: 60px; 6 | background: white; 7 | width: 200px; 8 | padding: 6px; 9 | transform: translateY(100%); 10 | border-radius: 4px; 11 | box-shadow: rgb(15 15 15 / 10%) 0px 0px 0px 1px, 12 | rgb(15 15 15 / 20%) 0px 3px 6px, rgb(15 15 15 / 40%) 0px 9px 24px; 13 | } 14 | 15 | .panel.reverse { 16 | transform: translateY(-50px); 17 | } 18 | 19 | .panel ul { 20 | list-style: none; 21 | padding: 0; 22 | margin: 0; 23 | width: 100%; 24 | } 25 | 26 | .panel ul li { 27 | padding: 12px; 28 | cursor: pointer; 29 | border-radius: 4px; 30 | } 31 | 32 | .panel ul li:hover { 33 | background-color: #d0d0d0; 34 | } 35 | 36 | .panel ul li.selected { 37 | background-color: #d0d0d0; 38 | } 39 | 40 | .title { 41 | font-weight: bold; 42 | padding: 12px; 43 | } 44 | -------------------------------------------------------------------------------- /src/Node/CommandPanel.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { NodeType } from "../utils/types"; 3 | import { useOverflowsScreenBottom } from "./useOverflowsScreenBottom"; 4 | import styles from "./CommandPanel.module.css"; 5 | import cx from "classnames"; 6 | 7 | type CommandPanelProps = { 8 | nodeText: string; 9 | selectItem: (nodeType: NodeType) => void; 10 | }; 11 | 12 | type SupportedNodeType = { 13 | value: NodeType; 14 | name: string; 15 | }; 16 | 17 | const supportedNodeTypes: SupportedNodeType[] = [ 18 | { value: "text", name: "Text" }, 19 | { value: "list", name: "List" }, 20 | { value: "page", name: "Page" }, 21 | { value: "image", name: "Image" }, 22 | { value: "heading1", name: "Heading 1" }, 23 | { value: "heading2", name: "Heading 2" }, 24 | { value: "heading3", name: "Heading 3" }, 25 | ]; 26 | 27 | export const CommandPanel = ({ selectItem, nodeText }: CommandPanelProps) => { 28 | const [selectedItemIndex, setSelectedItemIndex] = useState(0); 29 | const { overflows, ref } = useOverflowsScreenBottom(); 30 | 31 | useEffect(() => { 32 | const handleKeyDown = (event: KeyboardEvent) => { 33 | if (event.key === "Enter") { 34 | selectItem(supportedNodeTypes[selectedItemIndex].value); 35 | } 36 | }; 37 | 38 | window.addEventListener("keydown", handleKeyDown); 39 | 40 | return () => { 41 | window.removeEventListener("keydown", handleKeyDown); 42 | }; 43 | }, [selectedItemIndex, selectItem]); 44 | 45 | useEffect(() => { 46 | const normalizedValue = nodeText.toLowerCase().replace(/\//, ""); 47 | setSelectedItemIndex( 48 | supportedNodeTypes.findIndex((item) => item.value.match(normalizedValue)) 49 | ); 50 | }, [nodeText]); 51 | 52 | return ( 53 |
59 |
Blocks
60 |
    61 | {supportedNodeTypes.map((type, index) => { 62 | const selected = selectedItemIndex === index; 63 | 64 | return ( 65 |
  • selectItem(type.value)} 71 | > 72 | {type.name} 73 |
  • 74 | ); 75 | })} 76 |
77 |
78 | ); 79 | }; 80 | -------------------------------------------------------------------------------- /src/Node/ImageNode.tsx: -------------------------------------------------------------------------------- 1 | import { NodeData } from "../utils/types"; 2 | import { ChangeEvent, useEffect, useRef } from "react"; 3 | import { useAppState } from "../state/AppStateContext"; 4 | import cx from "classnames"; 5 | import styles from "./Node.module.css"; 6 | import { FileImage } from "../components/FileImage"; 7 | import { uploadImage } from "../utils/uploadImage"; 8 | 9 | type ImageNodeProps = { 10 | node: NodeData; 11 | isFocused: boolean; 12 | index: number; 13 | }; 14 | 15 | export const ImageNode = ({ node, isFocused, index }: ImageNodeProps) => { 16 | const { removeNodeByIndex, changeNodeValue, changeNodeType } = useAppState(); 17 | const fileInputRef = useRef(null); 18 | 19 | useEffect(() => { 20 | if (!node.value || node.value.length === 0) { 21 | fileInputRef.current?.click(); 22 | } 23 | }, [node.value]); 24 | 25 | useEffect(() => { 26 | const handleKeyDown = (event: KeyboardEvent) => { 27 | event.preventDefault(); 28 | if (event.key === "Backspace") { 29 | removeNodeByIndex(index); 30 | } 31 | if (event.key === "Enter") { 32 | fileInputRef.current?.click(); 33 | } 34 | }; 35 | if (isFocused) { 36 | window.addEventListener("keydown", handleKeyDown); 37 | } else { 38 | window.removeEventListener("keydown", handleKeyDown); 39 | } 40 | 41 | return () => { 42 | window.removeEventListener("keydown", handleKeyDown); 43 | }; 44 | }, [isFocused, removeNodeByIndex, index, node]); 45 | 46 | const onImageUpload = async (event: ChangeEvent) => { 47 | const target = event.target; 48 | if (!target.files) { 49 | changeNodeType(index, "text"); 50 | } 51 | try { 52 | const result = await uploadImage(target.files?.[0]); 53 | if (result?.filePath) { 54 | changeNodeValue(index, result?.filePath); 55 | } 56 | } catch (error) { 57 | changeNodeType(index, "text"); 58 | } 59 | }; 60 | 61 | return ( 62 |
67 | 68 | 74 |
75 | ); 76 | }; 77 | -------------------------------------------------------------------------------- /src/Node/Node.module.css: -------------------------------------------------------------------------------- 1 | .node { 2 | border-radius: 4px; 3 | padding: 6px 6px 6px 46px; 4 | cursor: text; 5 | width: 100%; 6 | } 7 | 8 | .page { 9 | cursor: pointer; 10 | font-weight: bold; 11 | } 12 | 13 | .page:hover { 14 | background-color: #f0f0f0; 15 | } 16 | 17 | .list { 18 | position: relative; 19 | padding-left: 20px; 20 | } 21 | 22 | .list::after { 23 | content: ""; 24 | position: absolute; 25 | bottom: 50%; 26 | left: 6px; 27 | width: 6px; 28 | height: 6px; 29 | background-color: #222; 30 | border-radius: 50%; 31 | transform: translateY(50%); 32 | } 33 | 34 | .heading1 { 35 | font-size: 40px; 36 | font-weight: bold; 37 | } 38 | 39 | .heading2 { 40 | font-size: 30px; 41 | font-weight: bold; 42 | } 43 | 44 | .heading3 { 45 | font-size: 20px; 46 | font-weight: bold; 47 | } 48 | 49 | .focused { 50 | background-color: #00bcd4; 51 | } 52 | -------------------------------------------------------------------------------- /src/Node/NodeContainer.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: row; 4 | position: relative; 5 | padding-left: 18px; 6 | } 7 | 8 | .container img { 9 | width: 100%; 10 | } 11 | 12 | .dragHandle { 13 | padding: 6px; 14 | cursor: grab; 15 | font-weight: bold; 16 | opacity: 0; 17 | transition: opacity 0.2s ease-in-out; 18 | } 19 | 20 | .dragHandle:hover { 21 | opacity: 1; 22 | } 23 | -------------------------------------------------------------------------------- /src/Node/NodeContainer.tsx: -------------------------------------------------------------------------------- 1 | import { NodeData } from "../utils/types"; 2 | import { CSS } from "@dnd-kit/utilities"; 3 | import { useSortable } from "@dnd-kit/sortable"; 4 | import { NodeTypeSwitcher } from "./NodeTypeSwitcher"; 5 | import styles from "./NodeContainer.module.css"; 6 | 7 | type NodeContainerProps = { 8 | node: NodeData; 9 | updateFocusedIndex(index: number): void; 10 | isFocused: boolean; 11 | index: number; 12 | }; 13 | 14 | export const NodeContainer = ({ 15 | node, 16 | index, 17 | isFocused, 18 | updateFocusedIndex, 19 | }: NodeContainerProps) => { 20 | const { attributes, listeners, setNodeRef, transform, transition } = 21 | useSortable({ 22 | id: node.id, 23 | }); 24 | 25 | const style = { 26 | transform: CSS.Transform.toString(transform), 27 | transition, 28 | }; 29 | 30 | return ( 31 |
37 |
38 | ⠿ 39 |
40 | 46 |
47 | ); 48 | }; 49 | -------------------------------------------------------------------------------- /src/Node/NodeTypeSwitcher.tsx: -------------------------------------------------------------------------------- 1 | import { NodeType, NodeData } from "../utils/types" 2 | import { BasicNode } from "./BasicNode" 3 | import { ImageNode } from "./ImageNode"; 4 | import { PageNode } from "./PageNode" 5 | 6 | type NodeTypeSwitcherProps = { 7 | node: NodeData; 8 | updateFocusedIndex(index: number): void; 9 | isFocused: boolean; 10 | index: number; 11 | }; 12 | 13 | const TEXT_NODE_TYPES: NodeType[] = [ 14 | "text", "list", "heading1", "heading2", "heading3" 15 | ] 16 | 17 | export const NodeTypeSwitcher = ({ 18 | node, 19 | isFocused, 20 | index, 21 | updateFocusedIndex 22 | }: NodeTypeSwitcherProps) => { 23 | if(TEXT_NODE_TYPES.includes(node.type)) { 24 | return 30 | } 31 | 32 | if(node.type == "page"){ 33 | return 34 | } 35 | 36 | if(node.type === "image") { 37 | return 38 | } 39 | 40 | return null 41 | } 42 | -------------------------------------------------------------------------------- /src/Node/PageNode.tsx: -------------------------------------------------------------------------------- 1 | import { NodeData } from "../utils/types"; 2 | import { useEffect, useState } from "react"; 3 | import { useNavigate } from "react-router-dom"; 4 | import { useAppState } from "../state/AppStateContext"; 5 | import { supabase } from "../supabaseClient"; 6 | import cx from "classnames"; 7 | import styles from "./Node.module.css" 8 | 9 | type PageNodeProps = { 10 | node: NodeData; 11 | isFocused: boolean; 12 | index: number; 13 | }; 14 | 15 | export const PageNode = ({ node, isFocused, index }: PageNodeProps) => { 16 | const navigate = useNavigate(); 17 | const [pageTitle, setPageTitle] = useState(""); 18 | const { removeNodeByIndex } = useAppState(); 19 | 20 | useEffect(() => { 21 | const handleKeyDown = (event: KeyboardEvent) => { 22 | event.preventDefault(); 23 | if (event.key === "Backspace") { 24 | removeNodeByIndex(index); 25 | } 26 | if (event.key === "Enter") { 27 | navigate(`/${node.value}`); 28 | } 29 | }; 30 | if (isFocused) { 31 | window.addEventListener("keydown", handleKeyDown); 32 | } else { 33 | window.removeEventListener("keydown", handleKeyDown); 34 | } 35 | 36 | return () => { 37 | window.removeEventListener("keydown", handleKeyDown); 38 | }; 39 | }, [isFocused, removeNodeByIndex, index, navigate, node]); 40 | 41 | useEffect(() => { 42 | const fetchPageTitle = async () => { 43 | const { data } = await supabase 44 | .from("pages") 45 | .select("title") 46 | .eq("slug", node.value) 47 | .single(); 48 | setPageTitle(data?.title); 49 | }; 50 | if (node.type === "page" && node.value) { 51 | fetchPageTitle(); 52 | } 53 | }, [node.type, node.value]); 54 | 55 | const navigateToPage = () => { 56 | navigate(`/${node.value}`); 57 | }; 58 | 59 | return ( 60 |
66 | 📄 {pageTitle} 67 |
68 | ); 69 | }; 70 | -------------------------------------------------------------------------------- /src/Node/useOverflowsScreenBottom.ts: -------------------------------------------------------------------------------- 1 | import { useRef, useState, useEffect } from "react"; 2 | 3 | export const useOverflowsScreenBottom = () => { 4 | const ref = useRef(null); 5 | const [overflows, setOverflows] = useState(false); 6 | 7 | useEffect(() => { 8 | if (ref.current) { 9 | const { bottom } = ref.current.getBoundingClientRect(); 10 | const { innerHeight } = window; 11 | setOverflows(bottom > innerHeight); 12 | } 13 | }, []); 14 | 15 | return { overflows, ref }; 16 | }; 17 | -------------------------------------------------------------------------------- /src/Page/Cover.module.css: -------------------------------------------------------------------------------- 1 | .cover { 2 | position: relative; 3 | height: 295px; 4 | border-bottom: 2px solid #eaeaea; 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | } 9 | 10 | .button { 11 | position: absolute; 12 | bottom: 20px; 13 | right: 90px; 14 | padding: 6px; 15 | opacity: 0; 16 | transition: opacity 0.2s ease-in-out; 17 | background: white; 18 | border: 2px solid #888; 19 | border-radius: 4px; 20 | color: #6f6f6f; 21 | font-weight: bold; 22 | cursor: pointer; 23 | } 24 | 25 | .cover:hover .button { 26 | opacity: 1; 27 | } 28 | 29 | .image { 30 | width: 100%; 31 | max-height: 295px; 32 | object-fit: cover; 33 | } 34 | -------------------------------------------------------------------------------- /src/Page/Cover.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, ChangeEventHandler } from "react"; 2 | import styles from "./Cover.module.css"; 3 | import { FileImage } from "../components/FileImage"; 4 | import { uploadImage } from "../utils/uploadImage" 5 | 6 | type CoverProps = { 7 | filePath?: string; 8 | changePageCover: (filePath: string) => void; 9 | }; 10 | 11 | export const Cover = ({ filePath, changePageCover }: CoverProps) => { 12 | const fileInputRef = useRef(null); 13 | 14 | const onChangeCoverImage = () => { 15 | fileInputRef.current?.click(); 16 | }; 17 | 18 | const onCoverImageUpload: ChangeEventHandler = async (event) => { 19 | const target = event.target; 20 | const result = await uploadImage(target?.files?.[0]) 21 | 22 | if(result?.filePath){ 23 | changePageCover(result.filePath) 24 | } 25 | }; 26 | 27 | return ( 28 |
29 | {filePath ? ( 30 | 31 | ) : ( 32 | Cover 33 | )} 34 | 37 | 43 |
44 | ); 45 | }; 46 | -------------------------------------------------------------------------------- /src/Page/Page.module.css: -------------------------------------------------------------------------------- 1 | .body { 2 | padding-left: 50px; 3 | padding-right: 90px; 4 | max-width: 900px; 5 | } 6 | 7 | .backLink { 8 | padding-left: 46px; 9 | padding-top: 10px; 10 | } 11 | -------------------------------------------------------------------------------- /src/Page/Page.tsx: -------------------------------------------------------------------------------- 1 | import { useFocusedNodeIndex } from "./useFocusedNodeIndex"; 2 | import { Cover } from "./Cover"; 3 | import { Spacer } from "./Spacer"; 4 | import { NodeContainer } from "../Node/NodeContainer"; 5 | import { Title } from "./Title"; 6 | import { nanoid } from "nanoid"; 7 | import { useAppState } from "../state/AppStateContext"; 8 | import { DndContext, DragOverlay, DragEndEvent } from "@dnd-kit/core"; 9 | import { 10 | SortableContext, 11 | verticalListSortingStrategy, 12 | } from "@dnd-kit/sortable"; 13 | 14 | export const Page = () => { 15 | const { title, nodes, addNode, cover, setCoverImage, reorderNodes, setTitle } = useAppState(); 16 | 17 | const [focusedNodeIndex, setFocusedNodeIndex] = useFocusedNodeIndex({ 18 | nodes, 19 | }); 20 | 21 | const handleDragEvent = (event: DragEndEvent) => { 22 | const { active, over } = event; 23 | if (over?.id && active.id !== over?.id) { 24 | reorderNodes(active.id as string, over.id as string); 25 | } 26 | }; 27 | 28 | return ( 29 | <> 30 | 31 |
32 | 33 | <DndContext onDragEnd={handleDragEvent}> 34 | <SortableContext items={nodes} strategy={verticalListSortingStrategy}> 35 | {nodes.map((node, index) => ( 36 | <NodeContainer 37 | key={node.id} 38 | node={node} 39 | isFocused={focusedNodeIndex === index} 40 | updateFocusedIndex={setFocusedNodeIndex} 41 | index={index} 42 | /> 43 | ))} 44 | </SortableContext> 45 | <DragOverlay /> 46 | </DndContext> 47 | <Spacer 48 | handleClick={() => { 49 | addNode({ type: "text", value: "", id: nanoid() }, nodes.length); 50 | }} 51 | showHint={!nodes.length} 52 | /> 53 | </div> 54 | </> 55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /src/Page/Spacer.module.css: -------------------------------------------------------------------------------- 1 | .spacer { 2 | height: 200px; 3 | width: 100%; 4 | padding: 0 46px; 5 | color: grey; 6 | } 7 | -------------------------------------------------------------------------------- /src/Page/Spacer.tsx: -------------------------------------------------------------------------------- 1 | import styles from "./Spacer.module.css"; 2 | 3 | type SpacerProps = { 4 | handleClick(): void; 5 | showHint: boolean; 6 | }; 7 | 8 | export const Spacer = ({ handleClick, showHint }: SpacerProps) => { 9 | return ( 10 | <div className={styles.spacer} onClick={handleClick}> 11 | {showHint && "Click to create the first paragraph."} 12 | </div> 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /src/Page/Title.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding-left: 40px; 3 | padding-right: 40px; 4 | max-width: 900px; 5 | } 6 | 7 | .title { 8 | padding: 6px; 9 | } 10 | -------------------------------------------------------------------------------- /src/Page/Title.tsx: -------------------------------------------------------------------------------- 1 | import { NodeData } from "../utils/types"; 2 | import { useRef, useEffect } from "react"; 3 | import styles from "./Title.module.css"; 4 | import { nanoid } from "nanoid"; 5 | 6 | type TitleProps = { 7 | title: string; 8 | changePageTitle(title: string): void; 9 | addNode(node: NodeData, index: number): void; 10 | }; 11 | 12 | export const Title = ({ title, changePageTitle, addNode }: TitleProps) => { 13 | const headerRef = useRef<HTMLHeadingElement>(null); 14 | 15 | useEffect(() => { 16 | const isFocused = document.activeElement == headerRef.current; 17 | if (!isFocused && headerRef.current) { 18 | headerRef.current.textContent = title; 19 | } 20 | }, [title]); 21 | 22 | return ( 23 | <div className={styles.container}> 24 | <h1 25 | className={styles.title} 26 | contentEditable 27 | ref={headerRef} 28 | suppressContentEditableWarning 29 | onInput={(e) => changePageTitle(e.currentTarget.textContent || "")} 30 | onKeyDown={(event) => { 31 | if (event.key === "Enter") { 32 | event.preventDefault(); 33 | addNode({ type: "text", id: nanoid(), value: "" }, 0); 34 | } 35 | }} 36 | /> 37 | </div> 38 | ); 39 | }; 40 | -------------------------------------------------------------------------------- /src/Page/useFocusedNodeIndex.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState, Dispatch, SetStateAction } from "react"; 2 | import { NodeData } from "../utils/types"; 3 | 4 | type UseFocusedNodeIndexProps = { 5 | nodes: NodeData[]; 6 | }; 7 | 8 | export const useFocusedNodeIndex = ({ 9 | nodes, 10 | }: UseFocusedNodeIndexProps): [number, Dispatch<SetStateAction<number>>] => { 11 | const [focusedNodeIndex, setFocusedNodeIndex] = useState(0); 12 | 13 | useEffect(() => { 14 | const onKeyDown = (event: KeyboardEvent) => { 15 | if (event.key === "ArrowUp") { 16 | setFocusedNodeIndex((index) => Math.max(index - 1, 0)); 17 | } 18 | if (event.key === "ArrowDown") { 19 | setFocusedNodeIndex((index) => Math.min(index + 1, nodes.length - 1)); 20 | } 21 | }; 22 | document.addEventListener("keydown", onKeyDown); 23 | 24 | return () => document.removeEventListener("keydown", onKeyDown); 25 | }, [nodes]); 26 | 27 | return [focusedNodeIndex, setFocusedNodeIndex]; 28 | }; 29 | -------------------------------------------------------------------------------- /src/auth/Auth.tsx: -------------------------------------------------------------------------------- 1 | import { useState, FormEvent} from "react" 2 | import { useAuthSession } from "./AuthSessionContext" 3 | import { Navigate } from "react-router-dom" 4 | import styles from "../utils.module.css" 5 | import { supabase } from "../supabaseClient" 6 | 7 | export const Auth = () => { 8 | const [loading, setLoading] = useState(false) 9 | const [email, setEmail] = useState("") 10 | const { session } = useAuthSession() 11 | 12 | const handleLogin = async (e: FormEvent<HTMLFormElement>) => { 13 | e.preventDefault() 14 | 15 | try { 16 | setLoading(true) 17 | const { error } = await supabase.auth.signInWithOtp({ email }) 18 | if(error) throw error 19 | alert("CHeck your email for the login link!") 20 | } catch (error){ 21 | alert(error) 22 | } finally { 23 | setLoading(false) 24 | } 25 | } 26 | 27 | if(session){ 28 | return <Navigate to="/" /> 29 | } 30 | 31 | return ( 32 | <div className={styles.centeredFlex}> 33 | <div> 34 | <h1>ZTM Notes App</h1> 35 | <p>Sign in via magic link with your email below</p> 36 | {loading ? ("Sending magic link...") : ( 37 | <form onSubmit={handleLogin}> 38 | <label htmlFor="email">Email: </label> 39 | <input 40 | type="email" 41 | id="email" 42 | value={email} 43 | onChange={e => setEmail(e.target.value)} 44 | placeholder="Your email" 45 | /> 46 | <button> 47 | Send magic link 48 | </button> 49 | </form> 50 | )} 51 | </div> 52 | </div> 53 | ) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/auth/AuthSessionContext.tsx: -------------------------------------------------------------------------------- 1 | import { supabase } from "../supabaseClient" 2 | import { Session } from "@supabase/supabase-js" 3 | import { createContext, ReactNode, useState, useEffect, useContext } from "react" 4 | 5 | type AuthSessionContextValue = { 6 | session: Session | null; 7 | loading: boolean; 8 | } 9 | 10 | const AuthSessionContext = createContext<AuthSessionContextValue>({} as AuthSessionContextValue) 11 | 12 | 13 | type AuthSessionProviderProps = { 14 | children: ReactNode 15 | } 16 | 17 | export const AuthSessionProvider = ({children}: AuthSessionProviderProps) => { 18 | const [ session, setSession ] = useState<Session | null>(null) 19 | const [ loading, setLoading ] = useState(true); 20 | 21 | useEffect(() => { 22 | const auth = async () => { 23 | const {data, error } = await supabase.auth.getSession() 24 | if(data.session){ 25 | setSession(data.session) 26 | setLoading(false) 27 | } else { 28 | console.log(error) 29 | } 30 | } 31 | auth() 32 | supabase.auth.onAuthStateChange((_event, session) => { 33 | setSession(session) 34 | setLoading(false) 35 | }) 36 | }, []) 37 | 38 | return ( 39 | <AuthSessionContext.Provider value={{ session, loading }}> 40 | {children} 41 | </AuthSessionContext.Provider> 42 | ) 43 | } 44 | 45 | export const useAuthSession = () => useContext(AuthSessionContext) 46 | -------------------------------------------------------------------------------- /src/auth/Private.tsx: -------------------------------------------------------------------------------- 1 | import { ReactElement } from "react" 2 | import { useAuthSession } from "./AuthSessionContext" 3 | import { Navigate } from "react-router-dom" 4 | 5 | type PrivateProps = { 6 | component: ReactElement; 7 | } 8 | 9 | export const Private = ({ component }: PrivateProps) => { 10 | const { session, loading } = useAuthSession() 11 | 12 | if (loading) { 13 | return <> Authenticating...</> 14 | } 15 | 16 | return session ? component : <Navigate to="/auth" /> 17 | } 18 | -------------------------------------------------------------------------------- /src/components/FileImage.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react" 2 | import { supabase } from "../supabaseClient" 3 | import { Loader } from "./Loader" 4 | import styles from "../utils.module.css" 5 | 6 | type FileImageProps = { 7 | filePath: string 8 | } & React.ImgHTMLAttributes<HTMLImageElement> 9 | 10 | export const FileImage = ({filePath, ...props}: FileImageProps) => { 11 | const [image, setImage] = useState("") 12 | const [ loading, setLoading ] = useState(true) 13 | 14 | useEffect(() => { 15 | const downloadImage = async (filePath: string) => { 16 | setLoading(true); 17 | const {data} = await supabase.storage.from("images").download(filePath) 18 | if(data){ 19 | const url = URL.createObjectURL(data) 20 | setImage(url) 21 | setLoading(false) 22 | } 23 | } 24 | if(filePath && filePath.length > 0){ 25 | downloadImage(filePath) 26 | } 27 | }, [filePath]) 28 | 29 | if(loading){ 30 | return <div className={styles.centeredFlex}> 31 | <Loader/> 32 | </div> 33 | } 34 | 35 | return <img src={image} alt={filePath} {...props} /> 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/components/Loader.module.css: -------------------------------------------------------------------------------- 1 | .loader { 2 | display: inline-block; 3 | position: relative; 4 | width: 80px; 5 | height: 80px; 6 | } 7 | .loader div { 8 | position: absolute; 9 | top: 33px; 10 | width: 13px; 11 | height: 13px; 12 | border-radius: 50%; 13 | background: #ccc; 14 | animation-timing-function: cubic-bezier(0, 1, 1, 0); 15 | } 16 | .loader div:nth-child(1) { 17 | left: 8px; 18 | animation: loader1 0.6s infinite; 19 | } 20 | .loader div:nth-child(2) { 21 | left: 8px; 22 | animation: loader2 0.6s infinite; 23 | } 24 | .loader div:nth-child(3) { 25 | left: 32px; 26 | animation: loader2 0.6s infinite; 27 | } 28 | .loader div:nth-child(4) { 29 | left: 56px; 30 | animation: loader3 0.6s infinite; 31 | } 32 | @keyframes loader1 { 33 | 0% { 34 | transform: scale(0); 35 | } 36 | 100% { 37 | transform: scale(1); 38 | } 39 | } 40 | @keyframes loader3 { 41 | 0% { 42 | transform: scale(1); 43 | } 44 | 100% { 45 | transform: scale(0); 46 | } 47 | } 48 | @keyframes loader2 { 49 | 0% { 50 | transform: translate(0, 0); 51 | } 52 | 100% { 53 | transform: translate(24px, 0); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/components/Loader.tsx: -------------------------------------------------------------------------------- 1 | import styles from "./Loader.module.css"; 2 | 3 | // https://loading.io/css/ 4 | 5 | export const Loader = () => { 6 | return ( 7 | <div className={styles.loader}> 8 | <div /> 9 | <div /> 10 | <div /> 11 | <div /> 12 | </div> 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | 15 | html, 16 | body, 17 | #root { 18 | height: 100%; 19 | position: relative; 20 | } 21 | 22 | [contenteditable="true"]:focus { 23 | outline: none; 24 | } 25 | 26 | [contenteditable="true"]:empty:focus:before { 27 | content: attr(data-placeholder); 28 | color: grey; 29 | } 30 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | import "./index.css"; 5 | import { BrowserRouter } from "react-router-dom"; 6 | import { AuthSessionProvider } from "./auth/AuthSessionContext" 7 | 8 | ReactDOM.createRoot(document.getElementById("root")!).render( 9 | <React.StrictMode> 10 | <BrowserRouter> 11 | <AuthSessionProvider> 12 | <App /> 13 | </AuthSessionProvider> 14 | </BrowserRouter> 15 | </React.StrictMode> 16 | ); 17 | -------------------------------------------------------------------------------- /src/state/AppStateContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | import { usePageState } from "./usePageState"; 3 | import { Page } from "../utils/types"; 4 | import { withInitialState } from "./withInitialState" 5 | 6 | type AppStateContextType = ReturnType<typeof usePageState>; 7 | 8 | const AppStateContext = createContext<AppStateContextType>( 9 | {} as AppStateContextType 10 | ); 11 | 12 | type AppStateProviderProps = { 13 | children: React.ReactNode; 14 | initialState: Page; 15 | }; 16 | 17 | export const AppStateProvider = withInitialState<AppStateProviderProps>(({ 18 | children, 19 | initialState, 20 | }: AppStateProviderProps) => { 21 | const pageStateHandlers = usePageState(initialState); 22 | 23 | return ( 24 | <AppStateContext.Provider value={pageStateHandlers}> 25 | {children} 26 | </AppStateContext.Provider> 27 | ); 28 | }); 29 | 30 | export const useAppState = () => useContext(AppStateContext); 31 | -------------------------------------------------------------------------------- /src/state/startPageScaffold.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Welcome to ZTM Notes", 3 | "nodes": [ 4 | { 5 | "type": "text", 6 | "value": "This app is written in React + TypeScript and works similarly to Notion. For example, try entering the text below this paragraph 👇", 7 | "id": "dgkm6uWT58KKIvBuo4KCE" 8 | }, 9 | { "type": "text", "value": "", "id": "cZjPbQHUQmv5h-v1rpDoD" }, 10 | { 11 | "type": "text", 12 | "value": "You can also add lists, to do this bring up the command palette by starting a new line with `/`", 13 | "id": "eK__MFBh2DieZzKQDf5rl" 14 | }, 15 | { "type": "text", "value": "", "id": "IYd7XsCkoiqysGrOLvM0B" }, 16 | { 17 | "type": "text", 18 | "value": "Here are a few list items just to show how it looks like:", 19 | "id": "tGEVZQlUB_zGi66GU2TIz" 20 | }, 21 | { "type": "list", "value": "First item", "id": "zJ42BYE7QCx_1XSsZETuc" }, 22 | { "type": "list", "value": "Second item", "id": "ia_pE2qrqR8un_BYqqM9_" }, 23 | { "type": "list", "value": "Third item", "id": "gD6IRCl09HQGpaDorOiF6" }, 24 | { "type": "text", "value": "", "id": "pH0TGrzTJ09_8w8XXfKO8" }, 25 | { 26 | "type": "heading2", 27 | "value": "You can add headings as well", 28 | "id": "qbsmQ_NkTC7jRO4csWL8h" 29 | }, 30 | { 31 | "type": "text", 32 | "value": "If you tried adding list items, you've noticed that there are also other types of blocks.", 33 | "id": "e1pnucOk3k_G3_Gjw7SrB" 34 | }, 35 | { "type": "text", "value": "", "id": "Zctuc8G9XyWEPhUGIYBVW" }, 36 | { 37 | "type": "text", 38 | "value": "Currently the app supports:", 39 | "id": "v3s7NU1a-X_uWSAELT2nK" 40 | }, 41 | { "type": "list", "value": "regular text", "id": "ADtjGSZ4p53f9VpQK72f1" }, 42 | { 43 | "type": "list", 44 | "value": "unordered lists", 45 | "id": "Zrwh60KFLzqeBmmhAAKDN" 46 | }, 47 | { 48 | "type": "list", 49 | "value": "heading levels 1-3", 50 | "id": "SLNB1qZ3TuGiNerxfAL7N" 51 | }, 52 | { "type": "list", "value": "images", "id": "rT-xkKSS3l23Olui4XUF8" }, 53 | { 54 | "type": "list", 55 | "value": "links to other pages", 56 | "id": "oHdB3ghNMer9DTlCp0dhA" 57 | }, 58 | { "type": "text", "value": "", "id": "qD6vnHeExO5gTg5ZmPUt3" }, 59 | { 60 | "type": "text", 61 | "value": "Try adding a new page.", 62 | "id": "765A3xPw56d8j7NcYpi3D" 63 | } 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /src/state/usePageState.ts: -------------------------------------------------------------------------------- 1 | import { Page, NodeData, NodeType } from "../utils/types"; 2 | import { arrayMove } from "@dnd-kit/sortable" 3 | import { useSyncedState } from "./useSyncedState" 4 | import { updatePage } from "../utils/updatePage" 5 | import { createPage } from "../utils/createPage" 6 | 7 | export const usePageState = (initialState: Page) => { 8 | const [page, setPage] = useSyncedState(initialState, updatePage); 9 | 10 | const addNode = (node: NodeData, index: number) => { 11 | setPage((draft) => { 12 | draft.nodes.splice(index, 0, node); 13 | }); 14 | }; 15 | 16 | const removeNodeByIndex = (nodeIndex: number) => { 17 | setPage((draft) => { 18 | draft.nodes.splice(nodeIndex, 1); 19 | }); 20 | }; 21 | 22 | const changeNodeValue = (nodeIndex: number, value: string) => { 23 | setPage((draft) => { 24 | draft.nodes[nodeIndex].value = value; 25 | }); 26 | }; 27 | 28 | const changeNodeType = async (nodeIndex: number, type: NodeType) => { 29 | if (type === "page") { 30 | const newPage = await createPage(); 31 | if (newPage) { 32 | setPage((draft) => { 33 | draft.nodes[nodeIndex].type = type; 34 | draft.nodes[nodeIndex].value = newPage.slug; 35 | }); 36 | } 37 | } else { 38 | setPage((draft) => { 39 | draft.nodes[nodeIndex].type = type; 40 | draft.nodes[nodeIndex].value = ""; 41 | }); 42 | } 43 | }; 44 | 45 | const setNodes = (nodes: NodeData[]) => { 46 | setPage((draft) => { 47 | draft.nodes = nodes; 48 | }); 49 | }; 50 | 51 | const setTitle = (title: string) => { 52 | setPage((draft) => { 53 | draft.title = title; 54 | }); 55 | }; 56 | 57 | const setCoverImage = (coverImage: string) => { 58 | setPage((draft) => { 59 | draft.cover = coverImage; 60 | }); 61 | }; 62 | 63 | const reorderNodes = (id1: string, id2: string) => { 64 | setPage((draft) => { 65 | const index1 = draft.nodes.findIndex(node => node.id === id1) 66 | const index2 = draft.nodes.findIndex(node => node.id === id2) 67 | draft.nodes = arrayMove(draft.nodes, index1, index2) 68 | }) 69 | } 70 | 71 | return { 72 | nodes: page.nodes, 73 | title: page.title, 74 | cover: page.cover, 75 | changeNodeType, 76 | changeNodeValue, 77 | addNode, 78 | removeNodeByIndex, 79 | setTitle, 80 | setCoverImage, 81 | setNodes, 82 | reorderNodes 83 | }; 84 | }; 85 | -------------------------------------------------------------------------------- /src/state/useSyncedState.ts: -------------------------------------------------------------------------------- 1 | import { ImmerHook, useImmer } from "use-immer" 2 | import { useRef, useEffect } from "react" 3 | 4 | export const useSyncedState = <TState>( 5 | initialState: TState, 6 | syncCallback: (state: TState) => void 7 | ): ImmerHook<TState> => { 8 | const [state, setState] = useImmer(initialState) 9 | const didMountRef = useRef(false) 10 | 11 | useEffect(() => { 12 | if(didMountRef.current){ 13 | syncCallback(state) 14 | } 15 | didMountRef.current = true; 16 | }, [state, setState]) 17 | 18 | return [state, setState] 19 | } 20 | -------------------------------------------------------------------------------- /src/state/withInitialState.tsx: -------------------------------------------------------------------------------- 1 | import { Page } from "../utils/types"; 2 | import { useMatch } from "react-router-dom"; 3 | import { useState, useEffect, useRef } from "react"; 4 | import { supabase } from "../supabaseClient"; 5 | import startPageScaffold from "./startPageScaffold.json"; 6 | import styles from "../utils.module.css"; 7 | import { Loader } from "../components/Loader"; 8 | 9 | type InjectedProps = { 10 | initialState: Page; 11 | }; 12 | 13 | type PropsWithoutInjected<TBaseProps> = Omit<TBaseProps, keyof InjectedProps>; 14 | 15 | export function withInitialState<TProps>( 16 | WrappedComponent: React.ComponentType< 17 | PropsWithoutInjected<TProps> & InjectedProps 18 | > 19 | ) { 20 | return (props: PropsWithoutInjected<TProps>) => { 21 | const match = useMatch("/:slug"); 22 | const pageSlug = match ? match.params.slug : "start"; 23 | 24 | const [initialState, setInitialState] = useState<Page | null>(); 25 | const [isLoading, setIsLoading] = useState(true); 26 | const [error, setError] = useState<Error | undefined>(); 27 | const inProgress = useRef(false) 28 | 29 | useEffect(() => { 30 | if (inProgress.current) { 31 | return 32 | } 33 | setIsLoading(true); 34 | inProgress.current = true 35 | const fetchInitialState = async () => { 36 | try { 37 | const { data: userData } = await supabase.auth.getUser(); 38 | const user = userData.user; 39 | if (!user) { 40 | throw new Error("User is not logged in"); 41 | } 42 | const { data } = await supabase 43 | .from("pages") 44 | .select("title, id, cover, nodes, slug") 45 | .match({ slug: pageSlug, created_by: user.id }) 46 | 47 | if (data?.[0]) { 48 | setInitialState(data?.[0]); 49 | inProgress.current = false; 50 | setIsLoading(false); 51 | return 52 | } 53 | 54 | if (pageSlug === "start") { 55 | await supabase 56 | .from("pages") 57 | .insert({ 58 | ...startPageScaffold, 59 | slug: "start", 60 | created_by: user.id, 61 | }) 62 | 63 | const { data } = await supabase 64 | .from("pages") 65 | .select("title, id, cover, nodes, slug") 66 | .match({ slug: "start", created_by: user.id }) 67 | 68 | setInitialState(data?.[0]); 69 | } else { 70 | setInitialState(data?.[0]); 71 | } 72 | } catch (e) { 73 | if (e instanceof Error) { 74 | setError(e); 75 | } 76 | } 77 | inProgress.current = false; 78 | setIsLoading(false); 79 | }; 80 | fetchInitialState(); 81 | }, [pageSlug]); 82 | 83 | if (isLoading) { 84 | return ( 85 | <div className={styles.centeredFlex}> 86 | <Loader /> 87 | </div> 88 | ); 89 | } 90 | 91 | if (error) { 92 | return <div>{error.message}</div>; 93 | } 94 | 95 | if (!initialState) { 96 | return <div className={styles.centeredFlex}>Page not found</div>; 97 | } 98 | 99 | return <WrappedComponent {...props} initialState={initialState} />; 100 | }; 101 | } 102 | -------------------------------------------------------------------------------- /src/supabaseClient.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from "@supabase/supabase-js" 2 | 3 | const supabaseUrl = import.meta.env.VITE_SUPABASE_URL; 4 | const supabaseKey = import.meta.env.VITE_SUPABASE_API_KEY; 5 | 6 | if(!supabaseUrl || !supabaseKey){ 7 | throw new Error("Missing supabase url or key") 8 | } 9 | 10 | export const supabase = createClient(supabaseUrl, supabaseKey) 11 | -------------------------------------------------------------------------------- /src/utils.module.css: -------------------------------------------------------------------------------- 1 | .centeredFlex { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/createPage.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from "nanoid"; 2 | import { supabase } from "../supabaseClient"; 3 | 4 | export const createPage = async () => { 5 | const { data: userData } = await supabase.auth.getUser(); 6 | const user = userData.user; 7 | if (!user) { 8 | throw new Error("You must be logged in to create a page."); 9 | } 10 | const slug = nanoid(); 11 | 12 | const page = { 13 | id: undefined, 14 | title: "Untitled", 15 | slug, 16 | nodes: [], 17 | created_by: user.id, 18 | }; 19 | 20 | await supabase.from("pages").insert(page); 21 | const { data: pageData } = await supabase 22 | .from("pages") 23 | .select("id") 24 | .match({ slug, created_by: user.id }) 25 | .single(); 26 | 27 | page.id = pageData?.id; 28 | 29 | return page; 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /src/utils/debounce.ts: -------------------------------------------------------------------------------- 1 | type ArgumentTypes<F extends Function> = F extends (...args: infer A) => any 2 | ? A 3 | : never; 4 | 5 | export function debounce<TCallback extends Function>( 6 | callback: TCallback, 7 | delay = 300 8 | ) { 9 | let timeoutId: ReturnType<typeof setTimeout>; 10 | return function (...args: ArgumentTypes<TCallback>) { 11 | clearTimeout(timeoutId); 12 | timeoutId = setTimeout(() => callback(...args), delay); 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/types.ts: -------------------------------------------------------------------------------- 1 | export type NodeType = "text" | "image" | "list" | "page" | "heading1" | "heading2" | "heading3" 2 | 3 | export type NodeData = { 4 | id: string; 5 | type: NodeType; 6 | value: string; 7 | } 8 | 9 | export type Page = { 10 | id: string; 11 | slug: string; 12 | title: string; 13 | nodes: NodeData[]; 14 | cover: string; 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/updatePage.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "../utils/types"; 2 | import { supabase } from "../supabaseClient"; 3 | import { debounce } from "./debounce"; 4 | 5 | export const updatePage = debounce( 6 | async (page: Partial<Page> & Pick<Page, "id">) => { 7 | await supabase.from("pages").update(page).eq("id", page.id); 8 | }, 9 | 500 10 | ); 11 | -------------------------------------------------------------------------------- /src/utils/uploadImage.ts: -------------------------------------------------------------------------------- 1 | import { supabase } from "../supabaseClient" 2 | 3 | export const uploadImage = async (file?: File) => { 4 | try { 5 | if(!file){ 6 | throw new Error("You must select an image to upload"); 7 | } 8 | 9 | const fileExt = file.name.split(".").pop() 10 | const fileName = `${Math.random()}.${fileExt}` 11 | const filePath = fileName; 12 | 13 | await supabase.storage.from("images").upload(filePath, file); 14 | 15 | return {filePath, fileName} 16 | } catch (e) { 17 | alert(e) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// <reference types="vite/client" /> 2 | -------------------------------------------------------------------------------- /supabase/.gitignore: -------------------------------------------------------------------------------- 1 | # Supabase 2 | .branches 3 | .temp 4 | -------------------------------------------------------------------------------- /supabase/config.toml: -------------------------------------------------------------------------------- 1 | # A string used to distinguish different Supabase projects on the same host. Defaults to the 2 | # working directory name when running `supabase init`. 3 | project_id = "ztm-notion-clone" 4 | 5 | [api] 6 | # Port to use for the API URL. 7 | port = 54321 8 | # Schemas to expose in your API. Tables, views and stored procedures in this schema will get API 9 | # endpoints. public and storage are always included. 10 | schemas = ["public", "storage", "graphql_public"] 11 | # Extra schemas to add to the search_path of every request. public is always included. 12 | extra_search_path = ["public", "extensions"] 13 | # The maximum number of rows returns from a view, table, or stored procedure. Limits payload size 14 | # for accidental or malicious requests. 15 | max_rows = 1000 16 | 17 | [db] 18 | # Port to use for the local database URL. 19 | port = 54322 20 | # Port used by db diff command to initialise the shadow database. 21 | shadow_port = 54320 22 | # The database major version to use. This has to be the same as your remote database's. Run `SHOW 23 | # server_version;` on the remote database to check. 24 | major_version = 15 25 | 26 | [studio] 27 | enabled = true 28 | # Port to use for Supabase Studio. 29 | port = 54323 30 | # External URL of the API server that frontend connects to. 31 | api_url = "http://localhost" 32 | 33 | # Email testing server. Emails sent with the local dev setup are not actually sent - rather, they 34 | # are monitored, and you can view the emails that would have been sent from the web interface. 35 | [inbucket] 36 | enabled = true 37 | # Port to use for the email testing server web interface. 38 | port = 54324 39 | # Uncomment to expose additional ports for testing user applications that send emails. 40 | # smtp_port = 54325 41 | # pop3_port = 54326 42 | 43 | [storage] 44 | # The maximum file size allowed (e.g. "5MB", "500KB"). 45 | file_size_limit = "50MiB" 46 | 47 | [auth] 48 | # The base URL of your website. Used as an allow-list for redirects and for constructing URLs used 49 | # in emails. 50 | site_url = "http://localhost:3000" 51 | # A list of *exact* URLs that auth providers are permitted to redirect to post authentication. 52 | additional_redirect_urls = ["https://localhost:3000"] 53 | # How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). 54 | jwt_expiry = 3600 55 | # If disabled, the refresh token will never expire. 56 | enable_refresh_token_rotation = true 57 | # Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. 58 | # Requires enable_refresh_token_rotation = true. 59 | refresh_token_reuse_interval = 10 60 | # Allow/disallow new user signups to your project. 61 | enable_signup = true 62 | 63 | [auth.email] 64 | # Allow/disallow new user signups via email to your project. 65 | enable_signup = true 66 | # If enabled, a user will be required to confirm any email change on both the old, and new email 67 | # addresses. If disabled, only the new email is required to confirm. 68 | double_confirm_changes = true 69 | # If enabled, users need to confirm their email address before signing in. 70 | enable_confirmations = false 71 | 72 | [auth.sms] 73 | # Allow/disallow new user signups via SMS to your project. 74 | enable_signup = true 75 | # If enabled, users need to confirm their phone number before signing in. 76 | enable_confirmations = false 77 | 78 | # Configure one of the supported SMS providers: `twilio`, `messagebird`, `textlocal`, `vonage`. 79 | [auth.sms.twilio] 80 | enabled = false 81 | account_sid = "" 82 | message_service_sid = "" 83 | # DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: 84 | auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" 85 | 86 | # Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, 87 | # `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin`, `notion`, `twitch`, 88 | # `twitter`, `slack`, `spotify`, `workos`, `zoom`. 89 | [auth.external.apple] 90 | enabled = false 91 | client_id = "" 92 | # DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: 93 | secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" 94 | # Overrides the default auth redirectUrl. 95 | redirect_uri = "" 96 | # Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, 97 | # or any other third-party OIDC providers. 98 | url = "" 99 | 100 | [analytics] 101 | enabled = false 102 | port = 54327 103 | vector_port = 54328 104 | # Setup BigQuery project to enable log viewer on local development stack. 105 | # See: https://supabase.com/docs/guides/getting-started/local-development#enabling-local-logging 106 | gcp_project_id = "" 107 | gcp_project_number = "" 108 | gcp_jwt_path = "supabase/gcloud.json" 109 | -------------------------------------------------------------------------------- /supabase/functions/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["denoland.vscode-deno"] 3 | } 4 | -------------------------------------------------------------------------------- /supabase/functions/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.lint": true, 4 | "editor.defaultFormatter": "denoland.vscode-deno" 5 | } 6 | -------------------------------------------------------------------------------- /supabase/seed.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/satansdeer/ztm-notion-clone/83f407169bf413804cd2f0af07278d500e85120f/supabase/seed.sql -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react-swc' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ztm-notion-clone.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "name": "project-root", 5 | "path": "./" 6 | }, 7 | { 8 | "name": "supabase-functions", 9 | "path": "supabase/functions" 10 | } 11 | ], 12 | "settings": { 13 | "files.exclude": { 14 | "supabase/functions/": true 15 | } 16 | } 17 | } 18 | --------------------------------------------------------------------------------