├── .dockerignore ├── .editorconfig ├── .eslintignore ├── .eslintrc.cjs ├── .github └── workflows │ ├── ci.yml │ ├── main.yml │ └── production.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── Dockerfile ├── README.md ├── docker-compose.yml ├── example.env ├── excalidraw └── Waiting List Invite-2021-11-24-2244.excalidraw ├── fly.toml ├── ley.config.cjs ├── migrations ├── 00000-create_profile_table.cjs ├── 00001-handle_new_profile_function.cjs ├── 00002-create_waiting_list_table.cjs ├── 00003-create_is_admin_function.cjs ├── 00004-create_rls_policy_profiles.cjs ├── 00005-create_rls_policy_waiting_list.cjs ├── 00006-handle_waiting_list_invited_at_function.cjs ├── 00007-enable_rls_migrations.cjs ├── 00008-add_cascade_delete_constraint_profiles.cjs └── 00009-add_reference_from_users_to_waiting_list.cjs ├── package.json ├── pnpm-lock.yaml ├── src ├── app.d.ts ├── app.html ├── hooks.server.ts ├── lib │ ├── admin.ts │ ├── common │ │ ├── ButtonAction.svelte │ │ ├── ButtonWithIcon.svelte │ │ ├── FullScreenLoader.svelte │ │ ├── GitHubButton.svelte │ │ ├── Header.svelte │ │ ├── InlineLoader.svelte │ │ ├── Loader.svelte │ │ ├── Notification.svelte │ │ └── TwitterButton.svelte │ ├── data │ │ └── mappers │ │ │ ├── internal.ts │ │ │ ├── users.ts │ │ │ └── waiting_list.ts │ ├── handleAuth.ts │ ├── handleProfile.ts │ ├── schema.ts │ ├── utils.ts │ └── validationSchema.ts └── routes │ ├── +layout.server.ts │ ├── +layout.svelte │ ├── +layout.ts │ ├── +page.server.ts │ ├── +page.svelte │ ├── account │ ├── +layout.server.ts │ ├── +layout.svelte │ ├── +page.svelte │ └── password-update │ │ ├── +page.server.ts │ │ └── +page.svelte │ ├── auth │ ├── +layout.svelte │ ├── +page.ts │ ├── confirm │ │ └── +server.ts │ ├── forgotpassword │ │ ├── +page.server.ts │ │ └── +page.svelte │ ├── invite-code │ │ ├── +page.server.ts │ │ └── +page.svelte │ ├── signin │ │ ├── +page.server.ts │ │ └── +page.svelte │ ├── signout │ │ └── +page.server.ts │ └── signup │ │ ├── +page.server.ts │ │ └── +page.svelte │ └── manage │ ├── +layout.server.ts │ ├── +layout.svelte │ ├── +page.server.ts │ ├── +page.svelte │ ├── Layout.svelte │ └── users │ ├── +page.server.ts │ └── +page.svelte ├── static ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── css │ └── bulma.min.css ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── favicon.png ├── img │ ├── 1280x960.png │ ├── WaitingList_Icon.png │ ├── WaitingList_Logo.svg │ └── WaitingList_Placeholder.png └── site.webmanifest ├── supabase ├── .gitignore ├── auth │ └── email │ │ ├── confirmation.html │ │ ├── email-change.html │ │ ├── invite.html │ │ ├── magic-link.html │ │ └── recovery.html ├── config.toml ├── migrations │ ├── 20230529164842_create_profile_table.sql │ ├── 20230529164939_handle_new_profile_function.sql │ ├── 20230529170733_create_waiting_list_table.sql │ ├── 20230529170749_create_is_admin_function.sql │ ├── 20230529170805_create_rls_policy_profiles.sql │ ├── 20230529170821_create_rls_policy_waiting_list.sql │ ├── 20230529170846_handle_waiting_list_invited_at_function.sql │ ├── 20230529170913_add_cascade_delete_constraint_profiles.sql │ ├── 20230529170940_add_reference_from_users_to_waiting_list.sql │ ├── 20230601000442_update_profile_table_and_add_trigger_function.sql │ └── 20230903015359_waiting_list_email_confirmed_function.sql └── seed.sql ├── svelte.config.js ├── tsconfig.json └── vite.config.js /.dockerignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules 3 | excalidraw -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = tab 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | supabase/**/*.sql 10 | 11 | # Ignore files for PNPM, NPM and YARN 12 | pnpm-lock.yaml 13 | package-lock.json 14 | yarn.lock 15 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v3 13 | 14 | - uses: supabase/setup-cli@v1 15 | with: 16 | version: latest 17 | 18 | - name: Start Supabase local development setup 19 | run: supabase start -x realtime,storage-api,imgproxy,inbucket,studio,edge-runtime,logflare,vector,pgbouncer 20 | 21 | - name: Verify generated types are checked in 22 | run: | 23 | supabase gen types typescript --local > types.gen.ts 24 | if ! git diff --ignore-space-at-eol --exit-code --quiet types.gen.ts; then 25 | echo "Detected uncommitted changes after build. See status below:" 26 | git diff 27 | exit 1 28 | fi 29 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Fly deploy 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | jobs: 8 | deploy: 9 | name: Deploy app 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout app 13 | uses: actions/checkout@v2 14 | 15 | - name: Deploy app 16 | uses: superfly/flyctl-actions@1.1 17 | with: 18 | args: 'deploy 19 | --no-cache 20 | --local-only 21 | --detach 22 | --build-arg PUBLIC_SUPABASE_URL=${{ secrets.PUBLIC_SUPABASE_URL }} 23 | --build-arg PUBLIC_SUPABASE_ANON_KEY=${{ secrets.PUBLIC_SUPABASE_ANON_KEY }} 24 | --build-arg SUPABASE_SERVICE_ROLE_KEY=${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}' 25 | env: 26 | FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} 27 | -------------------------------------------------------------------------------- /.github/workflows/production.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Migrations to Production 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | 13 | env: 14 | SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} 15 | SUPABASE_DB_PASSWORD: ${{ secrets.PRODUCTION_DB_PASSWORD }} 16 | SUPABASE_PROJECT_ID: ${{ secrets.PRODUCTION_PROJECT_ID }} 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | 21 | - uses: supabase/setup-cli@v1 22 | with: 23 | version: latest 24 | 25 | - run: supabase link --project-ref $SUPABASE_PROJECT_ID 26 | - run: supabase db push 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .pnpm-debug.log 4 | /.svelte-kit 5 | /package 6 | /build 7 | .env* 8 | .yalc 9 | yalc.lock -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .svelte-kit/** 2 | static/** 3 | build/** 4 | node_modules/** 5 | supabase/**/*.sql 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "semi": false, 4 | "singleQuote": true, 5 | "trailingComma": "none", 6 | "tabWidth": 2, 7 | "printWidth": 100, 8 | "plugins": ["prettier-plugin-svelte"], 9 | "pluginSearchDirs": ["."], 10 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 11 | } 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Install dependencies only when needed 2 | FROM node:alpine AS deps 3 | # Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. 4 | RUN apk add --no-cache libc6-compat 5 | WORKDIR /app 6 | COPY package.json pnpm-lock.yaml ./ 7 | RUN npm install -g pnpm 8 | RUN pnpm -v 9 | RUN pnpm install --frozen-lockfile 10 | 11 | # Rebuild the source code only when needed 12 | FROM node:alpine AS builder 13 | WORKDIR /app 14 | COPY . . 15 | COPY --from=deps /app/node_modules ./node_modules 16 | ARG PUBLIC_SUPABASE_URL 17 | ARG PUBLIC_SUPABASE_ANON_KEY 18 | ARG SUPABASE_SERVICE_ROLE_KEY 19 | ENV PUBLIC_SUPABASE_URL=$PUBLIC_SUPABASE_URL 20 | ENV PUBLIC_SUPABASE_ANON_KEY=$PUBLIC_SUPABASE_ANON_KEY 21 | ENV SUPABASE_SERVICE_ROLE_KEY=$SUPABASE_SERVICE_ROLE_KEY 22 | ENV NODE_ENV=production 23 | RUN echo $NODE_ENV 24 | RUN echo $PUBLIC_SUPABASE_URL 25 | RUN npm install -g pnpm 26 | RUN pnpm build && pnpm install --prod --ignore-scripts --prefer-offline 27 | 28 | # Production image, copy all the files and run next 29 | FROM node:alpine AS runner 30 | WORKDIR /app 31 | 32 | ENV NODE_ENV production 33 | RUN echo $NODE_ENV 34 | # RUN addgroup -g 1001 -S nodejs 35 | # RUN adduser -S nextjs -u 1001 36 | 37 | COPY --from=builder /app/build ./build 38 | COPY --from=builder /app/node_modules ./node_modules 39 | COPY --from=builder /app/package.json ./package.json 40 | 41 | EXPOSE 3000 42 | CMD ["node", "./build"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Waiting List App 2 | 3 | Example Supabase application showing how to use the `inviteUserByEmail` api to invite users to your application. 4 | 5 | This project is built with: 6 | 7 | - [SvelteKit](https://kit.svelte.dev/) 8 | - [Bulma](https://bulma.io/) 9 | - [Vest](https://vestjs.dev/) 10 | - [Supabase](https://supabase.com/) 11 | 12 | ## Features 13 | 14 | - Invite List 15 | - Sign Up to Invite 16 | - Forgot Password 17 | - Admin Registration 18 | 19 | ## Getting started 20 | 21 | Clone the project from GitHub 22 | 23 | ```sh 24 | git clone https://github.com/silentworks/waiting-list 25 | cd waiting-list 26 | ``` 27 | 28 | ## Developing 29 | 30 | Copy the `env.example` and name it `.env` 31 | 32 | Edit the file and enter all the required variable values 33 | 34 | ``` 35 | PUBLIC_SUPABASE_URL= 36 | PUBLIC_SUPABASE_ANON_KEY= 37 | SUPABASE_SERVICE_ROLE_KEY= 38 | ``` 39 | 40 | This project makes use of the [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started) which uses docker under the hood for setting up a Supabase project locally. Docker must be running before attempting to run any of the `supaabse` commands. 41 | 42 | ### Starting your project 43 | 44 | ```sh 45 | pnpm exec supabase start 46 | ``` 47 | 48 | This commend will download the necessary docker containers and run the migration files inside of the `supabase/migrations` directory. 49 | 50 | ### Run database migrations 51 | 52 | When creating a new migration file you can manually run the command below to update your local database. 53 | 54 | ```sh 55 | pnpm exec supabase migration up 56 | ``` 57 | 58 | ### Creating admin user 59 | 60 | Once the project server is running you can visit the signup path `/auth/signup` to create your admin user. 61 | 62 | > Note that once you have created your admin user, this route will no longer be accessible. 63 | 64 | ### Start development server 65 | 66 | Once you've created a project and installed dependencies with `pnpm install` (or `npm install` or `yarn`), start a development server: 67 | 68 | ```bash 69 | pnpm dev 70 | 71 | # or start the server and open the app in a new browser tab 72 | pnpm dev -- --open 73 | ``` 74 | 75 | ## Production 76 | 77 | There are email templates in this project that are used for local development. To update your hosted project, please copy the templates from `supabase/auth/email` into the [Email Templates](https://supabase.com/dashboard/project/_/auth/templates) section of the Dashboard. 78 | 79 | This project also contains GitHub workflow files for deploying your application into production using [Fly.io](https://fly.io/). 80 | 81 | ### Building 82 | 83 | To manually create a production version of your app: 84 | 85 | ```bash 86 | pnpm build 87 | ``` 88 | 89 | You can preview the production build with `pnpm preview`. 90 | 91 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 92 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | web: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | args: 8 | PUBLIC_SUPABASE_URL: 9 | PUBLIC_SUPABASE_ANON_KEY: 10 | SUPABASE_SERVICE_ROLE_KEY: 11 | ports: 12 | - 80:3000 13 | volumes: 14 | - ./build:/app/build/ 15 | -------------------------------------------------------------------------------- /example.env: -------------------------------------------------------------------------------- 1 | VITE_APP_URL=http://localhost:3000/ 2 | VITE_SUPABASE_URL=http://localhost:58721 3 | VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0 4 | SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU 5 | CONNECTION_STRING=postgresql://postgres:postgres@localhost:58722/postgres 6 | -------------------------------------------------------------------------------- /excalidraw/Waiting List Invite-2021-11-24-2244.excalidraw: -------------------------------------------------------------------------------- 1 | { 2 | "type": "excalidraw", 3 | "version": 2, 4 | "source": "https://excalidraw.com", 5 | "elements": [ 6 | { 7 | "id": "dyI6CT0bsUSoml20qsE-B", 8 | "type": "rectangle", 9 | "x": 595, 10 | "y": 231, 11 | "width": 203, 12 | "height": 120, 13 | "angle": 0, 14 | "strokeColor": "#000000", 15 | "backgroundColor": "#15aabf", 16 | "fillStyle": "hachure", 17 | "strokeWidth": 1, 18 | "strokeStyle": "solid", 19 | "roughness": 1, 20 | "opacity": 100, 21 | "groupIds": [ 22 | "82qVLhXhxIHVlLQnvbLfm" 23 | ], 24 | "strokeSharpness": "sharp", 25 | "seed": 730137383, 26 | "version": 144, 27 | "versionNonce": 1042900585, 28 | "isDeleted": false, 29 | "boundElementIds": [ 30 | "S_0RniDd6WXpUJ6PgDQ9m" 31 | ], 32 | "updated": 1637794273260 33 | }, 34 | { 35 | "id": "4VYeu-_U5hFw--6b1dRF_", 36 | "type": "text", 37 | "x": 615, 38 | "y": 271, 39 | "width": 163, 40 | "height": 35, 41 | "angle": 0, 42 | "strokeColor": "#000000", 43 | "backgroundColor": "#15aabf", 44 | "fillStyle": "hachure", 45 | "strokeWidth": 1, 46 | "strokeStyle": "solid", 47 | "roughness": 1, 48 | "opacity": 100, 49 | "groupIds": [ 50 | "82qVLhXhxIHVlLQnvbLfm" 51 | ], 52 | "strokeSharpness": "sharp", 53 | "seed": 1114113607, 54 | "version": 80, 55 | "versionNonce": 542462119, 56 | "isDeleted": false, 57 | "boundElementIds": null, 58 | "updated": 1637794273260, 59 | "text": "Waiting List", 60 | "fontSize": 28, 61 | "fontFamily": 1, 62 | "textAlign": "left", 63 | "verticalAlign": "top", 64 | "baseline": 25 65 | }, 66 | { 67 | "id": "oI_oa01nIstfVDjzRkIND", 68 | "type": "rectangle", 69 | "x": 591, 70 | "y": 500, 71 | "width": 203, 72 | "height": 120, 73 | "angle": 0, 74 | "strokeColor": "#000000", 75 | "backgroundColor": "#15aabf", 76 | "fillStyle": "hachure", 77 | "strokeWidth": 1, 78 | "strokeStyle": "solid", 79 | "roughness": 1, 80 | "opacity": 100, 81 | "groupIds": [ 82 | "772_1w_nX7BQSuDPtSCvA" 83 | ], 84 | "strokeSharpness": "sharp", 85 | "seed": 162291561, 86 | "version": 223, 87 | "versionNonce": 920826185, 88 | "isDeleted": false, 89 | "boundElementIds": [ 90 | "S_0RniDd6WXpUJ6PgDQ9m", 91 | "H0tOEGTyaNOjtrJ36aPit" 92 | ], 93 | "updated": 1637794273260 94 | }, 95 | { 96 | "id": "joTpmtyazilbLc8GXRnjw", 97 | "type": "text", 98 | "x": 650, 99 | "y": 541, 100 | "width": 80, 101 | "height": 35, 102 | "angle": 0, 103 | "strokeColor": "#000000", 104 | "backgroundColor": "#15aabf", 105 | "fillStyle": "hachure", 106 | "strokeWidth": 1, 107 | "strokeStyle": "solid", 108 | "roughness": 1, 109 | "opacity": 100, 110 | "groupIds": [ 111 | "772_1w_nX7BQSuDPtSCvA" 112 | ], 113 | "strokeSharpness": "sharp", 114 | "seed": 1771997769, 115 | "version": 192, 116 | "versionNonce": 584229831, 117 | "isDeleted": false, 118 | "boundElementIds": null, 119 | "updated": 1637794273260, 120 | "text": "Invite", 121 | "fontSize": 28, 122 | "fontFamily": 1, 123 | "textAlign": "left", 124 | "verticalAlign": "top", 125 | "baseline": 25 126 | }, 127 | { 128 | "id": "S_0RniDd6WXpUJ6PgDQ9m", 129 | "type": "arrow", 130 | "x": 681.4912752709607, 131 | "y": 352, 132 | "width": 1.2810420577397963, 133 | "height": 145.2138271767646, 134 | "angle": 0, 135 | "strokeColor": "#000000", 136 | "backgroundColor": "#15aabf", 137 | "fillStyle": "hachure", 138 | "strokeWidth": 1, 139 | "strokeStyle": "solid", 140 | "roughness": 1, 141 | "opacity": 100, 142 | "groupIds": [], 143 | "strokeSharpness": "round", 144 | "seed": 1476096711, 145 | "version": 124, 146 | "versionNonce": 680925257, 147 | "isDeleted": false, 148 | "boundElementIds": null, 149 | "updated": 1637794273260, 150 | "points": [ 151 | [ 152 | 0, 153 | 0 154 | ], 155 | [ 156 | 1.2810420577397963, 157 | 145.2138271767646 158 | ] 159 | ], 160 | "lastCommittedPoint": null, 161 | "startBinding": { 162 | "focus": 0.1437688409132372, 163 | "gap": 1, 164 | "elementId": "dyI6CT0bsUSoml20qsE-B" 165 | }, 166 | "endBinding": { 167 | "focus": -0.119316678659409, 168 | "gap": 2.786172823235404, 169 | "elementId": "oI_oa01nIstfVDjzRkIND" 170 | }, 171 | "startArrowhead": null, 172 | "endArrowhead": "arrow" 173 | }, 174 | { 175 | "id": "VCnO2jsgAG1r3VQcs6NPq", 176 | "type": "ellipse", 177 | "x": 908, 178 | "y": 517, 179 | "width": 214, 180 | "height": 121, 181 | "angle": 0, 182 | "strokeColor": "#000000", 183 | "backgroundColor": "#40c057", 184 | "fillStyle": "hachure", 185 | "strokeWidth": 1, 186 | "strokeStyle": "solid", 187 | "roughness": 1, 188 | "opacity": 100, 189 | "groupIds": [ 190 | "K3CBeT_nJCOt8dVSTa80H" 191 | ], 192 | "strokeSharpness": "sharp", 193 | "seed": 673166921, 194 | "version": 199, 195 | "versionNonce": 209228519, 196 | "isDeleted": false, 197 | "boundElementIds": [ 198 | "H0tOEGTyaNOjtrJ36aPit", 199 | "7pIrQWMKFN8JGvoD15Vvg" 200 | ], 201 | "updated": 1637794273260 202 | }, 203 | { 204 | "id": "lMd1Qmi-IlHRo-erw-YUG", 205 | "type": "text", 206 | "x": 938, 207 | "y": 567.5, 208 | "width": 161, 209 | "height": 25, 210 | "angle": 0, 211 | "strokeColor": "#000000", 212 | "backgroundColor": "#fa5252", 213 | "fillStyle": "hachure", 214 | "strokeWidth": 1, 215 | "strokeStyle": "solid", 216 | "roughness": 1, 217 | "opacity": 100, 218 | "groupIds": [ 219 | "K3CBeT_nJCOt8dVSTa80H" 220 | ], 221 | "strokeSharpness": "sharp", 222 | "seed": 1363412265, 223 | "version": 183, 224 | "versionNonce": 54244105, 225 | "isDeleted": false, 226 | "boundElementIds": [ 227 | "H0tOEGTyaNOjtrJ36aPit" 228 | ], 229 | "updated": 1637794273260, 230 | "text": "Send invite email", 231 | "fontSize": 20, 232 | "fontFamily": 1, 233 | "textAlign": "left", 234 | "verticalAlign": "top", 235 | "baseline": 18 236 | }, 237 | { 238 | "id": "H0tOEGTyaNOjtrJ36aPit", 239 | "type": "arrow", 240 | "x": 799, 241 | "y": 560.3693177571904, 242 | "width": 97.39473623948857, 243 | "height": 1.2366707557928294, 244 | "angle": 0, 245 | "strokeColor": "#000000", 246 | "backgroundColor": "#40c057", 247 | "fillStyle": "hachure", 248 | "strokeWidth": 1, 249 | "strokeStyle": "solid", 250 | "roughness": 1, 251 | "opacity": 100, 252 | "groupIds": [], 253 | "strokeSharpness": "round", 254 | "seed": 538029671, 255 | "version": 235, 256 | "versionNonce": 1705848007, 257 | "isDeleted": false, 258 | "boundElementIds": null, 259 | "updated": 1637794273260, 260 | "points": [ 261 | [ 262 | 0, 263 | 0 264 | ], 265 | [ 266 | 97.39473623948857, 267 | -1.2366707557928294 268 | ] 269 | ], 270 | "lastCommittedPoint": null, 271 | "startBinding": { 272 | "elementId": "oI_oa01nIstfVDjzRkIND", 273 | "focus": 0.0421183508135312, 274 | "gap": 5 275 | }, 276 | "endBinding": { 277 | "elementId": "VCnO2jsgAG1r3VQcs6NPq", 278 | "focus": 0.3284022386437304, 279 | "gap": 15.253219960678479 280 | }, 281 | "startArrowhead": null, 282 | "endArrowhead": "arrow" 283 | }, 284 | { 285 | "id": "oF0d-nG4BUjdXuYRYgCz5", 286 | "type": "rectangle", 287 | "x": 1246, 288 | "y": 517, 289 | "width": 203, 290 | "height": 120, 291 | "angle": 0, 292 | "strokeColor": "#000000", 293 | "backgroundColor": "#fd7e14", 294 | "fillStyle": "hachure", 295 | "strokeWidth": 1, 296 | "strokeStyle": "solid", 297 | "roughness": 1, 298 | "opacity": 100, 299 | "groupIds": [ 300 | "entrEnVP68Ue3_W4hcSIH", 301 | "f4iCTDZ2PY86n6DudckVf" 302 | ], 303 | "strokeSharpness": "sharp", 304 | "seed": 409941417, 305 | "version": 419, 306 | "versionNonce": 2130651239, 307 | "isDeleted": false, 308 | "boundElementIds": [ 309 | "S_0RniDd6WXpUJ6PgDQ9m", 310 | "H0tOEGTyaNOjtrJ36aPit", 311 | "7pIrQWMKFN8JGvoD15Vvg" 312 | ], 313 | "updated": 1637794281913 314 | }, 315 | { 316 | "id": "PVI2M9u_0vTebQWgq9xuK", 317 | "type": "text", 318 | "x": 1280, 319 | "y": 549, 320 | "width": 144, 321 | "height": 50, 322 | "angle": 0, 323 | "strokeColor": "#000000", 324 | "backgroundColor": "#15aabf", 325 | "fillStyle": "hachure", 326 | "strokeWidth": 1, 327 | "strokeStyle": "solid", 328 | "roughness": 1, 329 | "opacity": 100, 330 | "groupIds": [ 331 | "entrEnVP68Ue3_W4hcSIH", 332 | "f4iCTDZ2PY86n6DudckVf" 333 | ], 334 | "strokeSharpness": "sharp", 335 | "seed": 1449377351, 336 | "version": 473, 337 | "versionNonce": 1126538345, 338 | "isDeleted": false, 339 | "boundElementIds": null, 340 | "updated": 1637794281913, 341 | "text": "Change user's \ninvited state", 342 | "fontSize": 20, 343 | "fontFamily": 1, 344 | "textAlign": "left", 345 | "verticalAlign": "top", 346 | "baseline": 43 347 | }, 348 | { 349 | "id": "85klB8eGYhaM4plT60oa5", 350 | "type": "text", 351 | "x": 1251, 352 | "y": 480, 353 | "width": 69, 354 | "height": 25, 355 | "angle": 0, 356 | "strokeColor": "#000000", 357 | "backgroundColor": "#fd7e14", 358 | "fillStyle": "hachure", 359 | "strokeWidth": 1, 360 | "strokeStyle": "solid", 361 | "roughness": 1, 362 | "opacity": 100, 363 | "groupIds": [ 364 | "f4iCTDZ2PY86n6DudckVf" 365 | ], 366 | "strokeSharpness": "sharp", 367 | "seed": 99111369, 368 | "version": 219, 369 | "versionNonce": 551516839, 370 | "isDeleted": false, 371 | "boundElementIds": null, 372 | "updated": 1637794281913, 373 | "text": "Trigger", 374 | "fontSize": 20, 375 | "fontFamily": 1, 376 | "textAlign": "left", 377 | "verticalAlign": "top", 378 | "baseline": 18 379 | }, 380 | { 381 | "id": "7pIrQWMKFN8JGvoD15Vvg", 382 | "type": "arrow", 383 | "x": 1129.320025488299, 384 | "y": 565.5391866857151, 385 | "width": 111.67997451170095, 386 | "height": 1.4580010360232336, 387 | "angle": 0, 388 | "strokeColor": "#000000", 389 | "backgroundColor": "#fd7e14", 390 | "fillStyle": "hachure", 391 | "strokeWidth": 1, 392 | "strokeStyle": "solid", 393 | "roughness": 1, 394 | "opacity": 100, 395 | "groupIds": [], 396 | "strokeSharpness": "round", 397 | "seed": 1849640009, 398 | "version": 263, 399 | "versionNonce": 99320711, 400 | "isDeleted": false, 401 | "boundElementIds": null, 402 | "updated": 1637794281913, 403 | "points": [ 404 | [ 405 | 0, 406 | 0 407 | ], 408 | [ 409 | 111.67997451170095, 410 | -1.4580010360232336 411 | ] 412 | ], 413 | "lastCommittedPoint": null, 414 | "startBinding": { 415 | "elementId": "VCnO2jsgAG1r3VQcs6NPq", 416 | "focus": -0.15702479338842976, 417 | "gap": 9.049037868169165 418 | }, 419 | "endBinding": { 420 | "elementId": "oF0d-nG4BUjdXuYRYgCz5", 421 | "focus": 0.2333333333333333, 422 | "gap": 5 423 | }, 424 | "startArrowhead": null, 425 | "endArrowhead": "arrow" 426 | } 427 | ], 428 | "appState": { 429 | "gridSize": null, 430 | "viewBackgroundColor": "#ffffff" 431 | }, 432 | "files": {} 433 | } -------------------------------------------------------------------------------- /fly.toml: -------------------------------------------------------------------------------- 1 | # fly.toml file generated for waiting-list on 2021-12-31T22:53:06Z 2 | 3 | app = "waiting-list" 4 | 5 | kill_signal = "SIGINT" 6 | kill_timeout = 5 7 | processes = [] 8 | 9 | [env] 10 | PORT = 8080 11 | 12 | [experimental] 13 | allowed_public_ports = [] 14 | auto_rollback = true 15 | 16 | [[services]] 17 | http_checks = [] 18 | internal_port = 8080 19 | processes = ["app"] 20 | protocol = "tcp" 21 | script_checks = [] 22 | 23 | [services.concurrency] 24 | hard_limit = 25 25 | soft_limit = 20 26 | type = "connections" 27 | 28 | [[services.ports]] 29 | handlers = ["http"] 30 | port = 80 31 | 32 | [[services.ports]] 33 | handlers = ["tls", "http"] 34 | port = 443 35 | 36 | [[services.tcp_checks]] 37 | grace_period = "1s" 38 | interval = "15s" 39 | restart_limit = 0 40 | timeout = "2s" 41 | -------------------------------------------------------------------------------- /ley.config.cjs: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | 3 | const options = {}; 4 | 5 | if (process.env.CONNECTION_STRING) { 6 | const { parse } = require("pg-connection-string"); 7 | const { host, database, port, user, password } = parse(process.env.CONNECTION_STRING); 8 | 9 | options.host = host; 10 | options.database = database; 11 | options.username = user; 12 | options.password = password; 13 | options.port = port; 14 | } 15 | 16 | module.exports = options; -------------------------------------------------------------------------------- /migrations/00000-create_profile_table.cjs: -------------------------------------------------------------------------------- 1 | exports.up = async (client) => { 2 | await client` 3 | create table public.profiles ( 4 | id uuid PRIMARY KEY REFERENCES auth.users NOT NULL, 5 | full_name VARCHAR NULL, 6 | is_admin BOOL DEFAULT FALSE, 7 | created_at TIMESTAMPTZ DEFAULT now() NOT NULL, 8 | updated_at TIMESTAMPTZ 9 | ) 10 | ` 11 | await client`alter table public.profiles enable row level security;` 12 | } 13 | 14 | exports.down = async (client) => { 15 | await client`alter table public.profiles disable row level security;` 16 | await client`drop table if exists public.profiles` 17 | } 18 | -------------------------------------------------------------------------------- /migrations/00001-handle_new_profile_function.cjs: -------------------------------------------------------------------------------- 1 | exports.up = async client => { 2 | await client` 3 | create function public.handle_new_profile() 4 | returns trigger as $$ 5 | begin 6 | insert into public.profiles (id, full_name, is_admin) 7 | values (new.id, new.raw_user_meta_data->>'full_name', (new.raw_user_meta_data->>'is_admin')::boolean); 8 | return new; 9 | end; 10 | $$ language plpgsql security definer; 11 | ` 12 | 13 | await client` 14 | create trigger on_auth_user_created 15 | after insert on auth.users 16 | for each row execute procedure public.handle_new_profile(); 17 | ` 18 | }; 19 | 20 | exports.down = async client => { 21 | // You will need to elevate the user in order for the down to run on the auth.users table 22 | // just run the code commented below inside of the supabase dashboard SQL editor 23 | // await client`alter user postgres with superuser;` 24 | await client`drop trigger if exists on_auth_user_created on auth.users;` 25 | await client`drop function if exists public.handle_new_profile();` 26 | // await client`alter user postgres with nosuperuser;` 27 | }; 28 | -------------------------------------------------------------------------------- /migrations/00002-create_waiting_list_table.cjs: -------------------------------------------------------------------------------- 1 | exports.up = async (client) => { 2 | await client` 3 | create table public.waiting_list ( 4 | id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), 5 | full_name VARCHAR NOT NULL, 6 | email VARCHAR UNIQUE NOT NULL, 7 | email_confirmed_at TIMESTAMPTZ, 8 | invited_at TIMESTAMPTZ, 9 | created_at TIMESTAMPTZ DEFAULT now() NOT NULL, 10 | updated_at TIMESTAMPTZ 11 | ) 12 | ` 13 | await client`alter table public.waiting_list enable row level security;` 14 | } 15 | 16 | exports.down = async (client) => { 17 | await client`alter table public.waiting_list disable row level security;` 18 | await client`drop table if exists public.waiting_list` 19 | } 20 | -------------------------------------------------------------------------------- /migrations/00003-create_is_admin_function.cjs: -------------------------------------------------------------------------------- 1 | exports.up = async client => { 2 | await client` 3 | -- admin check with boolean 4 | create function public.is_admin(user_id uuid) 5 | returns boolean as $$ 6 | declare 7 | admin int; 8 | begin 9 | select count(*) 10 | from public.profiles 11 | where profiles.is_admin 12 | and profiles.id = is_admin.user_id 13 | into admin; 14 | 15 | return admin > 0; 16 | end; 17 | $$ language plpgsql security definer; 18 | ` 19 | }; 20 | 21 | exports.down = async client => { 22 | await client`drop function if exists public.is_admin(user_id uuid);` 23 | }; 24 | -------------------------------------------------------------------------------- /migrations/00004-create_rls_policy_profiles.cjs: -------------------------------------------------------------------------------- 1 | exports.up = async client => { 2 | await client` 3 | CREATE POLICY "Allow select for admin users or own profile only" 4 | ON public.profiles 5 | FOR SELECT USING ( 6 | is_admin(auth.uid()) or auth.uid() = id 7 | );` 8 | 9 | await client` 10 | CREATE POLICY "Allow insert for own profile only" 11 | ON public.profiles 12 | FOR INSERT WITH CHECK (auth.uid() = id);` 13 | 14 | await client` 15 | -- update policy 16 | CREATE POLICY "Allow update for own profile only" 17 | ON public.profiles 18 | FOR UPDATE USING (auth.uid() = id);` 19 | 20 | await client` 21 | -- delete policy 22 | CREATE POLICY "Allow delete for own profile only" 23 | ON public.profiles 24 | FOR DELETE USING (auth.uid() = id);` 25 | }; 26 | 27 | exports.down = async client => { 28 | await client`DROP POLICY IF EXISTS "Allow select for admin users or own profile only" ON public.profiles` 29 | await client`DROP POLICY IF EXISTS "Allow insert for own profile only" ON public.profiles` 30 | await client`DROP POLICY IF EXISTS "Allow update for own profile only" ON public.profiles` 31 | await client`DROP POLICY IF EXISTS "Allow delete for own profile only" ON public.profiles` 32 | }; -------------------------------------------------------------------------------- /migrations/00005-create_rls_policy_waiting_list.cjs: -------------------------------------------------------------------------------- 1 | exports.up = async client => { 2 | await client` 3 | CREATE POLICY "Allow select for admin users only" 4 | ON public.waiting_list 5 | FOR SELECT USING ( 6 | is_admin(auth.uid()) 7 | );` 8 | 9 | await client` 10 | CREATE POLICY "Allow insert for all users" 11 | ON public.waiting_list 12 | FOR INSERT WITH CHECK (true);` 13 | 14 | await client` 15 | -- update policy 16 | CREATE POLICY "Allow update for admin users only" 17 | ON public.waiting_list 18 | FOR UPDATE USING ( 19 | is_admin(auth.uid()) 20 | );` 21 | 22 | await client` 23 | -- delete policy 24 | CREATE POLICY "Allow delete for admin users only" 25 | ON public.waiting_list 26 | FOR DELETE USING ( 27 | is_admin(auth.uid()) 28 | );` 29 | }; 30 | 31 | exports.down = async client => { 32 | await client`DROP POLICY IF EXISTS "Allow select for admin users only" ON public.waiting_list` 33 | await client`DROP POLICY IF EXISTS "Allow insert for all users" ON public.waiting_list` 34 | await client`DROP POLICY IF EXISTS "Allow update for admin users only" ON public.waiting_list` 35 | await client`DROP POLICY IF EXISTS "Allow delete for admin users only" ON public.waiting_list` 36 | }; -------------------------------------------------------------------------------- /migrations/00006-handle_waiting_list_invited_at_function.cjs: -------------------------------------------------------------------------------- 1 | exports.up = async client => { 2 | await client` 3 | create function public.handle_waiting_list_invited_at() 4 | returns trigger as $$ 5 | begin 6 | IF ((NEW.raw_user_meta_data->>'waiting_list_id')::uuid is null) THEN 7 | RETURN NULL; 8 | ELSE 9 | UPDATE public.waiting_list 10 | SET invited_at = NOW(), 11 | updated_at = NOW() 12 | WHERE id = (NEW.raw_user_meta_data->>'waiting_list_id')::uuid; 13 | RETURN NEW; 14 | END IF; 15 | end; 16 | $$ language plpgsql security definer; 17 | ` 18 | 19 | await client` 20 | create trigger on_invite_sent 21 | after insert on auth.users 22 | for each row execute procedure public.handle_waiting_list_invited_at(); 23 | ` 24 | }; 25 | 26 | exports.down = async client => { 27 | await client`drop trigger if exists on_invite_sent on auth.users;` 28 | await client`drop function if exists public.handle_waiting_list_invited_at();` 29 | }; 30 | -------------------------------------------------------------------------------- /migrations/00007-enable_rls_migrations.cjs: -------------------------------------------------------------------------------- 1 | exports.up = async client => { 2 | await client`alter table public.migrations enable row level security;` 3 | }; 4 | 5 | exports.down = async client => { 6 | await client`alter table public.migrations disable row level security;` 7 | }; 8 | -------------------------------------------------------------------------------- /migrations/00008-add_cascade_delete_constraint_profiles.cjs: -------------------------------------------------------------------------------- 1 | exports.up = async client => { 2 | await client` 3 | alter table profiles 4 | drop constraint if exists profiles_id_fkey, 5 | add constraint profiles_id_fkey 6 | foreign key (id) 7 | references auth.users 8 | on delete cascade; 9 | ` 10 | }; 11 | 12 | exports.down = async client => { 13 | await client`alter table profiles drop constraint profiles_id_fkey;` 14 | }; 15 | -------------------------------------------------------------------------------- /migrations/00009-add_reference_from_users_to_waiting_list.cjs: -------------------------------------------------------------------------------- 1 | exports.up = async client => { 2 | await client` 3 | alter table waiting_list 4 | add column profile_id uuid; 5 | ` 6 | 7 | await client` 8 | alter table waiting_list 9 | add constraint waiting_list_id_fkey 10 | foreign key (profile_id) 11 | references profiles (id) 12 | on delete cascade; 13 | ` 14 | 15 | // Replace handle waiting list function with additional profile_id entry 16 | await client` 17 | create or replace function public.handle_waiting_list_invited_at() 18 | returns trigger as $$ 19 | begin 20 | IF ((NEW.raw_user_meta_data->>'waiting_list_id')::uuid is null) THEN 21 | RETURN NULL; 22 | ELSE 23 | UPDATE public.waiting_list 24 | SET profile_id = new.id, 25 | invited_at = NOW(), 26 | updated_at = NOW() 27 | WHERE id = (NEW.raw_user_meta_data->>'waiting_list_id')::uuid; 28 | RETURN NEW; 29 | END IF; 30 | end; 31 | $$ language plpgsql security definer; 32 | ` 33 | }; 34 | 35 | exports.down = async client => { 36 | await client`alter table waiting_list drop column profile_id;` 37 | 38 | await client` 39 | create or replace function public.handle_waiting_list_invited_at() 40 | returns trigger as $$ 41 | begin 42 | IF ((NEW.raw_user_meta_data->>'waiting_list_id')::uuid is null) THEN 43 | RETURN NULL; 44 | ELSE 45 | UPDATE public.waiting_list 46 | SET invited_at = NOW(), 47 | updated_at = NOW() 48 | WHERE id = (NEW.raw_user_meta_data->>'waiting_list_id')::uuid; 49 | RETURN NEW; 50 | END IF; 51 | end; 52 | $$ language plpgsql security definer; 53 | ` 54 | }; 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "waiting-list", 3 | "version": "0.3.0", 4 | "scripts": { 5 | "dev": "vite dev", 6 | "build": "vite build", 7 | "preview": "vite preview", 8 | "start": "node build/index.js", 9 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 11 | "lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .", 12 | "format": "prettier --write --plugin-search-dir=. .", 13 | "m:new": "ley new", 14 | "m:up": "ley up", 15 | "m:down": "ley down", 16 | "m:status": "ley status" 17 | }, 18 | "devDependencies": { 19 | "@supabase/supabase-js": "^2.33.1", 20 | "@sveltejs/adapter-node": "^1.3.1", 21 | "@sveltejs/kit": "^1.24.0", 22 | "@types/cookie": "^0.5.1", 23 | "@typescript-eslint/eslint-plugin": "^6.5.0", 24 | "@typescript-eslint/parser": "^6.5.0", 25 | "dotenv": "^16.3.1", 26 | "eslint": "^8.48.0", 27 | "eslint-config-prettier": "^9.0.0", 28 | "eslint-plugin-svelte": "^2.33.0", 29 | "ley": "^0.8.1", 30 | "pg-connection-string": "^2.6.2", 31 | "postgres": "^3.3.5", 32 | "prettier": "~3.0.3", 33 | "prettier-plugin-svelte": "^3.0.3", 34 | "supabase": "1.88.0", 35 | "svelte": "^4.2.0", 36 | "svelte-check": "^3.5.1", 37 | "svelte-preprocess": "^5.0.4", 38 | "sveltekit-flash-message": "^2.2.0", 39 | "tslib": "^2.6.2", 40 | "typescript": "^5.2.2", 41 | "vite": "^4.4.9" 42 | }, 43 | "type": "module", 44 | "dependencies": { 45 | "@supabase/auth-helpers-sveltekit": "^0.10.2", 46 | "email-regex": "^5.0.0", 47 | "vest": "^4.6.11" 48 | } 49 | } -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | '@supabase/auth-helpers-sveltekit': 9 | specifier: ^0.10.2 10 | version: 0.10.2(@supabase/supabase-js@2.33.1)(@sveltejs/kit@1.24.0) 11 | email-regex: 12 | specifier: ^5.0.0 13 | version: 5.0.0 14 | vest: 15 | specifier: ^4.6.11 16 | version: 4.6.11 17 | 18 | devDependencies: 19 | '@supabase/supabase-js': 20 | specifier: ^2.33.1 21 | version: 2.33.1 22 | '@sveltejs/adapter-node': 23 | specifier: ^1.3.1 24 | version: 1.3.1(@sveltejs/kit@1.24.0) 25 | '@sveltejs/kit': 26 | specifier: ^1.24.0 27 | version: 1.24.0(svelte@4.2.0)(vite@4.4.9) 28 | '@types/cookie': 29 | specifier: ^0.5.1 30 | version: 0.5.1 31 | '@typescript-eslint/eslint-plugin': 32 | specifier: ^6.5.0 33 | version: 6.5.0(@typescript-eslint/parser@6.5.0)(eslint@8.48.0)(typescript@5.2.2) 34 | '@typescript-eslint/parser': 35 | specifier: ^6.5.0 36 | version: 6.5.0(eslint@8.48.0)(typescript@5.2.2) 37 | dotenv: 38 | specifier: ^16.3.1 39 | version: 16.3.1 40 | eslint: 41 | specifier: ^8.48.0 42 | version: 8.48.0 43 | eslint-config-prettier: 44 | specifier: ^9.0.0 45 | version: 9.0.0(eslint@8.48.0) 46 | eslint-plugin-svelte: 47 | specifier: ^2.33.0 48 | version: 2.33.0(eslint@8.48.0)(svelte@4.2.0) 49 | ley: 50 | specifier: ^0.8.1 51 | version: 0.8.1 52 | pg-connection-string: 53 | specifier: ^2.6.2 54 | version: 2.6.2 55 | postgres: 56 | specifier: ^3.3.5 57 | version: 3.3.5 58 | prettier: 59 | specifier: ~3.0.3 60 | version: 3.0.3 61 | prettier-plugin-svelte: 62 | specifier: ^3.0.3 63 | version: 3.0.3(prettier@3.0.3)(svelte@4.2.0) 64 | supabase: 65 | specifier: 1.88.0 66 | version: 1.88.0 67 | svelte: 68 | specifier: ^4.2.0 69 | version: 4.2.0 70 | svelte-check: 71 | specifier: ^3.5.1 72 | version: 3.5.1(postcss@8.4.29)(svelte@4.2.0) 73 | svelte-preprocess: 74 | specifier: ^5.0.4 75 | version: 5.0.4(postcss@8.4.29)(svelte@4.2.0)(typescript@5.2.2) 76 | sveltekit-flash-message: 77 | specifier: ^2.2.0 78 | version: 2.2.0(@sveltejs/kit@1.24.0)(svelte@4.2.0) 79 | tslib: 80 | specifier: ^2.6.2 81 | version: 2.6.2 82 | typescript: 83 | specifier: ^5.2.2 84 | version: 5.2.2 85 | vite: 86 | specifier: ^4.4.9 87 | version: 4.4.9 88 | 89 | packages: 90 | 91 | /@aashutoshrathi/word-wrap@1.2.6: 92 | resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} 93 | engines: {node: '>=0.10.0'} 94 | dev: true 95 | 96 | /@ampproject/remapping@2.2.1: 97 | resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} 98 | engines: {node: '>=6.0.0'} 99 | dependencies: 100 | '@jridgewell/gen-mapping': 0.3.3 101 | '@jridgewell/trace-mapping': 0.3.18 102 | 103 | /@esbuild/android-arm64@0.18.20: 104 | resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} 105 | engines: {node: '>=12'} 106 | cpu: [arm64] 107 | os: [android] 108 | requiresBuild: true 109 | optional: true 110 | 111 | /@esbuild/android-arm@0.18.20: 112 | resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} 113 | engines: {node: '>=12'} 114 | cpu: [arm] 115 | os: [android] 116 | requiresBuild: true 117 | optional: true 118 | 119 | /@esbuild/android-x64@0.18.20: 120 | resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} 121 | engines: {node: '>=12'} 122 | cpu: [x64] 123 | os: [android] 124 | requiresBuild: true 125 | optional: true 126 | 127 | /@esbuild/darwin-arm64@0.18.20: 128 | resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} 129 | engines: {node: '>=12'} 130 | cpu: [arm64] 131 | os: [darwin] 132 | requiresBuild: true 133 | optional: true 134 | 135 | /@esbuild/darwin-x64@0.18.20: 136 | resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} 137 | engines: {node: '>=12'} 138 | cpu: [x64] 139 | os: [darwin] 140 | requiresBuild: true 141 | optional: true 142 | 143 | /@esbuild/freebsd-arm64@0.18.20: 144 | resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} 145 | engines: {node: '>=12'} 146 | cpu: [arm64] 147 | os: [freebsd] 148 | requiresBuild: true 149 | optional: true 150 | 151 | /@esbuild/freebsd-x64@0.18.20: 152 | resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} 153 | engines: {node: '>=12'} 154 | cpu: [x64] 155 | os: [freebsd] 156 | requiresBuild: true 157 | optional: true 158 | 159 | /@esbuild/linux-arm64@0.18.20: 160 | resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} 161 | engines: {node: '>=12'} 162 | cpu: [arm64] 163 | os: [linux] 164 | requiresBuild: true 165 | optional: true 166 | 167 | /@esbuild/linux-arm@0.18.20: 168 | resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} 169 | engines: {node: '>=12'} 170 | cpu: [arm] 171 | os: [linux] 172 | requiresBuild: true 173 | optional: true 174 | 175 | /@esbuild/linux-ia32@0.18.20: 176 | resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} 177 | engines: {node: '>=12'} 178 | cpu: [ia32] 179 | os: [linux] 180 | requiresBuild: true 181 | optional: true 182 | 183 | /@esbuild/linux-loong64@0.18.20: 184 | resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} 185 | engines: {node: '>=12'} 186 | cpu: [loong64] 187 | os: [linux] 188 | requiresBuild: true 189 | optional: true 190 | 191 | /@esbuild/linux-mips64el@0.18.20: 192 | resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} 193 | engines: {node: '>=12'} 194 | cpu: [mips64el] 195 | os: [linux] 196 | requiresBuild: true 197 | optional: true 198 | 199 | /@esbuild/linux-ppc64@0.18.20: 200 | resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} 201 | engines: {node: '>=12'} 202 | cpu: [ppc64] 203 | os: [linux] 204 | requiresBuild: true 205 | optional: true 206 | 207 | /@esbuild/linux-riscv64@0.18.20: 208 | resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} 209 | engines: {node: '>=12'} 210 | cpu: [riscv64] 211 | os: [linux] 212 | requiresBuild: true 213 | optional: true 214 | 215 | /@esbuild/linux-s390x@0.18.20: 216 | resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} 217 | engines: {node: '>=12'} 218 | cpu: [s390x] 219 | os: [linux] 220 | requiresBuild: true 221 | optional: true 222 | 223 | /@esbuild/linux-x64@0.18.20: 224 | resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} 225 | engines: {node: '>=12'} 226 | cpu: [x64] 227 | os: [linux] 228 | requiresBuild: true 229 | optional: true 230 | 231 | /@esbuild/netbsd-x64@0.18.20: 232 | resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} 233 | engines: {node: '>=12'} 234 | cpu: [x64] 235 | os: [netbsd] 236 | requiresBuild: true 237 | optional: true 238 | 239 | /@esbuild/openbsd-x64@0.18.20: 240 | resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} 241 | engines: {node: '>=12'} 242 | cpu: [x64] 243 | os: [openbsd] 244 | requiresBuild: true 245 | optional: true 246 | 247 | /@esbuild/sunos-x64@0.18.20: 248 | resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} 249 | engines: {node: '>=12'} 250 | cpu: [x64] 251 | os: [sunos] 252 | requiresBuild: true 253 | optional: true 254 | 255 | /@esbuild/win32-arm64@0.18.20: 256 | resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} 257 | engines: {node: '>=12'} 258 | cpu: [arm64] 259 | os: [win32] 260 | requiresBuild: true 261 | optional: true 262 | 263 | /@esbuild/win32-ia32@0.18.20: 264 | resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} 265 | engines: {node: '>=12'} 266 | cpu: [ia32] 267 | os: [win32] 268 | requiresBuild: true 269 | optional: true 270 | 271 | /@esbuild/win32-x64@0.18.20: 272 | resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} 273 | engines: {node: '>=12'} 274 | cpu: [x64] 275 | os: [win32] 276 | requiresBuild: true 277 | optional: true 278 | 279 | /@eslint-community/eslint-utils@4.4.0(eslint@8.48.0): 280 | resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} 281 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 282 | peerDependencies: 283 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 284 | dependencies: 285 | eslint: 8.48.0 286 | eslint-visitor-keys: 3.4.3 287 | dev: true 288 | 289 | /@eslint-community/regexpp@4.8.0: 290 | resolution: {integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==} 291 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 292 | dev: true 293 | 294 | /@eslint/eslintrc@2.1.2: 295 | resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} 296 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 297 | dependencies: 298 | ajv: 6.12.6 299 | debug: 4.3.4 300 | espree: 9.6.1 301 | globals: 13.21.0 302 | ignore: 5.2.4 303 | import-fresh: 3.3.0 304 | js-yaml: 4.1.0 305 | minimatch: 3.1.2 306 | strip-json-comments: 3.1.1 307 | transitivePeerDependencies: 308 | - supports-color 309 | dev: true 310 | 311 | /@eslint/js@8.48.0: 312 | resolution: {integrity: sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==} 313 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 314 | dev: true 315 | 316 | /@humanwhocodes/config-array@0.11.11: 317 | resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} 318 | engines: {node: '>=10.10.0'} 319 | dependencies: 320 | '@humanwhocodes/object-schema': 1.2.1 321 | debug: 4.3.4 322 | minimatch: 3.1.2 323 | transitivePeerDependencies: 324 | - supports-color 325 | dev: true 326 | 327 | /@humanwhocodes/module-importer@1.0.1: 328 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 329 | engines: {node: '>=12.22'} 330 | dev: true 331 | 332 | /@humanwhocodes/object-schema@1.2.1: 333 | resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} 334 | dev: true 335 | 336 | /@jridgewell/gen-mapping@0.3.3: 337 | resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} 338 | engines: {node: '>=6.0.0'} 339 | dependencies: 340 | '@jridgewell/set-array': 1.1.2 341 | '@jridgewell/sourcemap-codec': 1.4.15 342 | '@jridgewell/trace-mapping': 0.3.18 343 | 344 | /@jridgewell/resolve-uri@3.1.0: 345 | resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} 346 | engines: {node: '>=6.0.0'} 347 | 348 | /@jridgewell/set-array@1.1.2: 349 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} 350 | engines: {node: '>=6.0.0'} 351 | 352 | /@jridgewell/sourcemap-codec@1.4.14: 353 | resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} 354 | 355 | /@jridgewell/sourcemap-codec@1.4.15: 356 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 357 | 358 | /@jridgewell/trace-mapping@0.3.18: 359 | resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} 360 | dependencies: 361 | '@jridgewell/resolve-uri': 3.1.0 362 | '@jridgewell/sourcemap-codec': 1.4.14 363 | 364 | /@nodelib/fs.scandir@2.1.5: 365 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 366 | engines: {node: '>= 8'} 367 | dependencies: 368 | '@nodelib/fs.stat': 2.0.5 369 | run-parallel: 1.2.0 370 | dev: true 371 | 372 | /@nodelib/fs.stat@2.0.5: 373 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 374 | engines: {node: '>= 8'} 375 | dev: true 376 | 377 | /@nodelib/fs.walk@1.2.8: 378 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 379 | engines: {node: '>= 8'} 380 | dependencies: 381 | '@nodelib/fs.scandir': 2.1.5 382 | fastq: 1.15.0 383 | dev: true 384 | 385 | /@polka/url@1.0.0-next.21: 386 | resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} 387 | 388 | /@rollup/plugin-commonjs@25.0.3(rollup@3.26.1): 389 | resolution: {integrity: sha512-uBdtWr/H3BVcgm97MUdq2oJmqBR23ny1hOrWe2PKo9FTbjsGqg32jfasJUKYAI5ouqacjRnj65mBB/S79F+GQA==} 390 | engines: {node: '>=14.0.0'} 391 | peerDependencies: 392 | rollup: ^2.68.0||^3.0.0 393 | peerDependenciesMeta: 394 | rollup: 395 | optional: true 396 | dependencies: 397 | '@rollup/pluginutils': 5.0.2(rollup@3.26.1) 398 | commondir: 1.0.1 399 | estree-walker: 2.0.2 400 | glob: 8.1.0 401 | is-reference: 1.2.1 402 | magic-string: 0.27.0 403 | rollup: 3.26.1 404 | dev: true 405 | 406 | /@rollup/plugin-json@6.0.0(rollup@3.26.1): 407 | resolution: {integrity: sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==} 408 | engines: {node: '>=14.0.0'} 409 | peerDependencies: 410 | rollup: ^1.20.0||^2.0.0||^3.0.0 411 | peerDependenciesMeta: 412 | rollup: 413 | optional: true 414 | dependencies: 415 | '@rollup/pluginutils': 5.0.2(rollup@3.26.1) 416 | rollup: 3.26.1 417 | dev: true 418 | 419 | /@rollup/plugin-node-resolve@15.1.0(rollup@3.26.1): 420 | resolution: {integrity: sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==} 421 | engines: {node: '>=14.0.0'} 422 | peerDependencies: 423 | rollup: ^2.78.0||^3.0.0 424 | peerDependenciesMeta: 425 | rollup: 426 | optional: true 427 | dependencies: 428 | '@rollup/pluginutils': 5.0.2(rollup@3.26.1) 429 | '@types/resolve': 1.20.2 430 | deepmerge: 4.3.1 431 | is-builtin-module: 3.2.1 432 | is-module: 1.0.0 433 | resolve: 1.22.2 434 | rollup: 3.26.1 435 | dev: true 436 | 437 | /@rollup/pluginutils@5.0.2(rollup@3.26.1): 438 | resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} 439 | engines: {node: '>=14.0.0'} 440 | peerDependencies: 441 | rollup: ^1.20.0||^2.0.0||^3.0.0 442 | peerDependenciesMeta: 443 | rollup: 444 | optional: true 445 | dependencies: 446 | '@types/estree': 1.0.1 447 | estree-walker: 2.0.2 448 | picomatch: 2.3.1 449 | rollup: 3.26.1 450 | dev: true 451 | 452 | /@supabase/auth-helpers-shared@0.4.1(@supabase/supabase-js@2.33.1): 453 | resolution: {integrity: sha512-IEDX9JzWkIjQiLUaP4Qy5YDiG0jFQatWfS+jw8cCQs6QfbNdEPd2Y3qonwGHnM90CZom9SvjuylBv2pFVAL7Lw==} 454 | peerDependencies: 455 | '@supabase/supabase-js': ^2.19.0 456 | dependencies: 457 | '@supabase/supabase-js': 2.33.1 458 | jose: 4.14.4 459 | dev: false 460 | 461 | /@supabase/auth-helpers-sveltekit@0.10.2(@supabase/supabase-js@2.33.1)(@sveltejs/kit@1.24.0): 462 | resolution: {integrity: sha512-azQqh4ofgB+ewHBGQPp77R9552jD0DXZMd0QQQQvsgLUdGVghRrydW11491473DvcONoy2KMWUShVxccjzo6Gw==} 463 | peerDependencies: 464 | '@supabase/supabase-js': ^2.19.0 465 | '@sveltejs/kit': ^1.15.4 466 | dependencies: 467 | '@supabase/auth-helpers-shared': 0.4.1(@supabase/supabase-js@2.33.1) 468 | '@supabase/supabase-js': 2.33.1 469 | '@sveltejs/kit': 1.24.0(svelte@4.2.0)(vite@4.4.9) 470 | dev: false 471 | 472 | /@supabase/functions-js@2.1.2: 473 | resolution: {integrity: sha512-QCR6pwJs9exCl37bmpMisUd6mf+0SUBJ6mUpiAjEkSJ/+xW8TCuO14bvkWHADd5hElJK9MxNlMQXxSA4DRz9nQ==} 474 | dependencies: 475 | cross-fetch: 3.1.8 476 | transitivePeerDependencies: 477 | - encoding 478 | 479 | /@supabase/gotrue-js@2.46.2: 480 | resolution: {integrity: sha512-tLyZZNEb3St6Dxe671seLCzYWZ2DftSWWjPEfqAwW6kNOAr+Aw2uEIW0H3gEJxSIST+E+ly9lUBm/rGlfDWKPA==} 481 | dependencies: 482 | cross-fetch: 3.1.8 483 | transitivePeerDependencies: 484 | - encoding 485 | 486 | /@supabase/postgrest-js@1.8.0: 487 | resolution: {integrity: sha512-R6leDIC92NgjyG2/tCRJ42rWN7+fZY6ulTEE+c00tcnghn6cX4IYUlnTNMtrdfYC2JYNOTyM+rWj63Wdhr7Zig==} 488 | dependencies: 489 | cross-fetch: 3.1.8 490 | transitivePeerDependencies: 491 | - encoding 492 | 493 | /@supabase/realtime-js@2.7.4: 494 | resolution: {integrity: sha512-FzSzs1k9ruh/uds5AJ95Nc3beiMCCIhougExJ3O98CX1LMLAKUKFy5FivKLvcNhXnNfUEL0XUfGMb4UH2J7alg==} 495 | dependencies: 496 | '@types/phoenix': 1.6.0 497 | '@types/websocket': 1.0.5 498 | websocket: 1.0.34 499 | transitivePeerDependencies: 500 | - supports-color 501 | 502 | /@supabase/storage-js@2.5.1: 503 | resolution: {integrity: sha512-nkR0fQA9ScAtIKA3vNoPEqbZv1k5B5HVRYEvRWdlP6mUpFphM9TwPL2jZ/ztNGMTG5xT6SrHr+H7Ykz8qzbhjw==} 504 | dependencies: 505 | cross-fetch: 3.1.8 506 | transitivePeerDependencies: 507 | - encoding 508 | 509 | /@supabase/supabase-js@2.33.1: 510 | resolution: {integrity: sha512-jA00rquPTppPOHpBB6KABW98lfg0gYXcuGqP3TB1iiduznRVsi3GGk2qBKXPDLMYSe0kRlQp5xCwWWthaJr8eA==} 511 | dependencies: 512 | '@supabase/functions-js': 2.1.2 513 | '@supabase/gotrue-js': 2.46.2 514 | '@supabase/postgrest-js': 1.8.0 515 | '@supabase/realtime-js': 2.7.4 516 | '@supabase/storage-js': 2.5.1 517 | cross-fetch: 3.1.8 518 | transitivePeerDependencies: 519 | - encoding 520 | - supports-color 521 | 522 | /@sveltejs/adapter-node@1.3.1(@sveltejs/kit@1.24.0): 523 | resolution: {integrity: sha512-A0VgRQDCDPzdLNoiAbcOxGw4zT1Mc+n1LwT1OmO350R7WxrEqdMUChPPOd1iMfIDWlP4ie6E2d/WQf5es2d4Zw==} 524 | peerDependencies: 525 | '@sveltejs/kit': ^1.0.0 526 | dependencies: 527 | '@rollup/plugin-commonjs': 25.0.3(rollup@3.26.1) 528 | '@rollup/plugin-json': 6.0.0(rollup@3.26.1) 529 | '@rollup/plugin-node-resolve': 15.1.0(rollup@3.26.1) 530 | '@sveltejs/kit': 1.24.0(svelte@4.2.0)(vite@4.4.9) 531 | rollup: 3.26.1 532 | dev: true 533 | 534 | /@sveltejs/kit@1.24.0(svelte@4.2.0)(vite@4.4.9): 535 | resolution: {integrity: sha512-r7Gj0/VcdAIRL1yE1cJ5rurWJ5drrR7BzRv+P+NAathtvnMCi0u4FhezO7T4bj7DJdQ3TNsax3yQcrVWxh60fg==} 536 | engines: {node: ^16.14 || >=18} 537 | hasBin: true 538 | requiresBuild: true 539 | peerDependencies: 540 | svelte: ^3.54.0 || ^4.0.0-next.0 541 | vite: ^4.0.0 542 | dependencies: 543 | '@sveltejs/vite-plugin-svelte': 2.4.2(svelte@4.2.0)(vite@4.4.9) 544 | '@types/cookie': 0.5.1 545 | cookie: 0.5.0 546 | devalue: 4.3.2 547 | esm-env: 1.0.0 548 | kleur: 4.1.5 549 | magic-string: 0.30.1 550 | mime: 3.0.0 551 | sade: 1.8.1 552 | set-cookie-parser: 2.6.0 553 | sirv: 2.0.3 554 | svelte: 4.2.0 555 | tiny-glob: 0.2.9 556 | undici: 5.23.0 557 | vite: 4.4.9 558 | transitivePeerDependencies: 559 | - supports-color 560 | 561 | /@sveltejs/vite-plugin-svelte-inspector@1.0.3(@sveltejs/vite-plugin-svelte@2.4.2)(svelte@4.2.0)(vite@4.4.9): 562 | resolution: {integrity: sha512-Khdl5jmmPN6SUsVuqSXatKpQTMIifoQPDanaxC84m9JxIibWvSABJyHpyys0Z+1yYrxY5TTEQm+6elh0XCMaOA==} 563 | engines: {node: ^14.18.0 || >= 16} 564 | peerDependencies: 565 | '@sveltejs/vite-plugin-svelte': ^2.2.0 566 | svelte: ^3.54.0 || ^4.0.0 567 | vite: ^4.0.0 568 | dependencies: 569 | '@sveltejs/vite-plugin-svelte': 2.4.2(svelte@4.2.0)(vite@4.4.9) 570 | debug: 4.3.4 571 | svelte: 4.2.0 572 | vite: 4.4.9 573 | transitivePeerDependencies: 574 | - supports-color 575 | 576 | /@sveltejs/vite-plugin-svelte@2.4.2(svelte@4.2.0)(vite@4.4.9): 577 | resolution: {integrity: sha512-ePfcC48ftMKhkT0OFGdOyycYKnnkT6i/buzey+vHRTR/JpQvuPzzhf1PtKqCDQfJRgoPSN2vscXs6gLigx/zGw==} 578 | engines: {node: ^14.18.0 || >= 16} 579 | peerDependencies: 580 | svelte: ^3.54.0 || ^4.0.0 581 | vite: ^4.0.0 582 | dependencies: 583 | '@sveltejs/vite-plugin-svelte-inspector': 1.0.3(@sveltejs/vite-plugin-svelte@2.4.2)(svelte@4.2.0)(vite@4.4.9) 584 | debug: 4.3.4 585 | deepmerge: 4.3.1 586 | kleur: 4.1.5 587 | magic-string: 0.30.1 588 | svelte: 4.2.0 589 | svelte-hmr: 0.15.2(svelte@4.2.0) 590 | vite: 4.4.9 591 | vitefu: 0.2.4(vite@4.4.9) 592 | transitivePeerDependencies: 593 | - supports-color 594 | 595 | /@types/cookie@0.5.1: 596 | resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==} 597 | 598 | /@types/estree@1.0.1: 599 | resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} 600 | 601 | /@types/json-schema@7.0.12: 602 | resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} 603 | dev: true 604 | 605 | /@types/node@20.3.3: 606 | resolution: {integrity: sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==} 607 | 608 | /@types/phoenix@1.6.0: 609 | resolution: {integrity: sha512-qwfpsHmFuhAS/dVd4uBIraMxRd56vwBUYQGZ6GpXnFuM2XMRFJbIyruFKKlW2daQliuYZwe0qfn/UjFCDKic5g==} 610 | 611 | /@types/pug@2.0.6: 612 | resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==} 613 | dev: true 614 | 615 | /@types/resolve@1.20.2: 616 | resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} 617 | dev: true 618 | 619 | /@types/semver@7.5.1: 620 | resolution: {integrity: sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==} 621 | dev: true 622 | 623 | /@types/websocket@1.0.5: 624 | resolution: {integrity: sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==} 625 | dependencies: 626 | '@types/node': 20.3.3 627 | 628 | /@typescript-eslint/eslint-plugin@6.5.0(@typescript-eslint/parser@6.5.0)(eslint@8.48.0)(typescript@5.2.2): 629 | resolution: {integrity: sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw==} 630 | engines: {node: ^16.0.0 || >=18.0.0} 631 | peerDependencies: 632 | '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha 633 | eslint: ^7.0.0 || ^8.0.0 634 | typescript: '*' 635 | peerDependenciesMeta: 636 | typescript: 637 | optional: true 638 | dependencies: 639 | '@eslint-community/regexpp': 4.8.0 640 | '@typescript-eslint/parser': 6.5.0(eslint@8.48.0)(typescript@5.2.2) 641 | '@typescript-eslint/scope-manager': 6.5.0 642 | '@typescript-eslint/type-utils': 6.5.0(eslint@8.48.0)(typescript@5.2.2) 643 | '@typescript-eslint/utils': 6.5.0(eslint@8.48.0)(typescript@5.2.2) 644 | '@typescript-eslint/visitor-keys': 6.5.0 645 | debug: 4.3.4 646 | eslint: 8.48.0 647 | graphemer: 1.4.0 648 | ignore: 5.2.4 649 | natural-compare: 1.4.0 650 | semver: 7.5.4 651 | ts-api-utils: 1.0.2(typescript@5.2.2) 652 | typescript: 5.2.2 653 | transitivePeerDependencies: 654 | - supports-color 655 | dev: true 656 | 657 | /@typescript-eslint/parser@6.5.0(eslint@8.48.0)(typescript@5.2.2): 658 | resolution: {integrity: sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ==} 659 | engines: {node: ^16.0.0 || >=18.0.0} 660 | peerDependencies: 661 | eslint: ^7.0.0 || ^8.0.0 662 | typescript: '*' 663 | peerDependenciesMeta: 664 | typescript: 665 | optional: true 666 | dependencies: 667 | '@typescript-eslint/scope-manager': 6.5.0 668 | '@typescript-eslint/types': 6.5.0 669 | '@typescript-eslint/typescript-estree': 6.5.0(typescript@5.2.2) 670 | '@typescript-eslint/visitor-keys': 6.5.0 671 | debug: 4.3.4 672 | eslint: 8.48.0 673 | typescript: 5.2.2 674 | transitivePeerDependencies: 675 | - supports-color 676 | dev: true 677 | 678 | /@typescript-eslint/scope-manager@6.5.0: 679 | resolution: {integrity: sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw==} 680 | engines: {node: ^16.0.0 || >=18.0.0} 681 | dependencies: 682 | '@typescript-eslint/types': 6.5.0 683 | '@typescript-eslint/visitor-keys': 6.5.0 684 | dev: true 685 | 686 | /@typescript-eslint/type-utils@6.5.0(eslint@8.48.0)(typescript@5.2.2): 687 | resolution: {integrity: sha512-f7OcZOkRivtujIBQ4yrJNIuwyCQO1OjocVqntl9dgSIZAdKqicj3xFDqDOzHDlGCZX990LqhLQXWRnQvsapq8A==} 688 | engines: {node: ^16.0.0 || >=18.0.0} 689 | peerDependencies: 690 | eslint: ^7.0.0 || ^8.0.0 691 | typescript: '*' 692 | peerDependenciesMeta: 693 | typescript: 694 | optional: true 695 | dependencies: 696 | '@typescript-eslint/typescript-estree': 6.5.0(typescript@5.2.2) 697 | '@typescript-eslint/utils': 6.5.0(eslint@8.48.0)(typescript@5.2.2) 698 | debug: 4.3.4 699 | eslint: 8.48.0 700 | ts-api-utils: 1.0.2(typescript@5.2.2) 701 | typescript: 5.2.2 702 | transitivePeerDependencies: 703 | - supports-color 704 | dev: true 705 | 706 | /@typescript-eslint/types@6.5.0: 707 | resolution: {integrity: sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==} 708 | engines: {node: ^16.0.0 || >=18.0.0} 709 | dev: true 710 | 711 | /@typescript-eslint/typescript-estree@6.5.0(typescript@5.2.2): 712 | resolution: {integrity: sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==} 713 | engines: {node: ^16.0.0 || >=18.0.0} 714 | peerDependencies: 715 | typescript: '*' 716 | peerDependenciesMeta: 717 | typescript: 718 | optional: true 719 | dependencies: 720 | '@typescript-eslint/types': 6.5.0 721 | '@typescript-eslint/visitor-keys': 6.5.0 722 | debug: 4.3.4 723 | globby: 11.1.0 724 | is-glob: 4.0.3 725 | semver: 7.5.4 726 | ts-api-utils: 1.0.2(typescript@5.2.2) 727 | typescript: 5.2.2 728 | transitivePeerDependencies: 729 | - supports-color 730 | dev: true 731 | 732 | /@typescript-eslint/utils@6.5.0(eslint@8.48.0)(typescript@5.2.2): 733 | resolution: {integrity: sha512-9nqtjkNykFzeVtt9Pj6lyR9WEdd8npPhhIPM992FWVkZuS6tmxHfGVnlUcjpUP2hv8r4w35nT33mlxd+Be1ACQ==} 734 | engines: {node: ^16.0.0 || >=18.0.0} 735 | peerDependencies: 736 | eslint: ^7.0.0 || ^8.0.0 737 | dependencies: 738 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) 739 | '@types/json-schema': 7.0.12 740 | '@types/semver': 7.5.1 741 | '@typescript-eslint/scope-manager': 6.5.0 742 | '@typescript-eslint/types': 6.5.0 743 | '@typescript-eslint/typescript-estree': 6.5.0(typescript@5.2.2) 744 | eslint: 8.48.0 745 | semver: 7.5.4 746 | transitivePeerDependencies: 747 | - supports-color 748 | - typescript 749 | dev: true 750 | 751 | /@typescript-eslint/visitor-keys@6.5.0: 752 | resolution: {integrity: sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==} 753 | engines: {node: ^16.0.0 || >=18.0.0} 754 | dependencies: 755 | '@typescript-eslint/types': 6.5.0 756 | eslint-visitor-keys: 3.4.3 757 | dev: true 758 | 759 | /acorn-jsx@5.3.2(acorn@8.10.0): 760 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 761 | peerDependencies: 762 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 763 | dependencies: 764 | acorn: 8.10.0 765 | dev: true 766 | 767 | /acorn@8.10.0: 768 | resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} 769 | engines: {node: '>=0.4.0'} 770 | hasBin: true 771 | 772 | /ajv@6.12.6: 773 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 774 | dependencies: 775 | fast-deep-equal: 3.1.3 776 | fast-json-stable-stringify: 2.1.0 777 | json-schema-traverse: 0.4.1 778 | uri-js: 4.4.1 779 | dev: true 780 | 781 | /ansi-regex@5.0.1: 782 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 783 | engines: {node: '>=8'} 784 | dev: true 785 | 786 | /ansi-styles@4.3.0: 787 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 788 | engines: {node: '>=8'} 789 | dependencies: 790 | color-convert: 2.0.1 791 | dev: true 792 | 793 | /anymatch@3.1.3: 794 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 795 | engines: {node: '>= 8'} 796 | dependencies: 797 | normalize-path: 3.0.0 798 | picomatch: 2.3.1 799 | dev: true 800 | 801 | /argparse@2.0.1: 802 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 803 | dev: true 804 | 805 | /aria-query@5.3.0: 806 | resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} 807 | dependencies: 808 | dequal: 2.0.3 809 | 810 | /array-union@2.1.0: 811 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 812 | engines: {node: '>=8'} 813 | dev: true 814 | 815 | /axobject-query@3.2.1: 816 | resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} 817 | dependencies: 818 | dequal: 2.0.3 819 | 820 | /balanced-match@1.0.2: 821 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 822 | dev: true 823 | 824 | /bin-links@4.0.2: 825 | resolution: {integrity: sha512-jxJ0PbXR8eQyPlExCvCs3JFnikvs1Yp4gUJt6nmgathdOwvur+q22KWC3h20gvWl4T/14DXKj2IlkJwwZkZPOw==} 826 | engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} 827 | dependencies: 828 | cmd-shim: 6.0.1 829 | npm-normalize-package-bin: 3.0.1 830 | read-cmd-shim: 4.0.0 831 | write-file-atomic: 5.0.1 832 | dev: true 833 | 834 | /binary-extensions@2.2.0: 835 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 836 | engines: {node: '>=8'} 837 | dev: true 838 | 839 | /brace-expansion@1.1.11: 840 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 841 | dependencies: 842 | balanced-match: 1.0.2 843 | concat-map: 0.0.1 844 | dev: true 845 | 846 | /brace-expansion@2.0.1: 847 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 848 | dependencies: 849 | balanced-match: 1.0.2 850 | dev: true 851 | 852 | /braces@3.0.2: 853 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 854 | engines: {node: '>=8'} 855 | dependencies: 856 | fill-range: 7.0.1 857 | dev: true 858 | 859 | /buffer-crc32@0.2.13: 860 | resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} 861 | dev: true 862 | 863 | /bufferutil@4.0.7: 864 | resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==} 865 | engines: {node: '>=6.14.2'} 866 | requiresBuild: true 867 | dependencies: 868 | node-gyp-build: 4.6.0 869 | 870 | /builtin-modules@3.3.0: 871 | resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} 872 | engines: {node: '>=6'} 873 | dev: true 874 | 875 | /busboy@1.6.0: 876 | resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} 877 | engines: {node: '>=10.16.0'} 878 | dependencies: 879 | streamsearch: 1.1.0 880 | 881 | /callsites@3.1.0: 882 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 883 | engines: {node: '>=6'} 884 | dev: true 885 | 886 | /chalk@4.1.2: 887 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 888 | engines: {node: '>=10'} 889 | dependencies: 890 | ansi-styles: 4.3.0 891 | supports-color: 7.2.0 892 | dev: true 893 | 894 | /chokidar@3.5.3: 895 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} 896 | engines: {node: '>= 8.10.0'} 897 | dependencies: 898 | anymatch: 3.1.3 899 | braces: 3.0.2 900 | glob-parent: 5.1.2 901 | is-binary-path: 2.1.0 902 | is-glob: 4.0.3 903 | normalize-path: 3.0.0 904 | readdirp: 3.6.0 905 | optionalDependencies: 906 | fsevents: 2.3.3 907 | dev: true 908 | 909 | /chownr@2.0.0: 910 | resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} 911 | engines: {node: '>=10'} 912 | dev: true 913 | 914 | /cmd-shim@6.0.1: 915 | resolution: {integrity: sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q==} 916 | engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} 917 | dev: true 918 | 919 | /code-red@1.0.3: 920 | resolution: {integrity: sha512-kVwJELqiILQyG5aeuyKFbdsI1fmQy1Cmf7dQ8eGmVuJoaRVdwey7WaMknr2ZFeVSYSKT0rExsa8EGw0aoI/1QQ==} 921 | dependencies: 922 | '@jridgewell/sourcemap-codec': 1.4.15 923 | '@types/estree': 1.0.1 924 | acorn: 8.10.0 925 | estree-walker: 3.0.3 926 | periscopic: 3.1.0 927 | 928 | /color-convert@2.0.1: 929 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 930 | engines: {node: '>=7.0.0'} 931 | dependencies: 932 | color-name: 1.1.4 933 | dev: true 934 | 935 | /color-name@1.1.4: 936 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 937 | dev: true 938 | 939 | /commondir@1.0.1: 940 | resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} 941 | dev: true 942 | 943 | /concat-map@0.0.1: 944 | resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} 945 | dev: true 946 | 947 | /context@3.0.7: 948 | resolution: {integrity: sha512-ceW8mQwFhOin5ih5Sm6jq9mju7+p/usZFkf+PwNPXcpARplz1eAE4PB0V90Os/STyd1387Gu4C8I5Jmy3wDoIA==} 949 | dependencies: 950 | vest-utils: 0.1.1 951 | dev: false 952 | 953 | /cookie@0.5.0: 954 | resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} 955 | engines: {node: '>= 0.6'} 956 | 957 | /cross-fetch@3.1.8: 958 | resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} 959 | dependencies: 960 | node-fetch: 2.6.12 961 | transitivePeerDependencies: 962 | - encoding 963 | 964 | /cross-spawn@7.0.3: 965 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 966 | engines: {node: '>= 8'} 967 | dependencies: 968 | path-key: 3.1.1 969 | shebang-command: 2.0.0 970 | which: 2.0.2 971 | dev: true 972 | 973 | /css-tree@2.3.1: 974 | resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} 975 | engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} 976 | dependencies: 977 | mdn-data: 2.0.30 978 | source-map-js: 1.0.2 979 | 980 | /cssesc@3.0.0: 981 | resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 982 | engines: {node: '>=4'} 983 | hasBin: true 984 | dev: true 985 | 986 | /d@1.0.1: 987 | resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==} 988 | dependencies: 989 | es5-ext: 0.10.62 990 | type: 1.2.0 991 | 992 | /data-uri-to-buffer@4.0.1: 993 | resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} 994 | engines: {node: '>= 12'} 995 | dev: true 996 | 997 | /debug@2.6.9: 998 | resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} 999 | peerDependencies: 1000 | supports-color: '*' 1001 | peerDependenciesMeta: 1002 | supports-color: 1003 | optional: true 1004 | dependencies: 1005 | ms: 2.0.0 1006 | 1007 | /debug@4.3.4: 1008 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 1009 | engines: {node: '>=6.0'} 1010 | peerDependencies: 1011 | supports-color: '*' 1012 | peerDependenciesMeta: 1013 | supports-color: 1014 | optional: true 1015 | dependencies: 1016 | ms: 2.1.2 1017 | 1018 | /deep-is@0.1.4: 1019 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 1020 | dev: true 1021 | 1022 | /deepmerge@4.3.1: 1023 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 1024 | engines: {node: '>=0.10.0'} 1025 | 1026 | /dequal@2.0.3: 1027 | resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} 1028 | engines: {node: '>=6'} 1029 | 1030 | /detect-indent@6.1.0: 1031 | resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} 1032 | engines: {node: '>=8'} 1033 | dev: true 1034 | 1035 | /devalue@4.3.2: 1036 | resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==} 1037 | 1038 | /dir-glob@3.0.1: 1039 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 1040 | engines: {node: '>=8'} 1041 | dependencies: 1042 | path-type: 4.0.0 1043 | dev: true 1044 | 1045 | /doctrine@3.0.0: 1046 | resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} 1047 | engines: {node: '>=6.0.0'} 1048 | dependencies: 1049 | esutils: 2.0.3 1050 | dev: true 1051 | 1052 | /dotenv@16.3.1: 1053 | resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} 1054 | engines: {node: '>=12'} 1055 | dev: true 1056 | 1057 | /email-regex@5.0.0: 1058 | resolution: {integrity: sha512-he76Cm8JFxb6OGQHabLBPdsiStgPmJeAEhctmw0uhonUh1pCBsHpI6/rB62s2GNzjBb0YlhIcF/1l9Lp5AfH0Q==} 1059 | engines: {node: '>=12'} 1060 | dev: false 1061 | 1062 | /es5-ext@0.10.62: 1063 | resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==} 1064 | engines: {node: '>=0.10'} 1065 | requiresBuild: true 1066 | dependencies: 1067 | es6-iterator: 2.0.3 1068 | es6-symbol: 3.1.3 1069 | next-tick: 1.1.0 1070 | 1071 | /es6-iterator@2.0.3: 1072 | resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} 1073 | dependencies: 1074 | d: 1.0.1 1075 | es5-ext: 0.10.62 1076 | es6-symbol: 3.1.3 1077 | 1078 | /es6-promise@3.3.1: 1079 | resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} 1080 | dev: true 1081 | 1082 | /es6-symbol@3.1.3: 1083 | resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==} 1084 | dependencies: 1085 | d: 1.0.1 1086 | ext: 1.7.0 1087 | 1088 | /esbuild@0.18.20: 1089 | resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} 1090 | engines: {node: '>=12'} 1091 | hasBin: true 1092 | requiresBuild: true 1093 | optionalDependencies: 1094 | '@esbuild/android-arm': 0.18.20 1095 | '@esbuild/android-arm64': 0.18.20 1096 | '@esbuild/android-x64': 0.18.20 1097 | '@esbuild/darwin-arm64': 0.18.20 1098 | '@esbuild/darwin-x64': 0.18.20 1099 | '@esbuild/freebsd-arm64': 0.18.20 1100 | '@esbuild/freebsd-x64': 0.18.20 1101 | '@esbuild/linux-arm': 0.18.20 1102 | '@esbuild/linux-arm64': 0.18.20 1103 | '@esbuild/linux-ia32': 0.18.20 1104 | '@esbuild/linux-loong64': 0.18.20 1105 | '@esbuild/linux-mips64el': 0.18.20 1106 | '@esbuild/linux-ppc64': 0.18.20 1107 | '@esbuild/linux-riscv64': 0.18.20 1108 | '@esbuild/linux-s390x': 0.18.20 1109 | '@esbuild/linux-x64': 0.18.20 1110 | '@esbuild/netbsd-x64': 0.18.20 1111 | '@esbuild/openbsd-x64': 0.18.20 1112 | '@esbuild/sunos-x64': 0.18.20 1113 | '@esbuild/win32-arm64': 0.18.20 1114 | '@esbuild/win32-ia32': 0.18.20 1115 | '@esbuild/win32-x64': 0.18.20 1116 | 1117 | /escape-string-regexp@4.0.0: 1118 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 1119 | engines: {node: '>=10'} 1120 | dev: true 1121 | 1122 | /eslint-config-prettier@9.0.0(eslint@8.48.0): 1123 | resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} 1124 | hasBin: true 1125 | peerDependencies: 1126 | eslint: '>=7.0.0' 1127 | dependencies: 1128 | eslint: 8.48.0 1129 | dev: true 1130 | 1131 | /eslint-plugin-svelte@2.33.0(eslint@8.48.0)(svelte@4.2.0): 1132 | resolution: {integrity: sha512-kk7Z4BfxVjFYJseFcOpS8kiKNio7KnAnhFagmM89h1wNSKlM7tIn+uguNQppKM9leYW+S+Us0Rjg2Qg3zsEcvg==} 1133 | engines: {node: ^14.17.0 || >=16.0.0} 1134 | peerDependencies: 1135 | eslint: ^7.0.0 || ^8.0.0-0 1136 | svelte: ^3.37.0 || ^4.0.0 1137 | peerDependenciesMeta: 1138 | svelte: 1139 | optional: true 1140 | dependencies: 1141 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) 1142 | '@jridgewell/sourcemap-codec': 1.4.15 1143 | debug: 4.3.4 1144 | eslint: 8.48.0 1145 | esutils: 2.0.3 1146 | known-css-properties: 0.28.0 1147 | postcss: 8.4.29 1148 | postcss-load-config: 3.1.4(postcss@8.4.29) 1149 | postcss-safe-parser: 6.0.0(postcss@8.4.29) 1150 | postcss-selector-parser: 6.0.13 1151 | semver: 7.5.4 1152 | svelte: 4.2.0 1153 | svelte-eslint-parser: 0.33.0(svelte@4.2.0) 1154 | transitivePeerDependencies: 1155 | - supports-color 1156 | - ts-node 1157 | dev: true 1158 | 1159 | /eslint-scope@7.2.2: 1160 | resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} 1161 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1162 | dependencies: 1163 | esrecurse: 4.3.0 1164 | estraverse: 5.3.0 1165 | dev: true 1166 | 1167 | /eslint-visitor-keys@3.4.3: 1168 | resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} 1169 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1170 | dev: true 1171 | 1172 | /eslint@8.48.0: 1173 | resolution: {integrity: sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==} 1174 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1175 | hasBin: true 1176 | dependencies: 1177 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0) 1178 | '@eslint-community/regexpp': 4.8.0 1179 | '@eslint/eslintrc': 2.1.2 1180 | '@eslint/js': 8.48.0 1181 | '@humanwhocodes/config-array': 0.11.11 1182 | '@humanwhocodes/module-importer': 1.0.1 1183 | '@nodelib/fs.walk': 1.2.8 1184 | ajv: 6.12.6 1185 | chalk: 4.1.2 1186 | cross-spawn: 7.0.3 1187 | debug: 4.3.4 1188 | doctrine: 3.0.0 1189 | escape-string-regexp: 4.0.0 1190 | eslint-scope: 7.2.2 1191 | eslint-visitor-keys: 3.4.3 1192 | espree: 9.6.1 1193 | esquery: 1.5.0 1194 | esutils: 2.0.3 1195 | fast-deep-equal: 3.1.3 1196 | file-entry-cache: 6.0.1 1197 | find-up: 5.0.0 1198 | glob-parent: 6.0.2 1199 | globals: 13.21.0 1200 | graphemer: 1.4.0 1201 | ignore: 5.2.4 1202 | imurmurhash: 0.1.4 1203 | is-glob: 4.0.3 1204 | is-path-inside: 3.0.3 1205 | js-yaml: 4.1.0 1206 | json-stable-stringify-without-jsonify: 1.0.1 1207 | levn: 0.4.1 1208 | lodash.merge: 4.6.2 1209 | minimatch: 3.1.2 1210 | natural-compare: 1.4.0 1211 | optionator: 0.9.3 1212 | strip-ansi: 6.0.1 1213 | text-table: 0.2.0 1214 | transitivePeerDependencies: 1215 | - supports-color 1216 | dev: true 1217 | 1218 | /esm-env@1.0.0: 1219 | resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} 1220 | 1221 | /espree@9.6.1: 1222 | resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} 1223 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 1224 | dependencies: 1225 | acorn: 8.10.0 1226 | acorn-jsx: 5.3.2(acorn@8.10.0) 1227 | eslint-visitor-keys: 3.4.3 1228 | dev: true 1229 | 1230 | /esquery@1.5.0: 1231 | resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} 1232 | engines: {node: '>=0.10'} 1233 | dependencies: 1234 | estraverse: 5.3.0 1235 | dev: true 1236 | 1237 | /esrecurse@4.3.0: 1238 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 1239 | engines: {node: '>=4.0'} 1240 | dependencies: 1241 | estraverse: 5.3.0 1242 | dev: true 1243 | 1244 | /estraverse@5.3.0: 1245 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 1246 | engines: {node: '>=4.0'} 1247 | dev: true 1248 | 1249 | /estree-walker@2.0.2: 1250 | resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 1251 | dev: true 1252 | 1253 | /estree-walker@3.0.3: 1254 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 1255 | dependencies: 1256 | '@types/estree': 1.0.1 1257 | 1258 | /esutils@2.0.3: 1259 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 1260 | engines: {node: '>=0.10.0'} 1261 | dev: true 1262 | 1263 | /ext@1.7.0: 1264 | resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} 1265 | dependencies: 1266 | type: 2.7.2 1267 | 1268 | /fast-deep-equal@3.1.3: 1269 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 1270 | dev: true 1271 | 1272 | /fast-glob@3.3.0: 1273 | resolution: {integrity: sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==} 1274 | engines: {node: '>=8.6.0'} 1275 | dependencies: 1276 | '@nodelib/fs.stat': 2.0.5 1277 | '@nodelib/fs.walk': 1.2.8 1278 | glob-parent: 5.1.2 1279 | merge2: 1.4.1 1280 | micromatch: 4.0.5 1281 | dev: true 1282 | 1283 | /fast-json-stable-stringify@2.1.0: 1284 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 1285 | dev: true 1286 | 1287 | /fast-levenshtein@2.0.6: 1288 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 1289 | dev: true 1290 | 1291 | /fastq@1.15.0: 1292 | resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} 1293 | dependencies: 1294 | reusify: 1.0.4 1295 | dev: true 1296 | 1297 | /fetch-blob@3.2.0: 1298 | resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} 1299 | engines: {node: ^12.20 || >= 14.13} 1300 | dependencies: 1301 | node-domexception: 1.0.0 1302 | web-streams-polyfill: 3.2.1 1303 | dev: true 1304 | 1305 | /file-entry-cache@6.0.1: 1306 | resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} 1307 | engines: {node: ^10.12.0 || >=12.0.0} 1308 | dependencies: 1309 | flat-cache: 3.1.0 1310 | dev: true 1311 | 1312 | /fill-range@7.0.1: 1313 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 1314 | engines: {node: '>=8'} 1315 | dependencies: 1316 | to-regex-range: 5.0.1 1317 | dev: true 1318 | 1319 | /find-up@5.0.0: 1320 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 1321 | engines: {node: '>=10'} 1322 | dependencies: 1323 | locate-path: 6.0.0 1324 | path-exists: 4.0.0 1325 | dev: true 1326 | 1327 | /flat-cache@3.1.0: 1328 | resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==} 1329 | engines: {node: '>=12.0.0'} 1330 | dependencies: 1331 | flatted: 3.2.7 1332 | keyv: 4.5.3 1333 | rimraf: 3.0.2 1334 | dev: true 1335 | 1336 | /flatted@3.2.7: 1337 | resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} 1338 | dev: true 1339 | 1340 | /formdata-polyfill@4.0.10: 1341 | resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} 1342 | engines: {node: '>=12.20.0'} 1343 | dependencies: 1344 | fetch-blob: 3.2.0 1345 | dev: true 1346 | 1347 | /fs-minipass@2.1.0: 1348 | resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} 1349 | engines: {node: '>= 8'} 1350 | dependencies: 1351 | minipass: 3.3.6 1352 | dev: true 1353 | 1354 | /fs.realpath@1.0.0: 1355 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 1356 | dev: true 1357 | 1358 | /fsevents@2.3.3: 1359 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 1360 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1361 | os: [darwin] 1362 | requiresBuild: true 1363 | optional: true 1364 | 1365 | /function-bind@1.1.1: 1366 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 1367 | dev: true 1368 | 1369 | /glob-parent@5.1.2: 1370 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 1371 | engines: {node: '>= 6'} 1372 | dependencies: 1373 | is-glob: 4.0.3 1374 | dev: true 1375 | 1376 | /glob-parent@6.0.2: 1377 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 1378 | engines: {node: '>=10.13.0'} 1379 | dependencies: 1380 | is-glob: 4.0.3 1381 | dev: true 1382 | 1383 | /glob@7.2.3: 1384 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 1385 | dependencies: 1386 | fs.realpath: 1.0.0 1387 | inflight: 1.0.6 1388 | inherits: 2.0.4 1389 | minimatch: 3.1.2 1390 | once: 1.4.0 1391 | path-is-absolute: 1.0.1 1392 | dev: true 1393 | 1394 | /glob@8.1.0: 1395 | resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} 1396 | engines: {node: '>=12'} 1397 | dependencies: 1398 | fs.realpath: 1.0.0 1399 | inflight: 1.0.6 1400 | inherits: 2.0.4 1401 | minimatch: 5.1.6 1402 | once: 1.4.0 1403 | dev: true 1404 | 1405 | /globals@13.21.0: 1406 | resolution: {integrity: sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==} 1407 | engines: {node: '>=8'} 1408 | dependencies: 1409 | type-fest: 0.20.2 1410 | dev: true 1411 | 1412 | /globalyzer@0.1.0: 1413 | resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} 1414 | 1415 | /globby@11.1.0: 1416 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} 1417 | engines: {node: '>=10'} 1418 | dependencies: 1419 | array-union: 2.1.0 1420 | dir-glob: 3.0.1 1421 | fast-glob: 3.3.0 1422 | ignore: 5.2.4 1423 | merge2: 1.4.1 1424 | slash: 3.0.0 1425 | dev: true 1426 | 1427 | /globrex@0.1.2: 1428 | resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} 1429 | 1430 | /graceful-fs@4.2.11: 1431 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 1432 | dev: true 1433 | 1434 | /graphemer@1.4.0: 1435 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 1436 | dev: true 1437 | 1438 | /has-flag@4.0.0: 1439 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1440 | engines: {node: '>=8'} 1441 | dev: true 1442 | 1443 | /has@1.0.3: 1444 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 1445 | engines: {node: '>= 0.4.0'} 1446 | dependencies: 1447 | function-bind: 1.1.1 1448 | dev: true 1449 | 1450 | /ignore@5.2.4: 1451 | resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} 1452 | engines: {node: '>= 4'} 1453 | dev: true 1454 | 1455 | /import-fresh@3.3.0: 1456 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 1457 | engines: {node: '>=6'} 1458 | dependencies: 1459 | parent-module: 1.0.1 1460 | resolve-from: 4.0.0 1461 | dev: true 1462 | 1463 | /imurmurhash@0.1.4: 1464 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1465 | engines: {node: '>=0.8.19'} 1466 | dev: true 1467 | 1468 | /inflight@1.0.6: 1469 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 1470 | dependencies: 1471 | once: 1.4.0 1472 | wrappy: 1.0.2 1473 | dev: true 1474 | 1475 | /inherits@2.0.4: 1476 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1477 | dev: true 1478 | 1479 | /is-binary-path@2.1.0: 1480 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 1481 | engines: {node: '>=8'} 1482 | dependencies: 1483 | binary-extensions: 2.2.0 1484 | dev: true 1485 | 1486 | /is-builtin-module@3.2.1: 1487 | resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} 1488 | engines: {node: '>=6'} 1489 | dependencies: 1490 | builtin-modules: 3.3.0 1491 | dev: true 1492 | 1493 | /is-core-module@2.12.1: 1494 | resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} 1495 | dependencies: 1496 | has: 1.0.3 1497 | dev: true 1498 | 1499 | /is-extglob@2.1.1: 1500 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1501 | engines: {node: '>=0.10.0'} 1502 | dev: true 1503 | 1504 | /is-glob@4.0.3: 1505 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1506 | engines: {node: '>=0.10.0'} 1507 | dependencies: 1508 | is-extglob: 2.1.1 1509 | dev: true 1510 | 1511 | /is-module@1.0.0: 1512 | resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} 1513 | dev: true 1514 | 1515 | /is-number@7.0.0: 1516 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1517 | engines: {node: '>=0.12.0'} 1518 | dev: true 1519 | 1520 | /is-path-inside@3.0.3: 1521 | resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} 1522 | engines: {node: '>=8'} 1523 | dev: true 1524 | 1525 | /is-reference@1.2.1: 1526 | resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} 1527 | dependencies: 1528 | '@types/estree': 1.0.1 1529 | dev: true 1530 | 1531 | /is-reference@3.0.1: 1532 | resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==} 1533 | dependencies: 1534 | '@types/estree': 1.0.1 1535 | 1536 | /is-typedarray@1.0.0: 1537 | resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} 1538 | 1539 | /isexe@2.0.0: 1540 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1541 | dev: true 1542 | 1543 | /jose@4.14.4: 1544 | resolution: {integrity: sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==} 1545 | dev: false 1546 | 1547 | /js-yaml@4.1.0: 1548 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 1549 | hasBin: true 1550 | dependencies: 1551 | argparse: 2.0.1 1552 | dev: true 1553 | 1554 | /json-buffer@3.0.1: 1555 | resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 1556 | dev: true 1557 | 1558 | /json-schema-traverse@0.4.1: 1559 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 1560 | dev: true 1561 | 1562 | /json-stable-stringify-without-jsonify@1.0.1: 1563 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 1564 | dev: true 1565 | 1566 | /keyv@4.5.3: 1567 | resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} 1568 | dependencies: 1569 | json-buffer: 3.0.1 1570 | dev: true 1571 | 1572 | /kleur@4.1.5: 1573 | resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} 1574 | engines: {node: '>=6'} 1575 | 1576 | /known-css-properties@0.28.0: 1577 | resolution: {integrity: sha512-9pSL5XB4J+ifHP0e0jmmC98OGC1nL8/JjS+fi6mnTlIf//yt/MfVLtKg7S6nCtj/8KTcWX7nRlY0XywoYY1ISQ==} 1578 | dev: true 1579 | 1580 | /levn@0.4.1: 1581 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 1582 | engines: {node: '>= 0.8.0'} 1583 | dependencies: 1584 | prelude-ls: 1.2.1 1585 | type-check: 0.4.0 1586 | dev: true 1587 | 1588 | /ley@0.8.1: 1589 | resolution: {integrity: sha512-8Nd5uzie4PxiEJcQNv5YL1IQCMzye/0sE8VPB4KczJkyd44NfDyK/7Vbmp9eHYt+dJ4hxaXy+gF4DORSxYGArg==} 1590 | engines: {node: '>= 8'} 1591 | hasBin: true 1592 | dependencies: 1593 | kleur: 4.1.5 1594 | mk-dirs: 3.0.0 1595 | sade: 1.8.1 1596 | totalist: 2.0.0 1597 | dev: true 1598 | 1599 | /lilconfig@2.1.0: 1600 | resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} 1601 | engines: {node: '>=10'} 1602 | dev: true 1603 | 1604 | /locate-character@3.0.0: 1605 | resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} 1606 | 1607 | /locate-path@6.0.0: 1608 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 1609 | engines: {node: '>=10'} 1610 | dependencies: 1611 | p-locate: 5.0.0 1612 | dev: true 1613 | 1614 | /lodash.merge@4.6.2: 1615 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 1616 | dev: true 1617 | 1618 | /lru-cache@6.0.0: 1619 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 1620 | engines: {node: '>=10'} 1621 | dependencies: 1622 | yallist: 4.0.0 1623 | dev: true 1624 | 1625 | /magic-string@0.27.0: 1626 | resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} 1627 | engines: {node: '>=12'} 1628 | dependencies: 1629 | '@jridgewell/sourcemap-codec': 1.4.15 1630 | dev: true 1631 | 1632 | /magic-string@0.30.1: 1633 | resolution: {integrity: sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==} 1634 | engines: {node: '>=12'} 1635 | dependencies: 1636 | '@jridgewell/sourcemap-codec': 1.4.15 1637 | 1638 | /mdn-data@2.0.30: 1639 | resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} 1640 | 1641 | /merge2@1.4.1: 1642 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1643 | engines: {node: '>= 8'} 1644 | dev: true 1645 | 1646 | /micromatch@4.0.5: 1647 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} 1648 | engines: {node: '>=8.6'} 1649 | dependencies: 1650 | braces: 3.0.2 1651 | picomatch: 2.3.1 1652 | dev: true 1653 | 1654 | /mime@3.0.0: 1655 | resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} 1656 | engines: {node: '>=10.0.0'} 1657 | hasBin: true 1658 | 1659 | /min-indent@1.0.1: 1660 | resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} 1661 | engines: {node: '>=4'} 1662 | dev: true 1663 | 1664 | /minimatch@3.1.2: 1665 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 1666 | dependencies: 1667 | brace-expansion: 1.1.11 1668 | dev: true 1669 | 1670 | /minimatch@5.1.6: 1671 | resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} 1672 | engines: {node: '>=10'} 1673 | dependencies: 1674 | brace-expansion: 2.0.1 1675 | dev: true 1676 | 1677 | /minimist@1.2.8: 1678 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 1679 | dev: true 1680 | 1681 | /minipass@3.3.6: 1682 | resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} 1683 | engines: {node: '>=8'} 1684 | dependencies: 1685 | yallist: 4.0.0 1686 | dev: true 1687 | 1688 | /minipass@5.0.0: 1689 | resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} 1690 | engines: {node: '>=8'} 1691 | dev: true 1692 | 1693 | /minizlib@2.1.2: 1694 | resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} 1695 | engines: {node: '>= 8'} 1696 | dependencies: 1697 | minipass: 3.3.6 1698 | yallist: 4.0.0 1699 | dev: true 1700 | 1701 | /mk-dirs@3.0.0: 1702 | resolution: {integrity: sha512-FEZDdUFb88hgdnsfAPa4VxcPVOd+8GyZ2jsI965im5bjBlBYhrvXuTqLka/UHa6YdUNN/kZBsVgofhZ3322AJw==} 1703 | engines: {node: '>=6'} 1704 | dev: true 1705 | 1706 | /mkdirp@0.5.6: 1707 | resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} 1708 | hasBin: true 1709 | dependencies: 1710 | minimist: 1.2.8 1711 | dev: true 1712 | 1713 | /mkdirp@1.0.4: 1714 | resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} 1715 | engines: {node: '>=10'} 1716 | hasBin: true 1717 | dev: true 1718 | 1719 | /mri@1.2.0: 1720 | resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} 1721 | engines: {node: '>=4'} 1722 | 1723 | /mrmime@1.0.1: 1724 | resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} 1725 | engines: {node: '>=10'} 1726 | 1727 | /ms@2.0.0: 1728 | resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} 1729 | 1730 | /ms@2.1.2: 1731 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1732 | 1733 | /n4s@4.3.7: 1734 | resolution: {integrity: sha512-uzm6CL9cBMHaB/YuGBHRDRa6RuvpZ/xXgyoWgVS/+8/E0zQC3IyZVnIOPCOavCs/UOm4zomn99T4ng9HWcL7Cw==} 1735 | dependencies: 1736 | context: 3.0.7 1737 | vest-utils: 0.1.1 1738 | dev: false 1739 | 1740 | /nanoid@3.3.6: 1741 | resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} 1742 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1743 | hasBin: true 1744 | 1745 | /natural-compare@1.4.0: 1746 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 1747 | dev: true 1748 | 1749 | /next-tick@1.1.0: 1750 | resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} 1751 | 1752 | /node-domexception@1.0.0: 1753 | resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} 1754 | engines: {node: '>=10.5.0'} 1755 | dev: true 1756 | 1757 | /node-fetch@2.6.12: 1758 | resolution: {integrity: sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==} 1759 | engines: {node: 4.x || >=6.0.0} 1760 | peerDependencies: 1761 | encoding: ^0.1.0 1762 | peerDependenciesMeta: 1763 | encoding: 1764 | optional: true 1765 | dependencies: 1766 | whatwg-url: 5.0.0 1767 | 1768 | /node-fetch@3.3.2: 1769 | resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} 1770 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1771 | dependencies: 1772 | data-uri-to-buffer: 4.0.1 1773 | fetch-blob: 3.2.0 1774 | formdata-polyfill: 4.0.10 1775 | dev: true 1776 | 1777 | /node-gyp-build@4.6.0: 1778 | resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} 1779 | hasBin: true 1780 | 1781 | /normalize-path@3.0.0: 1782 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1783 | engines: {node: '>=0.10.0'} 1784 | dev: true 1785 | 1786 | /npm-normalize-package-bin@3.0.1: 1787 | resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==} 1788 | engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} 1789 | dev: true 1790 | 1791 | /once@1.4.0: 1792 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1793 | dependencies: 1794 | wrappy: 1.0.2 1795 | dev: true 1796 | 1797 | /optionator@0.9.3: 1798 | resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} 1799 | engines: {node: '>= 0.8.0'} 1800 | dependencies: 1801 | '@aashutoshrathi/word-wrap': 1.2.6 1802 | deep-is: 0.1.4 1803 | fast-levenshtein: 2.0.6 1804 | levn: 0.4.1 1805 | prelude-ls: 1.2.1 1806 | type-check: 0.4.0 1807 | dev: true 1808 | 1809 | /p-limit@3.1.0: 1810 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1811 | engines: {node: '>=10'} 1812 | dependencies: 1813 | yocto-queue: 0.1.0 1814 | dev: true 1815 | 1816 | /p-locate@5.0.0: 1817 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1818 | engines: {node: '>=10'} 1819 | dependencies: 1820 | p-limit: 3.1.0 1821 | dev: true 1822 | 1823 | /parent-module@1.0.1: 1824 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 1825 | engines: {node: '>=6'} 1826 | dependencies: 1827 | callsites: 3.1.0 1828 | dev: true 1829 | 1830 | /path-exists@4.0.0: 1831 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1832 | engines: {node: '>=8'} 1833 | dev: true 1834 | 1835 | /path-is-absolute@1.0.1: 1836 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 1837 | engines: {node: '>=0.10.0'} 1838 | dev: true 1839 | 1840 | /path-key@3.1.1: 1841 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1842 | engines: {node: '>=8'} 1843 | dev: true 1844 | 1845 | /path-parse@1.0.7: 1846 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 1847 | dev: true 1848 | 1849 | /path-type@4.0.0: 1850 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 1851 | engines: {node: '>=8'} 1852 | dev: true 1853 | 1854 | /periscopic@3.1.0: 1855 | resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} 1856 | dependencies: 1857 | '@types/estree': 1.0.1 1858 | estree-walker: 3.0.3 1859 | is-reference: 3.0.1 1860 | 1861 | /pg-connection-string@2.6.2: 1862 | resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} 1863 | dev: true 1864 | 1865 | /picocolors@1.0.0: 1866 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 1867 | 1868 | /picomatch@2.3.1: 1869 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1870 | engines: {node: '>=8.6'} 1871 | dev: true 1872 | 1873 | /postcss-load-config@3.1.4(postcss@8.4.29): 1874 | resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} 1875 | engines: {node: '>= 10'} 1876 | peerDependencies: 1877 | postcss: '>=8.0.9' 1878 | ts-node: '>=9.0.0' 1879 | peerDependenciesMeta: 1880 | postcss: 1881 | optional: true 1882 | ts-node: 1883 | optional: true 1884 | dependencies: 1885 | lilconfig: 2.1.0 1886 | postcss: 8.4.29 1887 | yaml: 1.10.2 1888 | dev: true 1889 | 1890 | /postcss-safe-parser@6.0.0(postcss@8.4.29): 1891 | resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} 1892 | engines: {node: '>=12.0'} 1893 | peerDependencies: 1894 | postcss: ^8.3.3 1895 | dependencies: 1896 | postcss: 8.4.29 1897 | dev: true 1898 | 1899 | /postcss-scss@4.0.7(postcss@8.4.29): 1900 | resolution: {integrity: sha512-xPv2GseoyXPa58Nro7M73ZntttusuCmZdeOojUFR5PZDz2BR62vfYx1w9TyOnp1+nYFowgOMipsCBhxzVkAEPw==} 1901 | engines: {node: '>=12.0'} 1902 | peerDependencies: 1903 | postcss: ^8.4.19 1904 | dependencies: 1905 | postcss: 8.4.29 1906 | dev: true 1907 | 1908 | /postcss-selector-parser@6.0.13: 1909 | resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} 1910 | engines: {node: '>=4'} 1911 | dependencies: 1912 | cssesc: 3.0.0 1913 | util-deprecate: 1.0.2 1914 | dev: true 1915 | 1916 | /postcss@8.4.29: 1917 | resolution: {integrity: sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==} 1918 | engines: {node: ^10 || ^12 || >=14} 1919 | dependencies: 1920 | nanoid: 3.3.6 1921 | picocolors: 1.0.0 1922 | source-map-js: 1.0.2 1923 | 1924 | /postgres@3.3.5: 1925 | resolution: {integrity: sha512-+JD93VELV9gHkqpV5gdL5/70HdGtEw4/XE1S4BC8f1mcPmdib3K5XsKVbnR1XcAyC41zOnifJ+9YRKxdIsXiUw==} 1926 | dev: true 1927 | 1928 | /prelude-ls@1.2.1: 1929 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 1930 | engines: {node: '>= 0.8.0'} 1931 | dev: true 1932 | 1933 | /prettier-plugin-svelte@3.0.3(prettier@3.0.3)(svelte@4.2.0): 1934 | resolution: {integrity: sha512-dLhieh4obJEK1hnZ6koxF+tMUrZbV5YGvRpf2+OADyanjya5j0z1Llo8iGwiHmFWZVG/hLEw/AJD5chXd9r3XA==} 1935 | peerDependencies: 1936 | prettier: ^3.0.0 1937 | svelte: ^3.2.0 || ^4.0.0-next.0 1938 | dependencies: 1939 | prettier: 3.0.3 1940 | svelte: 4.2.0 1941 | dev: true 1942 | 1943 | /prettier@3.0.3: 1944 | resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} 1945 | engines: {node: '>=14'} 1946 | hasBin: true 1947 | dev: true 1948 | 1949 | /punycode@2.3.0: 1950 | resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} 1951 | engines: {node: '>=6'} 1952 | dev: true 1953 | 1954 | /queue-microtask@1.2.3: 1955 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1956 | dev: true 1957 | 1958 | /read-cmd-shim@4.0.0: 1959 | resolution: {integrity: sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==} 1960 | engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} 1961 | dev: true 1962 | 1963 | /readdirp@3.6.0: 1964 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 1965 | engines: {node: '>=8.10.0'} 1966 | dependencies: 1967 | picomatch: 2.3.1 1968 | dev: true 1969 | 1970 | /resolve-from@4.0.0: 1971 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 1972 | engines: {node: '>=4'} 1973 | dev: true 1974 | 1975 | /resolve@1.22.2: 1976 | resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} 1977 | hasBin: true 1978 | dependencies: 1979 | is-core-module: 2.12.1 1980 | path-parse: 1.0.7 1981 | supports-preserve-symlinks-flag: 1.0.0 1982 | dev: true 1983 | 1984 | /reusify@1.0.4: 1985 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 1986 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1987 | dev: true 1988 | 1989 | /rimraf@2.7.1: 1990 | resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} 1991 | hasBin: true 1992 | dependencies: 1993 | glob: 7.2.3 1994 | dev: true 1995 | 1996 | /rimraf@3.0.2: 1997 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 1998 | hasBin: true 1999 | dependencies: 2000 | glob: 7.2.3 2001 | dev: true 2002 | 2003 | /rollup@3.26.1: 2004 | resolution: {integrity: sha512-I5gJCSpSMr3U9wv4D5YA8g7w7cj3eaSDeo7t+JcaFQOmoOUBgu4K9iMp8k3EZnwbJrjQxUMSKxMyB8qEQzzaSg==} 2005 | engines: {node: '>=14.18.0', npm: '>=8.0.0'} 2006 | hasBin: true 2007 | optionalDependencies: 2008 | fsevents: 2.3.3 2009 | dev: true 2010 | 2011 | /rollup@3.28.1: 2012 | resolution: {integrity: sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==} 2013 | engines: {node: '>=14.18.0', npm: '>=8.0.0'} 2014 | hasBin: true 2015 | optionalDependencies: 2016 | fsevents: 2.3.3 2017 | 2018 | /run-parallel@1.2.0: 2019 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 2020 | dependencies: 2021 | queue-microtask: 1.2.3 2022 | dev: true 2023 | 2024 | /sade@1.8.1: 2025 | resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} 2026 | engines: {node: '>=6'} 2027 | dependencies: 2028 | mri: 1.2.0 2029 | 2030 | /sander@0.5.1: 2031 | resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} 2032 | dependencies: 2033 | es6-promise: 3.3.1 2034 | graceful-fs: 4.2.11 2035 | mkdirp: 0.5.6 2036 | rimraf: 2.7.1 2037 | dev: true 2038 | 2039 | /semver@7.5.4: 2040 | resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} 2041 | engines: {node: '>=10'} 2042 | hasBin: true 2043 | dependencies: 2044 | lru-cache: 6.0.0 2045 | dev: true 2046 | 2047 | /set-cookie-parser@2.6.0: 2048 | resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} 2049 | 2050 | /shebang-command@2.0.0: 2051 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 2052 | engines: {node: '>=8'} 2053 | dependencies: 2054 | shebang-regex: 3.0.0 2055 | dev: true 2056 | 2057 | /shebang-regex@3.0.0: 2058 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 2059 | engines: {node: '>=8'} 2060 | dev: true 2061 | 2062 | /signal-exit@4.1.0: 2063 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 2064 | engines: {node: '>=14'} 2065 | dev: true 2066 | 2067 | /sirv@2.0.3: 2068 | resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==} 2069 | engines: {node: '>= 10'} 2070 | dependencies: 2071 | '@polka/url': 1.0.0-next.21 2072 | mrmime: 1.0.1 2073 | totalist: 3.0.1 2074 | 2075 | /slash@3.0.0: 2076 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 2077 | engines: {node: '>=8'} 2078 | dev: true 2079 | 2080 | /sorcery@0.11.0: 2081 | resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==} 2082 | hasBin: true 2083 | dependencies: 2084 | '@jridgewell/sourcemap-codec': 1.4.15 2085 | buffer-crc32: 0.2.13 2086 | minimist: 1.2.8 2087 | sander: 0.5.1 2088 | dev: true 2089 | 2090 | /source-map-js@1.0.2: 2091 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} 2092 | engines: {node: '>=0.10.0'} 2093 | 2094 | /streamsearch@1.1.0: 2095 | resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} 2096 | engines: {node: '>=10.0.0'} 2097 | 2098 | /strip-ansi@6.0.1: 2099 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 2100 | engines: {node: '>=8'} 2101 | dependencies: 2102 | ansi-regex: 5.0.1 2103 | dev: true 2104 | 2105 | /strip-indent@3.0.0: 2106 | resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} 2107 | engines: {node: '>=8'} 2108 | dependencies: 2109 | min-indent: 1.0.1 2110 | dev: true 2111 | 2112 | /strip-json-comments@3.1.1: 2113 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 2114 | engines: {node: '>=8'} 2115 | dev: true 2116 | 2117 | /supabase@1.88.0: 2118 | resolution: {integrity: sha512-eyfgSkLVauPRFOiTtddC/v3TFPTTlOwSur5Qh2s/kR/ZWMCySEYQ2E1+lsGvMSwP+SYpaDrYUICkb5CiaIZKow==} 2119 | engines: {npm: '>=8'} 2120 | hasBin: true 2121 | requiresBuild: true 2122 | dependencies: 2123 | bin-links: 4.0.2 2124 | node-fetch: 3.3.2 2125 | tar: 6.1.15 2126 | dev: true 2127 | 2128 | /supports-color@7.2.0: 2129 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 2130 | engines: {node: '>=8'} 2131 | dependencies: 2132 | has-flag: 4.0.0 2133 | dev: true 2134 | 2135 | /supports-preserve-symlinks-flag@1.0.0: 2136 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 2137 | engines: {node: '>= 0.4'} 2138 | dev: true 2139 | 2140 | /svelte-check@3.5.1(postcss@8.4.29)(svelte@4.2.0): 2141 | resolution: {integrity: sha512-+Zb4iHxAhdUtcUg/WJPRjlS1RJalIsWAe9Mz6G1zyznSs7dDkT7VUBdXc3q7Iwg49O/VrZgyJRvOJkjuBfKjFA==} 2142 | hasBin: true 2143 | peerDependencies: 2144 | svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 2145 | dependencies: 2146 | '@jridgewell/trace-mapping': 0.3.18 2147 | chokidar: 3.5.3 2148 | fast-glob: 3.3.0 2149 | import-fresh: 3.3.0 2150 | picocolors: 1.0.0 2151 | sade: 1.8.1 2152 | svelte: 4.2.0 2153 | svelte-preprocess: 5.0.4(postcss@8.4.29)(svelte@4.2.0)(typescript@5.2.2) 2154 | typescript: 5.2.2 2155 | transitivePeerDependencies: 2156 | - '@babel/core' 2157 | - coffeescript 2158 | - less 2159 | - postcss 2160 | - postcss-load-config 2161 | - pug 2162 | - sass 2163 | - stylus 2164 | - sugarss 2165 | dev: true 2166 | 2167 | /svelte-eslint-parser@0.33.0(svelte@4.2.0): 2168 | resolution: {integrity: sha512-5awZ6Bs+Tb/zQwa41PSdcLynAVQTwW0HGyCBjtbAQ59taLZqDgQSMzRlDmapjZdDtzERm0oXDZNE0E+PKJ6ryg==} 2169 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 2170 | peerDependencies: 2171 | svelte: ^3.37.0 || ^4.0.0 2172 | peerDependenciesMeta: 2173 | svelte: 2174 | optional: true 2175 | dependencies: 2176 | eslint-scope: 7.2.2 2177 | eslint-visitor-keys: 3.4.3 2178 | espree: 9.6.1 2179 | postcss: 8.4.29 2180 | postcss-scss: 4.0.7(postcss@8.4.29) 2181 | svelte: 4.2.0 2182 | dev: true 2183 | 2184 | /svelte-hmr@0.15.2(svelte@4.2.0): 2185 | resolution: {integrity: sha512-q/bAruCvFLwvNbeE1x3n37TYFb3mTBJ6TrCq6p2CoFbSTNhDE9oAtEfpy+wmc9So8AG0Tja+X0/mJzX9tSfvIg==} 2186 | engines: {node: ^12.20 || ^14.13.1 || >= 16} 2187 | peerDependencies: 2188 | svelte: ^3.19.0 || ^4.0.0-next.0 2189 | dependencies: 2190 | svelte: 4.2.0 2191 | 2192 | /svelte-preprocess@5.0.4(postcss@8.4.29)(svelte@4.2.0)(typescript@5.2.2): 2193 | resolution: {integrity: sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==} 2194 | engines: {node: '>= 14.10.0'} 2195 | requiresBuild: true 2196 | peerDependencies: 2197 | '@babel/core': ^7.10.2 2198 | coffeescript: ^2.5.1 2199 | less: ^3.11.3 || ^4.0.0 2200 | postcss: ^7 || ^8 2201 | postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0 2202 | pug: ^3.0.0 2203 | sass: ^1.26.8 2204 | stylus: ^0.55.0 2205 | sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0 2206 | svelte: ^3.23.0 || ^4.0.0-next.0 || ^4.0.0 2207 | typescript: '>=3.9.5 || ^4.0.0 || ^5.0.0' 2208 | peerDependenciesMeta: 2209 | '@babel/core': 2210 | optional: true 2211 | coffeescript: 2212 | optional: true 2213 | less: 2214 | optional: true 2215 | postcss: 2216 | optional: true 2217 | postcss-load-config: 2218 | optional: true 2219 | pug: 2220 | optional: true 2221 | sass: 2222 | optional: true 2223 | stylus: 2224 | optional: true 2225 | sugarss: 2226 | optional: true 2227 | typescript: 2228 | optional: true 2229 | dependencies: 2230 | '@types/pug': 2.0.6 2231 | detect-indent: 6.1.0 2232 | magic-string: 0.27.0 2233 | postcss: 8.4.29 2234 | sorcery: 0.11.0 2235 | strip-indent: 3.0.0 2236 | svelte: 4.2.0 2237 | typescript: 5.2.2 2238 | dev: true 2239 | 2240 | /svelte@4.2.0: 2241 | resolution: {integrity: sha512-kVsdPjDbLrv74SmLSUzAsBGquMs4MPgWGkGLpH+PjOYnFOziAvENVzgJmyOCV2gntxE32aNm8/sqNKD6LbIpeQ==} 2242 | engines: {node: '>=16'} 2243 | dependencies: 2244 | '@ampproject/remapping': 2.2.1 2245 | '@jridgewell/sourcemap-codec': 1.4.15 2246 | '@jridgewell/trace-mapping': 0.3.18 2247 | acorn: 8.10.0 2248 | aria-query: 5.3.0 2249 | axobject-query: 3.2.1 2250 | code-red: 1.0.3 2251 | css-tree: 2.3.1 2252 | estree-walker: 3.0.3 2253 | is-reference: 3.0.1 2254 | locate-character: 3.0.0 2255 | magic-string: 0.30.1 2256 | periscopic: 3.1.0 2257 | 2258 | /sveltekit-flash-message@2.2.0(@sveltejs/kit@1.24.0)(svelte@4.2.0): 2259 | resolution: {integrity: sha512-22hYvD4kQUWJevbiJQkRNIWtEexKyKYhN4zyn8YhfU6J2hRY1uFdTTfH0JIWwPkJ/QarBgLwzP79GO5t/LLZUw==} 2260 | peerDependencies: 2261 | '@sveltejs/kit': 1.x 2262 | svelte: 3.x || 4.x 2263 | dependencies: 2264 | '@sveltejs/kit': 1.24.0(svelte@4.2.0)(vite@4.4.9) 2265 | svelte: 4.2.0 2266 | dev: true 2267 | 2268 | /tar@6.1.15: 2269 | resolution: {integrity: sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==} 2270 | engines: {node: '>=10'} 2271 | dependencies: 2272 | chownr: 2.0.0 2273 | fs-minipass: 2.1.0 2274 | minipass: 5.0.0 2275 | minizlib: 2.1.2 2276 | mkdirp: 1.0.4 2277 | yallist: 4.0.0 2278 | dev: true 2279 | 2280 | /text-table@0.2.0: 2281 | resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} 2282 | dev: true 2283 | 2284 | /tiny-glob@0.2.9: 2285 | resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} 2286 | dependencies: 2287 | globalyzer: 0.1.0 2288 | globrex: 0.1.2 2289 | 2290 | /to-regex-range@5.0.1: 2291 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 2292 | engines: {node: '>=8.0'} 2293 | dependencies: 2294 | is-number: 7.0.0 2295 | dev: true 2296 | 2297 | /totalist@2.0.0: 2298 | resolution: {integrity: sha512-+Y17F0YzxfACxTyjfhnJQEe7afPA0GSpYlFkl2VFMxYP7jshQf9gXV7cH47EfToBumFThfKBvfAcoUn6fdNeRQ==} 2299 | engines: {node: '>=6'} 2300 | dev: true 2301 | 2302 | /totalist@3.0.1: 2303 | resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} 2304 | engines: {node: '>=6'} 2305 | 2306 | /tr46@0.0.3: 2307 | resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} 2308 | 2309 | /ts-api-utils@1.0.2(typescript@5.2.2): 2310 | resolution: {integrity: sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==} 2311 | engines: {node: '>=16.13.0'} 2312 | peerDependencies: 2313 | typescript: '>=4.2.0' 2314 | dependencies: 2315 | typescript: 5.2.2 2316 | dev: true 2317 | 2318 | /tslib@2.6.2: 2319 | resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} 2320 | dev: true 2321 | 2322 | /type-check@0.4.0: 2323 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 2324 | engines: {node: '>= 0.8.0'} 2325 | dependencies: 2326 | prelude-ls: 1.2.1 2327 | dev: true 2328 | 2329 | /type-fest@0.20.2: 2330 | resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} 2331 | engines: {node: '>=10'} 2332 | dev: true 2333 | 2334 | /type@1.2.0: 2335 | resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} 2336 | 2337 | /type@2.7.2: 2338 | resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} 2339 | 2340 | /typedarray-to-buffer@3.1.5: 2341 | resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} 2342 | dependencies: 2343 | is-typedarray: 1.0.0 2344 | 2345 | /typescript@5.2.2: 2346 | resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} 2347 | engines: {node: '>=14.17'} 2348 | hasBin: true 2349 | dev: true 2350 | 2351 | /undici@5.23.0: 2352 | resolution: {integrity: sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==} 2353 | engines: {node: '>=14.0'} 2354 | dependencies: 2355 | busboy: 1.6.0 2356 | 2357 | /uri-js@4.4.1: 2358 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 2359 | dependencies: 2360 | punycode: 2.3.0 2361 | dev: true 2362 | 2363 | /utf-8-validate@5.0.10: 2364 | resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} 2365 | engines: {node: '>=6.14.2'} 2366 | requiresBuild: true 2367 | dependencies: 2368 | node-gyp-build: 4.6.0 2369 | 2370 | /util-deprecate@1.0.2: 2371 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 2372 | dev: true 2373 | 2374 | /vast@1.0.17: 2375 | resolution: {integrity: sha512-D2fZtQp8RfZ8WMfzC0izcrrmOsZ8Dmc4B57G/J3z4wCAuvAZskyPOXBKLR5QRoQ4nb7doB/ueihEMnpDcXl7JA==} 2376 | dependencies: 2377 | vest-utils: 0.1.1 2378 | dev: false 2379 | 2380 | /vest-utils@0.1.1: 2381 | resolution: {integrity: sha512-dsH4zt4IsBvDY3BhUo6mNgwN9WVIfUP8jwBp2XEZQAq7XYAuVQnGTCrdF8+/OtoP141jCxMppXYpO4xbMWYwhA==} 2382 | dev: false 2383 | 2384 | /vest@4.6.11: 2385 | resolution: {integrity: sha512-2C2PfDselDX5cgaxZmp4v1IaAhnGzlSkuQSSYIsOac3TW1+N6QFHoUx2n5qkLpe0thJLZjEWT4fM4anQSSjP2Q==} 2386 | dependencies: 2387 | context: 3.0.7 2388 | n4s: 4.3.7 2389 | vast: 1.0.17 2390 | vest-utils: 0.1.1 2391 | dev: false 2392 | 2393 | /vite@4.4.9: 2394 | resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} 2395 | engines: {node: ^14.18.0 || >=16.0.0} 2396 | hasBin: true 2397 | peerDependencies: 2398 | '@types/node': '>= 14' 2399 | less: '*' 2400 | lightningcss: ^1.21.0 2401 | sass: '*' 2402 | stylus: '*' 2403 | sugarss: '*' 2404 | terser: ^5.4.0 2405 | peerDependenciesMeta: 2406 | '@types/node': 2407 | optional: true 2408 | less: 2409 | optional: true 2410 | lightningcss: 2411 | optional: true 2412 | sass: 2413 | optional: true 2414 | stylus: 2415 | optional: true 2416 | sugarss: 2417 | optional: true 2418 | terser: 2419 | optional: true 2420 | dependencies: 2421 | esbuild: 0.18.20 2422 | postcss: 8.4.29 2423 | rollup: 3.28.1 2424 | optionalDependencies: 2425 | fsevents: 2.3.3 2426 | 2427 | /vitefu@0.2.4(vite@4.4.9): 2428 | resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==} 2429 | peerDependencies: 2430 | vite: ^3.0.0 || ^4.0.0 2431 | peerDependenciesMeta: 2432 | vite: 2433 | optional: true 2434 | dependencies: 2435 | vite: 4.4.9 2436 | 2437 | /web-streams-polyfill@3.2.1: 2438 | resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} 2439 | engines: {node: '>= 8'} 2440 | dev: true 2441 | 2442 | /webidl-conversions@3.0.1: 2443 | resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} 2444 | 2445 | /websocket@1.0.34: 2446 | resolution: {integrity: sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==} 2447 | engines: {node: '>=4.0.0'} 2448 | dependencies: 2449 | bufferutil: 4.0.7 2450 | debug: 2.6.9 2451 | es5-ext: 0.10.62 2452 | typedarray-to-buffer: 3.1.5 2453 | utf-8-validate: 5.0.10 2454 | yaeti: 0.0.6 2455 | transitivePeerDependencies: 2456 | - supports-color 2457 | 2458 | /whatwg-url@5.0.0: 2459 | resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} 2460 | dependencies: 2461 | tr46: 0.0.3 2462 | webidl-conversions: 3.0.1 2463 | 2464 | /which@2.0.2: 2465 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 2466 | engines: {node: '>= 8'} 2467 | hasBin: true 2468 | dependencies: 2469 | isexe: 2.0.0 2470 | dev: true 2471 | 2472 | /wrappy@1.0.2: 2473 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 2474 | dev: true 2475 | 2476 | /write-file-atomic@5.0.1: 2477 | resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} 2478 | engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} 2479 | dependencies: 2480 | imurmurhash: 0.1.4 2481 | signal-exit: 4.1.0 2482 | dev: true 2483 | 2484 | /yaeti@0.0.6: 2485 | resolution: {integrity: sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==} 2486 | engines: {node: '>=0.10.32'} 2487 | 2488 | /yallist@4.0.0: 2489 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 2490 | dev: true 2491 | 2492 | /yaml@1.10.2: 2493 | resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} 2494 | engines: {node: '>= 6'} 2495 | dev: true 2496 | 2497 | /yocto-queue@0.1.0: 2498 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 2499 | engines: {node: '>=10'} 2500 | dev: true 2501 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | import { SupabaseClient, Session } from '@supabase/supabase-js' 2 | import { Database } from './lib/schema' 3 | import { CombinedUserMapper } from './lib/data/mappers/users' 4 | 5 | declare global { 6 | namespace App { 7 | interface Locals { 8 | supabase: SupabaseClient 9 | getSession(): Promise 10 | user: CombinedUserMapper | null 11 | } 12 | 13 | interface PageData { 14 | session: Session | null 15 | user?: CombinedUserMapper 16 | flash?: { type: 'success' | 'error'; message: string } 17 | } 18 | 19 | // interface Error {} 20 | // interface Platform {} 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | %sveltekit.head% 12 | 13 | 14 |
%sveltekit.body%
15 | 16 | 17 | -------------------------------------------------------------------------------- /src/hooks.server.ts: -------------------------------------------------------------------------------- 1 | // src/hooks.server.ts 2 | import { handleAuth } from '$lib/handleAuth' 3 | import { handleProfile } from '$lib/handleProfile' 4 | import type { Handle } from '@sveltejs/kit' 5 | import { sequence } from '@sveltejs/kit/hooks' 6 | 7 | export const handle: Handle = sequence(handleAuth, handleProfile) 8 | -------------------------------------------------------------------------------- /src/lib/admin.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from '@supabase/supabase-js' 2 | import { PUBLIC_SUPABASE_URL } from '$env/static/public' 3 | import { SUPABASE_SERVICE_ROLE_KEY } from '$env/static/private' 4 | 5 | const supabase = createClient(PUBLIC_SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, { 6 | auth: { 7 | persistSession: false, 8 | autoRefreshToken: false, 9 | detectSessionInUrl: false, 10 | } 11 | }) 12 | 13 | export default supabase 14 | -------------------------------------------------------------------------------- /src/lib/common/ButtonAction.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
{ 15 | isLoading = true 16 | return async ({ update }) => { 17 | isLoading = false 18 | update() 19 | } 20 | }} 21 | > 22 | 23 | 30 | 31 | -------------------------------------------------------------------------------- /src/lib/common/ButtonWithIcon.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 12 | -------------------------------------------------------------------------------- /src/lib/common/FullScreenLoader.svelte: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 65 | -------------------------------------------------------------------------------- /src/lib/common/GitHubButton.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Login with GitHub 11 | 12 | -------------------------------------------------------------------------------- /src/lib/common/Header.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 33 | 34 | 44 | -------------------------------------------------------------------------------- /src/lib/common/InlineLoader.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 |
8 | 9 | 68 | -------------------------------------------------------------------------------- /src/lib/common/Loader.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 |
8 | 9 | 34 | -------------------------------------------------------------------------------- /src/lib/common/Notification.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | {#if showNotification} 10 |
15 | {#if withButton} 16 |
20 | {/if} 21 | -------------------------------------------------------------------------------- /src/lib/common/TwitterButton.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Login with Twitter 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/lib/data/mappers/internal.ts: -------------------------------------------------------------------------------- 1 | interface ResponseMapper { 2 | status: string 3 | message: string 4 | statusCode: number 5 | } 6 | 7 | export interface SuccessMapperResponse extends ResponseMapper { 8 | data: T 9 | } 10 | 11 | export interface ErrorMapperResponse extends ResponseMapper { 12 | error: { 13 | message: string 14 | code: number 15 | } 16 | } 17 | 18 | export function isSuccessResponse( 19 | response: SuccessMapperResponse | ErrorMapperResponse 20 | ): response is SuccessMapperResponse { 21 | return (response as SuccessMapperResponse) !== undefined 22 | } 23 | 24 | export const withDefault = (prop: T, original: OT) => (prop ? prop : original) 25 | 26 | interface ResponseEvent { 27 | status: string 28 | message: string 29 | code: number 30 | } 31 | 32 | const responseMapper = (event: ResponseEvent) => ({ 33 | status: event.status, 34 | message: event.message, 35 | statusCode: event.code 36 | }) 37 | 38 | interface SuccessEvent { 39 | message: string 40 | code: number 41 | data: any 42 | } 43 | 44 | export const successMapper = (event: SuccessEvent): SuccessMapperResponse => ({ 45 | ...responseMapper({ 46 | status: 'success', 47 | message: event.message, 48 | code: withDefault(event.code, 200) 49 | }), 50 | data: withDefault(event.data, []) 51 | }) 52 | 53 | interface ErrorEvent { 54 | message: string 55 | code: number 56 | error: any 57 | } 58 | 59 | export const errorMapper = (event: ErrorEvent) => ({ 60 | error: withDefault(event.error, {}), 61 | ...responseMapper({ 62 | status: 'failed', 63 | message: event.message, 64 | code: withDefault(event.code, 400) 65 | }) 66 | }) 67 | -------------------------------------------------------------------------------- /src/lib/data/mappers/users.ts: -------------------------------------------------------------------------------- 1 | import type { User } from '@supabase/supabase-js' 2 | import type { Database } from '../../schema.js' 3 | import { withDefault } from './internal.js' 4 | 5 | interface UserMapper { 6 | id: string 7 | fullName: string | null 8 | isAdmin: boolean 9 | } 10 | 11 | interface LoggedInUserMapper { 12 | last_sign_in_at?: string 13 | authenticated: boolean 14 | email?: string 15 | id: string 16 | } 17 | 18 | type ProfileRow = Database['public']['Tables']['profiles']['Row'] 19 | type UserProp = Pick 20 | type MyUser = Pick 21 | 22 | export const userMapper = (user: UserProp): UserMapper => ({ 23 | id: user.id, 24 | fullName: withDefault(user.full_name, ''), 25 | isAdmin: user.is_admin ? true : false 26 | }) 27 | 28 | export const usersMapper = (users: UserProp[]) => users.map((u) => userMapper(u)) 29 | 30 | export const loggedInUserMapper = (user: MyUser): LoggedInUserMapper => ({ 31 | last_sign_in_at: user.last_sign_in_at, 32 | authenticated: user.aud === 'authenticated', 33 | email: user.email, 34 | id: user.id 35 | }) 36 | 37 | export type UserProfileProp = MyUser & UserProp 38 | export type CombinedUserMapper = LoggedInUserMapper & UserMapper 39 | 40 | export const combinedUserMapper = (user: UserProfileProp) => ({ 41 | ...loggedInUserMapper(user), 42 | ...userMapper(user) 43 | }) 44 | -------------------------------------------------------------------------------- /src/lib/data/mappers/waiting_list.ts: -------------------------------------------------------------------------------- 1 | import type { Database } from '../../schema.js' 2 | import { withDefault } from './internal.js' 3 | 4 | export interface WaitingListMapper { 5 | id: string 6 | fullName: string | null 7 | email: string 8 | invitedAt: string | null 9 | isInvited: boolean 10 | isConfirmed: boolean 11 | } 12 | 13 | type WaitingListRow = Database['public']['Tables']['waiting_list']['Row'] 14 | 15 | export const waitingListMapper = (user: WaitingListRow): WaitingListMapper => ({ 16 | id: user.id, 17 | fullName: withDefault(user.full_name, ''), 18 | email: user.email, 19 | invitedAt: user.invited_at, 20 | isInvited: user.invited_at ? true : false, 21 | isConfirmed: user.email_confirmed_at ? true : false 22 | }) 23 | 24 | export const waitingListsMapper = (users: WaitingListRow[]): WaitingListMapper[] => 25 | users.map((u) => waitingListMapper(u)) 26 | -------------------------------------------------------------------------------- /src/lib/handleAuth.ts: -------------------------------------------------------------------------------- 1 | import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public' 2 | import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit' 3 | import type { Handle } from '@sveltejs/kit' 4 | 5 | export const handleAuth: Handle = async ({ event, resolve }) => { 6 | event.locals.supabase = createSupabaseServerClient({ 7 | supabaseUrl: PUBLIC_SUPABASE_URL, 8 | supabaseKey: PUBLIC_SUPABASE_ANON_KEY, 9 | event, 10 | cookieOptions: { 11 | name: 'waiting-list-auth-token' 12 | } 13 | }) 14 | 15 | /** 16 | * a little helper that is written for convenience so that instead 17 | * of calling `const { data: { session } } = await supabase.auth.getSession()` 18 | * you just call this `await getSession()` 19 | */ 20 | event.locals.getSession = async () => { 21 | const { 22 | data: { session } 23 | } = await event.locals.supabase.auth.getSession() 24 | return session 25 | } 26 | 27 | return resolve(event, { 28 | filterSerializedResponseHeaders(name) { 29 | return name === 'content-range' 30 | } 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /src/lib/handleProfile.ts: -------------------------------------------------------------------------------- 1 | import { combinedUserMapper, type UserProfileProp } from '$lib/data/mappers/users' 2 | import type { Handle } from '@sveltejs/kit' 3 | 4 | export const handleProfile: Handle = async ({ event, resolve }) => { 5 | const { getSession, supabase } = event.locals 6 | const session = await getSession() 7 | 8 | if (session) { 9 | const { user } = session 10 | if (user) { 11 | const { data: profile } = await supabase 12 | .from('profiles') 13 | .select('*') 14 | .eq('id', user?.id) 15 | .maybeSingle() 16 | 17 | const userProfile: UserProfileProp = Object.assign(user, profile) 18 | event.locals.user = combinedUserMapper(userProfile) 19 | } 20 | } else { 21 | event.locals.user = null 22 | } 23 | 24 | return resolve(event) 25 | } 26 | -------------------------------------------------------------------------------- /src/lib/schema.ts: -------------------------------------------------------------------------------- 1 | export type Json = 2 | | string 3 | | number 4 | | boolean 5 | | null 6 | | { [key: string]: Json | undefined } 7 | | Json[] 8 | 9 | export interface Database { 10 | graphql_public: { 11 | Tables: { 12 | [_ in never]: never 13 | } 14 | Views: { 15 | [_ in never]: never 16 | } 17 | Functions: { 18 | graphql: { 19 | Args: { 20 | operationName?: string 21 | query?: string 22 | variables?: Json 23 | extensions?: Json 24 | } 25 | Returns: Json 26 | } 27 | } 28 | Enums: { 29 | [_ in never]: never 30 | } 31 | CompositeTypes: { 32 | [_ in never]: never 33 | } 34 | } 35 | public: { 36 | Tables: { 37 | profiles: { 38 | Row: { 39 | confirmed_at: string | null 40 | created_at: string 41 | full_name: string | null 42 | id: string 43 | is_admin: boolean | null 44 | updated_at: string | null 45 | } 46 | Insert: { 47 | confirmed_at?: string | null 48 | created_at?: string 49 | full_name?: string | null 50 | id: string 51 | is_admin?: boolean | null 52 | updated_at?: string | null 53 | } 54 | Update: { 55 | confirmed_at?: string | null 56 | created_at?: string 57 | full_name?: string | null 58 | id?: string 59 | is_admin?: boolean | null 60 | updated_at?: string | null 61 | } 62 | Relationships: [ 63 | { 64 | foreignKeyName: "profiles_id_fkey" 65 | columns: ["id"] 66 | referencedRelation: "users" 67 | referencedColumns: ["id"] 68 | } 69 | ] 70 | } 71 | waiting_list: { 72 | Row: { 73 | created_at: string 74 | email: string 75 | email_confirmed_at: string | null 76 | full_name: string 77 | id: string 78 | invited_at: string | null 79 | profile_id: string | null 80 | updated_at: string | null 81 | } 82 | Insert: { 83 | created_at?: string 84 | email: string 85 | email_confirmed_at?: string | null 86 | full_name: string 87 | id?: string 88 | invited_at?: string | null 89 | profile_id?: string | null 90 | updated_at?: string | null 91 | } 92 | Update: { 93 | created_at?: string 94 | email?: string 95 | email_confirmed_at?: string | null 96 | full_name?: string 97 | id?: string 98 | invited_at?: string | null 99 | profile_id?: string | null 100 | updated_at?: string | null 101 | } 102 | Relationships: [ 103 | { 104 | foreignKeyName: "waiting_list_id_fkey" 105 | columns: ["profile_id"] 106 | referencedRelation: "profiles" 107 | referencedColumns: ["id"] 108 | } 109 | ] 110 | } 111 | } 112 | Views: { 113 | [_ in never]: never 114 | } 115 | Functions: { 116 | is_admin: { 117 | Args: { 118 | user_id: string 119 | } 120 | Returns: boolean 121 | } 122 | } 123 | Enums: { 124 | [_ in never]: never 125 | } 126 | CompositeTypes: { 127 | [_ in never]: never 128 | } 129 | } 130 | storage: { 131 | Tables: { 132 | buckets: { 133 | Row: { 134 | allowed_mime_types: string[] | null 135 | avif_autodetection: boolean | null 136 | created_at: string | null 137 | file_size_limit: number | null 138 | id: string 139 | name: string 140 | owner: string | null 141 | public: boolean | null 142 | updated_at: string | null 143 | } 144 | Insert: { 145 | allowed_mime_types?: string[] | null 146 | avif_autodetection?: boolean | null 147 | created_at?: string | null 148 | file_size_limit?: number | null 149 | id: string 150 | name: string 151 | owner?: string | null 152 | public?: boolean | null 153 | updated_at?: string | null 154 | } 155 | Update: { 156 | allowed_mime_types?: string[] | null 157 | avif_autodetection?: boolean | null 158 | created_at?: string | null 159 | file_size_limit?: number | null 160 | id?: string 161 | name?: string 162 | owner?: string | null 163 | public?: boolean | null 164 | updated_at?: string | null 165 | } 166 | Relationships: [ 167 | { 168 | foreignKeyName: "buckets_owner_fkey" 169 | columns: ["owner"] 170 | referencedRelation: "users" 171 | referencedColumns: ["id"] 172 | } 173 | ] 174 | } 175 | migrations: { 176 | Row: { 177 | executed_at: string | null 178 | hash: string 179 | id: number 180 | name: string 181 | } 182 | Insert: { 183 | executed_at?: string | null 184 | hash: string 185 | id: number 186 | name: string 187 | } 188 | Update: { 189 | executed_at?: string | null 190 | hash?: string 191 | id?: number 192 | name?: string 193 | } 194 | Relationships: [] 195 | } 196 | objects: { 197 | Row: { 198 | bucket_id: string | null 199 | created_at: string | null 200 | id: string 201 | last_accessed_at: string | null 202 | metadata: Json | null 203 | name: string | null 204 | owner: string | null 205 | path_tokens: string[] | null 206 | updated_at: string | null 207 | version: string | null 208 | } 209 | Insert: { 210 | bucket_id?: string | null 211 | created_at?: string | null 212 | id?: string 213 | last_accessed_at?: string | null 214 | metadata?: Json | null 215 | name?: string | null 216 | owner?: string | null 217 | path_tokens?: string[] | null 218 | updated_at?: string | null 219 | version?: string | null 220 | } 221 | Update: { 222 | bucket_id?: string | null 223 | created_at?: string | null 224 | id?: string 225 | last_accessed_at?: string | null 226 | metadata?: Json | null 227 | name?: string | null 228 | owner?: string | null 229 | path_tokens?: string[] | null 230 | updated_at?: string | null 231 | version?: string | null 232 | } 233 | Relationships: [ 234 | { 235 | foreignKeyName: "objects_bucketId_fkey" 236 | columns: ["bucket_id"] 237 | referencedRelation: "buckets" 238 | referencedColumns: ["id"] 239 | } 240 | ] 241 | } 242 | } 243 | Views: { 244 | [_ in never]: never 245 | } 246 | Functions: { 247 | can_insert_object: { 248 | Args: { 249 | bucketid: string 250 | name: string 251 | owner: string 252 | metadata: Json 253 | } 254 | Returns: undefined 255 | } 256 | extension: { 257 | Args: { 258 | name: string 259 | } 260 | Returns: string 261 | } 262 | filename: { 263 | Args: { 264 | name: string 265 | } 266 | Returns: string 267 | } 268 | foldername: { 269 | Args: { 270 | name: string 271 | } 272 | Returns: unknown 273 | } 274 | get_size_by_bucket: { 275 | Args: Record 276 | Returns: { 277 | size: number 278 | bucket_id: string 279 | }[] 280 | } 281 | search: { 282 | Args: { 283 | prefix: string 284 | bucketname: string 285 | limits?: number 286 | levels?: number 287 | offsets?: number 288 | search?: string 289 | sortcolumn?: string 290 | sortorder?: string 291 | } 292 | Returns: { 293 | name: string 294 | id: string 295 | updated_at: string 296 | created_at: string 297 | last_accessed_at: string 298 | metadata: Json 299 | }[] 300 | } 301 | } 302 | Enums: { 303 | [_ in never]: never 304 | } 305 | CompositeTypes: { 306 | [_ in never]: never 307 | } 308 | } 309 | } 310 | 311 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import type { Suite } from 'vest' 2 | 3 | export const formatErrors = (errors: Record) => { 4 | const formattedErrors: Record = {} 5 | for (const err in errors) { 6 | const errVal = errors[err] 7 | if (errVal.length > 0) { 8 | formattedErrors[err] = errVal[0] 9 | } 10 | } 11 | return formattedErrors 12 | } 13 | 14 | export const suiteRun = (suite: Suite<(data: T) => void>, data: T) => { 15 | const result = suite(data) 16 | if (result.isValid()) { 17 | return true 18 | } 19 | return formatErrors(result.getErrors()) 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/validationSchema.ts: -------------------------------------------------------------------------------- 1 | import { create, test, enforce, skipWhen } from 'vest' 2 | import emailRegex from 'email-regex' 3 | import { suiteRun } from '$lib/utils' 4 | 5 | enforce.extend({ 6 | isValidEmail: (value) => emailRegex({ exact: true }).test(value) 7 | }) 8 | 9 | const emailValidation = (data: { email: string }) => { 10 | test('email', 'Email is required', () => { 11 | enforce(data.email).isString().isNotEmpty() 12 | }) 13 | 14 | test('email', 'Email Address is not valid', () => { 15 | enforce(data.email).isValidEmail() 16 | }) 17 | } 18 | 19 | const passwordValidation = (data: { password: string }) => { 20 | test('password', 'Password is required', () => { 21 | enforce(data.password).isString().isNotEmpty() 22 | }) 23 | 24 | test('password', 'Password must be at least 6 characters', () => { 25 | enforce(data.password).longerThanOrEquals(6) 26 | }) 27 | } 28 | 29 | const forgotPasswordSuite = create((data) => { 30 | emailValidation(data) 31 | }) 32 | 33 | const signInSuite = create((data) => { 34 | emailValidation(data) 35 | passwordValidation(data) 36 | }) 37 | 38 | const signUpSuite = create((data) => { 39 | emailValidation(data) 40 | passwordValidation(data) 41 | 42 | test('fullName', 'Full Name is required', () => { 43 | enforce(data.fullName).isString().isNotEmpty() 44 | }) 45 | }) 46 | 47 | const waitingListSuite = create((data) => { 48 | emailValidation(data) 49 | 50 | test('fullName', 'Full Name is required', () => { 51 | enforce(data.fullName).isString().isNotEmpty() 52 | }) 53 | }) 54 | 55 | const resetPasswordSuite = create((data) => { 56 | passwordValidation(data) 57 | 58 | skipWhen(!data.password, () => { 59 | test('passwordConfirm', 'Password does not match', () => { 60 | enforce(data.passwordConfirm).equals(data.password) 61 | }) 62 | }) 63 | }) 64 | 65 | const inviteTokenSuite = create((data: InviteToken) => { 66 | emailValidation(data) 67 | 68 | test('token', 'Token is required', () => { 69 | enforce(data.token).isString().isNotEmpty() 70 | }) 71 | }) 72 | 73 | const confirmTokenSuite = create((data: ConfirmToken) => { 74 | test('token', 'Token Hash is required', () => { 75 | enforce(data.token).isString().isNotEmpty() 76 | }) 77 | }) 78 | 79 | interface ForgotPassword { 80 | email: string 81 | } 82 | 83 | interface SignIn { 84 | email: string 85 | password: string 86 | } 87 | 88 | interface SignUp { 89 | email: string 90 | password: string 91 | fullName: string 92 | } 93 | 94 | interface WaitingList { 95 | email: string 96 | fullName: string 97 | } 98 | interface ResetPassword { 99 | password: string 100 | passwordConfirm: string 101 | } 102 | 103 | interface InviteToken { 104 | email: string 105 | token: string 106 | } 107 | 108 | interface ConfirmToken { 109 | token: string 110 | } 111 | 112 | export const ForgotPasswordSchema = (data: ForgotPassword) => suiteRun(forgotPasswordSuite, data) 113 | export const SignInSchema = (data: SignIn) => suiteRun(signInSuite, data) 114 | export const SignUpSchema = (data: SignUp) => suiteRun(signUpSuite, data) 115 | export const WaitingListSchema = (data: WaitingList) => suiteRun(waitingListSuite, data) 116 | export const ResetPasswordSchema = (data: ResetPassword) => suiteRun(resetPasswordSuite, data) 117 | export const InviteTokenSchema = (data: InviteToken) => suiteRun(inviteTokenSuite, data) 118 | export const ConfirmTokenSchema = (data: ConfirmToken) => suiteRun(confirmTokenSuite, data) 119 | -------------------------------------------------------------------------------- /src/routes/+layout.server.ts: -------------------------------------------------------------------------------- 1 | import { loadFlash } from 'sveltekit-flash-message/server' 2 | import type { LayoutServerLoad } from './$types' 3 | 4 | export const load: LayoutServerLoad = loadFlash(async ({ locals: { getSession, user } }) => { 5 | return { 6 | session: await getSession(), 7 | user 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | Waiting List App 22 | 23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 | 45 | -------------------------------------------------------------------------------- /src/routes/+layout.ts: -------------------------------------------------------------------------------- 1 | // src/routes/+layout.ts 2 | import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public' 3 | import { createSupabaseLoadClient } from '@supabase/auth-helpers-sveltekit' 4 | import type { Database } from '../lib/schema' 5 | import type { LayoutLoadEvent } from './$types' 6 | 7 | export const load = async ({ fetch, data, depends }: LayoutLoadEvent) => { 8 | depends('supabase:auth') 9 | 10 | const supabase = createSupabaseLoadClient({ 11 | supabaseUrl: PUBLIC_SUPABASE_URL, 12 | supabaseKey: PUBLIC_SUPABASE_ANON_KEY, 13 | event: { fetch }, 14 | serverSession: data.session, 15 | cookieOptions: { 16 | name: 'waiting-list-auth-token' 17 | } 18 | }) 19 | 20 | const { 21 | data: { session } 22 | } = await supabase.auth.getSession() 23 | 24 | return { supabase, session, user: data.user } 25 | } 26 | -------------------------------------------------------------------------------- /src/routes/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { WaitingListSchema } from '$lib/validationSchema' 2 | import { fail } from '@sveltejs/kit' 3 | import type { Actions } from './$types' 4 | 5 | export const actions: Actions = { 6 | default: async (event) => { 7 | const { 8 | request, 9 | locals: { supabase } 10 | } = event 11 | const formData = await request.formData() 12 | const fullName = formData.get('fullName') as string 13 | const email = formData.get('email') as string 14 | 15 | const test = WaitingListSchema({ fullName, email }) 16 | 17 | if (test !== true) { 18 | return fail(400, { errors: test, fullName, email }) 19 | } 20 | 21 | const { error } = await supabase.from('waiting_list').insert({ email, full_name: fullName }) 22 | 23 | if (error) { 24 | return fail(400, { 25 | success: false, 26 | message: `We're sorry, but it seems that the email you provided might have already been invited. Please try using a different email address or contact our support team for assistance.`, 27 | fullName, 28 | email 29 | }) 30 | } 31 | 32 | return { success: true, message: `You've been successfully added to the waiting list.` } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 | {#if user?.id} 13 |
14 |
15 |
16 |

17 | You are currently signed in Take me to my account 18 |

19 |
20 |
21 |
22 | {:else} 23 |
24 |
25 |
26 | Waiting List App 27 |
28 |
29 |
30 |
31 |

Waiting List App

32 |
33 | 37 | {form?.message} 38 | 39 | 40 |
41 |
42 |

43 | 50 |

51 | {#if form?.errors?.fullName} 52 |

{form?.errors?.fullName}

53 | {/if} 54 |
55 |
56 |

57 | 64 |

65 | {#if form?.errors?.email} 66 |

{form?.errors?.email}

67 | {/if} 68 |
69 |
70 |

71 | 72 |

73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |

83 | Have you been invited already? Sign in 84 |

85 |
86 |
87 |
88 | {/if} 89 |
90 | -------------------------------------------------------------------------------- /src/routes/account/+layout.server.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from '@sveltejs/kit' 2 | import type { LayoutServerLoad } from './$types' 3 | 4 | export const load: LayoutServerLoad = async ({ locals: { getSession, user } }) => { 5 | const session = await getSession() 6 | 7 | if (!session) { 8 | throw redirect(303, '/auth/signin') 9 | } 10 | 11 | if (user?.isAdmin) { 12 | throw redirect(303, '/manage') 13 | } 14 | 15 | return { session } 16 | } 17 | -------------------------------------------------------------------------------- /src/routes/account/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |
7 | 8 |
9 | 10 | 15 | -------------------------------------------------------------------------------- /src/routes/account/+page.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | WLA 9 | 10 | 11 |

12 | Welcome {user?.fullName} 13 |

14 | 15 |
16 |
Thanks for taking the time to check this tutorial and project out
17 |
18 | Resources used in this project 19 | 36 |
37 |
38 | -------------------------------------------------------------------------------- /src/routes/account/password-update/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { ResetPasswordSchema } from '$lib/validationSchema' 2 | import { fail } from '@sveltejs/kit' 3 | import type { Actions } from './$types' 4 | 5 | export const actions: Actions = { 6 | default: async ({ request, locals: { supabase } }) => { 7 | const formData = await request.formData() 8 | const password = formData.get('password') as string 9 | const passwordConfirm = formData.get('passwordConfirm') as string 10 | 11 | const test = ResetPasswordSchema({ password, passwordConfirm }) 12 | 13 | if (test !== true) { 14 | return fail(400, { errors: test, password, passwordConfirm }) 15 | } 16 | 17 | const { error } = await supabase.auth.updateUser({ password }) 18 | 19 | if (error) { 20 | return fail(400, { 21 | success: false, 22 | message: error.message 23 | }) 24 | } 25 | 26 | return { 27 | success: true, 28 | message: 'Password updated successfully.' 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/routes/account/password-update/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | WLA 10 | 11 | 12 |

Update Password

13 | 14 |
15 | 19 | {form?.message} 20 | 21 |
22 |
23 |

24 | 31 |

32 | {#if form?.errors?.password} 33 |

{form?.errors?.password}

34 | {/if} 35 |
36 |
37 |

38 | 45 |

46 | {#if form?.errors?.passwordConfirm} 47 |

{form?.errors?.passwordConfirm}

48 | {/if} 49 |
50 |
51 |

52 | 53 |

54 |
55 |
56 |
57 | -------------------------------------------------------------------------------- /src/routes/auth/+layout.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /src/routes/auth/+page.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from '@sveltejs/kit' 2 | import type { PageLoad } from './$types' 3 | 4 | export const load: PageLoad = async () => { 5 | throw redirect(302, '/auth/signin') 6 | } 7 | -------------------------------------------------------------------------------- /src/routes/auth/confirm/+server.ts: -------------------------------------------------------------------------------- 1 | import { ConfirmTokenSchema } from '$lib/validationSchema' 2 | import type { EmailOtpType } from '@supabase/supabase-js' 3 | import { fail, redirect } from '@sveltejs/kit' 4 | import { setFlash } from 'sveltekit-flash-message/server' 5 | import type { RequestHandler } from './$types' 6 | 7 | export const GET: RequestHandler = async (event) => { 8 | let { 9 | url, 10 | locals: { supabase } 11 | } = event 12 | const token = url.searchParams.get('token_hash') as string 13 | const authType = (url.searchParams.get('type') ?? 'email') as EmailOtpType 14 | let next = url.searchParams.get('next') ?? '/account' 15 | 16 | const test = ConfirmTokenSchema({ token }) 17 | 18 | if (test !== true) { 19 | throw fail(400, { errors: test }) 20 | } 21 | 22 | const { error } = await supabase.auth.verifyOtp({ token_hash: token, type: authType }) 23 | 24 | if (error) { 25 | setFlash( 26 | { 27 | type: 'error', 28 | message: `The token link has expired, please try getting invited again.` 29 | }, 30 | event 31 | ) 32 | next = `/auth/signin${next ? '?next=' + next : ''}` 33 | } 34 | 35 | throw redirect(303, `/${next.slice(1)}`) 36 | } 37 | -------------------------------------------------------------------------------- /src/routes/auth/forgotpassword/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { ForgotPasswordSchema } from '$lib/validationSchema' 2 | import { fail } from '@sveltejs/kit' 3 | import type { Actions } from './$types' 4 | 5 | export const actions: Actions = { 6 | default: async (event) => { 7 | const { 8 | url, 9 | request, 10 | locals: { supabase } 11 | } = event 12 | const formData = await request.formData() 13 | const email = formData.get('email') as string 14 | 15 | const test = ForgotPasswordSchema({ email }) 16 | 17 | if (test !== true) { 18 | return fail(400, { errors: test, email }) 19 | } 20 | 21 | const { error } = await supabase.auth.resetPasswordForEmail(email) 22 | 23 | if (error) { 24 | return fail(400, { 25 | success: false, 26 | message: error.message 27 | }) 28 | } 29 | 30 | return { 31 | success: true, 32 | message: 'Reset email sent successfully, please check your email for the reset password link.' 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/routes/auth/forgotpassword/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | Forgot your password? - Waiting List App 10 | 11 | 12 |
13 |
14 |
15 |

Waiting List App

16 |
17 |

Trouble logging in?

18 |

19 | Enter your email and we'll send you a link to get back into your account. 20 |

21 | 25 | {form?.message} 26 | 27 |
28 |
29 |

30 | 37 |

38 | {#if form?.errors?.email} 39 |

{form?.errors?.email}

40 | {/if} 41 |
42 |
43 |

44 | 45 |

46 |
47 |
48 |
49 |
50 | 51 |
52 |

Back to Login

53 |
54 |
55 |
56 | -------------------------------------------------------------------------------- /src/routes/auth/invite-code/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { InviteTokenSchema } from '$lib/validationSchema' 2 | import { fail, redirect } from '@sveltejs/kit' 3 | import type { Actions, PageServerLoad } from './$types.js' 4 | 5 | export const load: PageServerLoad = async (event) => { 6 | const { 7 | locals: { getSession } 8 | } = event 9 | const session = await getSession() 10 | 11 | if (session) { 12 | throw redirect(303, '/account') 13 | } 14 | } 15 | 16 | export const actions: Actions = { 17 | default: async (event) => { 18 | const { 19 | request, 20 | locals: { supabase } 21 | } = event 22 | const formData = await request.formData() 23 | const email = formData.get('email') as string 24 | const token = formData.get('token') as string 25 | 26 | const test = InviteTokenSchema({ email, token }) 27 | 28 | if (test !== true) { 29 | return fail(400, { errors: test, email }) 30 | } 31 | 32 | const { error } = await supabase.auth.verifyOtp({ email, token, type: 'email' }) 33 | 34 | if (error) { 35 | return fail(400, { 36 | success: false, 37 | email, 38 | message: `The email that you've entered doesn't belong to an account. Please check your email and try again.` 39 | }) 40 | } 41 | 42 | throw redirect(303, '/account/password-update') 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/routes/auth/invite-code/+page.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | Waiting List App - Sign In 21 | 22 | 23 |
24 |
25 |
26 | Placeholder 27 |
28 |
29 |
30 |
31 |

Waiting List App

32 |
33 | 37 | {form?.message} 38 | 39 |
40 |
41 |

42 | 49 |

50 | {#if form?.errors?.email} 51 |

{form?.errors?.email}

52 | {/if} 53 |
54 |
55 |

56 | 57 |

58 | {#if form?.errors?.token} 59 |

{form?.errors?.token}

60 | {/if} 61 |
62 |
63 |

64 | 65 |

66 |
67 |
68 |
69 | 74 |
75 | 76 |
77 |

78 | Don't have an account? Get on the waiting list 79 |

80 |
81 |
82 |
83 | -------------------------------------------------------------------------------- /src/routes/auth/signin/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { SignInSchema } from '$lib/validationSchema' 2 | import { fail, redirect } from '@sveltejs/kit' 3 | import { loadFlash } from 'sveltekit-flash-message/server' 4 | import type { Actions, PageServerLoad } from './$types.js' 5 | 6 | export const load: PageServerLoad = loadFlash(async (event) => { 7 | const { 8 | locals: { getSession } 9 | } = event 10 | const session = await getSession() 11 | 12 | if (session) { 13 | throw redirect(303, '/account') 14 | } 15 | }) 16 | 17 | export const actions: Actions = { 18 | default: async (event) => { 19 | const { 20 | url, 21 | request, 22 | locals: { supabase } 23 | } = event 24 | const formData = await request.formData() 25 | const email = formData.get('email') as string 26 | const password = formData.get('password') as string 27 | const next = new URL(url.searchParams.get('next') ?? '/account', url) 28 | 29 | const test = SignInSchema({ email, password }) 30 | 31 | if (test !== true) { 32 | return fail(400, { errors: test, email }) 33 | } 34 | 35 | const { error } = await supabase.auth.signInWithPassword({ email, password }) 36 | 37 | if (error) { 38 | return fail(400, { 39 | success: false, 40 | email, 41 | message: `The email that you've entered doesn't belong to an account. Please check your email and try again.` 42 | }) 43 | } 44 | 45 | throw redirect(303, next.pathname) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/routes/auth/signin/+page.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | Waiting List App - Sign In 27 | 28 | 29 |
30 |
31 |
32 | Placeholder 33 |
34 |
35 |
36 |
37 |

Waiting List App

38 |
39 | {#if $flash} 40 | 41 | {$flash.message} 42 | 43 | {/if} 44 | 48 | {form?.message} 49 | 50 |
51 |
52 |

53 | 60 |

61 | {#if form?.errors?.email} 62 |

{form?.errors?.email}

63 | {/if} 64 |
65 |
66 |

67 | 74 |

75 | {#if form?.errors?.password} 76 |

{form?.errors?.password}

77 | {/if} 78 |
79 |
80 |

81 | 82 |

83 |
84 |
85 |
86 | 91 |
92 | 93 |
94 |

95 | Don't have an account? Get on the waiting list 96 |

97 |
98 |
99 |
100 | -------------------------------------------------------------------------------- /src/routes/auth/signout/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from '@sveltejs/kit' 2 | import type { Actions } from './$types' 3 | 4 | export const actions: Actions = { 5 | default: async (event) => { 6 | const { 7 | locals: { supabase, getSession } 8 | } = event 9 | const session = await getSession() 10 | 11 | if (session) { 12 | await supabase.auth.signOut() 13 | throw redirect(303, '/auth/signin') 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/routes/auth/signup/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { SignUpSchema } from '$lib/validationSchema' 2 | import { fail, redirect } from '@sveltejs/kit' 3 | import supabase from '$lib/admin' 4 | import type { Actions, PageServerLoad } from './$types' 5 | 6 | export const load: PageServerLoad = async () => { 7 | const { data, error } = await supabase 8 | .from('profiles') 9 | .select('is_admin, confirmed_at') 10 | .eq('is_admin', true) 11 | .maybeSingle() 12 | 13 | if (!error) { 14 | if (data?.confirmed_at === null || !data?.is_admin) { 15 | return {} 16 | } 17 | } 18 | 19 | throw redirect(302, '/auth/signin') 20 | } 21 | 22 | export const actions: Actions = { 23 | default: async (event) => { 24 | const { 25 | request, 26 | locals: { supabase } 27 | } = event 28 | const formData = await request.formData() 29 | const email = formData.get('email') as string 30 | const password = formData.get('password') as string 31 | const fullName = formData.get('fullName') as string 32 | 33 | const test = SignUpSchema({ email, password, fullName }) 34 | 35 | if (test !== true) { 36 | return fail(400, { errors: test, email, password, fullName }) 37 | } 38 | 39 | const { error } = await supabase.auth.signUp({ 40 | email, 41 | password, 42 | options: { 43 | data: { 44 | is_admin: true, 45 | full_name: fullName 46 | } 47 | } 48 | }) 49 | 50 | if (error) { 51 | return fail(400, { 52 | success: false, 53 | message: error.message, 54 | email, 55 | password, 56 | fullName 57 | }) 58 | } 59 | 60 | return { 61 | success: true, 62 | message: 'Signup successfully, please check your email for a confirmation message.' 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/routes/auth/signup/+page.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | Waiting List App - Sign up 10 | 11 | 12 |
13 |
14 |
15 |

Waiting List App

16 |
17 | 21 | {form?.message} 22 | 23 |
24 |
25 |

26 | 33 |

34 | {#if form?.errors?.fullName} 35 |

{form?.errors?.fullName}

36 | {/if} 37 |
38 |
39 |

40 | 47 |

48 | {#if form?.errors?.email} 49 |

{form?.errors?.email}

50 | {/if} 51 |
52 |
53 |

54 | 61 |

62 | {#if form?.errors?.password} 63 |

{form?.errors?.password}

64 | {/if} 65 |
66 |
67 |

68 | 69 |

70 |
71 |
72 |
73 |
74 | 75 |
76 |

Have have an account? Sign in

77 |
78 |
79 |
80 | -------------------------------------------------------------------------------- /src/routes/manage/+layout.server.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from '@sveltejs/kit' 2 | import type { LayoutServerLoad } from './$types' 3 | 4 | export const load: LayoutServerLoad = async (event) => { 5 | const { user, getSession } = event.locals 6 | const session = await getSession() 7 | 8 | if (!session) { 9 | throw redirect(303, '/auth/signin') 10 | } 11 | 12 | if (!user?.isAdmin) { 13 | throw redirect(303, '/account') 14 | } 15 | 16 | return { session } 17 | } 18 | -------------------------------------------------------------------------------- /src/routes/manage/+layout.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | Waiting List App 8 | 9 | 10 |
11 |
12 |
13 | 16 | 34 |
35 | 40 |
41 |
42 |
43 | 44 |
45 | -------------------------------------------------------------------------------- /src/routes/manage/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { fail } from '@sveltejs/kit' 2 | import { waitingListsMapper } from '$lib/data/mappers/waiting_list' 3 | import supabase from '$lib/admin' 4 | import type { Actions, PageServerLoad } from './$types.js' 5 | 6 | export const load: PageServerLoad = async (event) => { 7 | const { 8 | locals: { supabase } 9 | } = event 10 | const { data, error } = await supabase 11 | .from('waiting_list') 12 | .select('*') 13 | .order('created_at', { ascending: false }) 14 | 15 | if (error) { 16 | return { 17 | users: [] 18 | } 19 | } 20 | 21 | return { 22 | users: waitingListsMapper(data) 23 | } 24 | } 25 | 26 | export const actions: Actions = { 27 | invite: async (event) => { 28 | const { locals, request } = event 29 | if (!locals.user?.isAdmin) { 30 | return fail(401, { message: 'You are not authorized to make this request' }) 31 | } 32 | 33 | const formData = await request.formData() 34 | const formUser = formData.get('user') as string 35 | 36 | if (!formUser) { 37 | return fail(400, { user: formUser, missing: true }) 38 | } 39 | 40 | const user = JSON.parse(formUser) 41 | 42 | const { data, error } = await supabase.auth.admin.inviteUserByEmail(user.email, { 43 | data: { 44 | waiting_list_id: user.id, 45 | full_name: user.fullName, 46 | is_admin: false 47 | } 48 | }) 49 | 50 | if (error) { 51 | return fail(400, { message: error.message }) 52 | } 53 | 54 | return { ...user, isInvited: true, invitedAt: data.user.invited_at } 55 | }, 56 | remove: async (event) => { 57 | const { 58 | request, 59 | locals: { supabase, user } 60 | } = event 61 | if (!user?.isAdmin) { 62 | return fail(401, { message: 'You are not authorized to make this request' }) 63 | } 64 | 65 | const formData = await request.formData() 66 | const userId = formData.get('userId') 67 | 68 | if (!userId) { 69 | return fail(400, { userId: userId, missing: true }) 70 | } 71 | 72 | // check if invited before allowing delete 73 | const { data } = await supabase 74 | .from('waiting_list') 75 | .select() 76 | .match({ id: userId }) 77 | .maybeSingle() 78 | 79 | if (data && data.invited_at) { 80 | return fail(400, { 81 | message: `You cannot delete ${data.full_name} from the waiting list` 82 | }) 83 | } 84 | 85 | const { error } = await supabase.from('waiting_list').delete().match({ id: userId }) 86 | if (error) { 87 | return fail(400, { message: error.message }) 88 | } 89 | 90 | return { success: true, message: 'User was deleted successfully' } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/routes/manage/+page.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 17 | {form?.message} 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {#each users as user} 39 | 40 | 41 | 42 | 43 | 59 | 60 | {:else} 61 | 62 | 63 | 64 | {/each} 65 | 66 |
NameEmailInvitedAction
NameEmailInvitedAction
{user.fullName} {user.email}{user.isInvited ? 'Yes' : 'No'} 44 |
45 | 46 | 47 | 48 | 49 | {user.isInvited ? 'Invite Again' : 'Invite'} 50 | 51 | 52 | 53 | 54 | 55 | Delete 56 | 57 |
58 |
No user was found on the waiting list
67 |
68 |
69 | -------------------------------------------------------------------------------- /src/routes/manage/Layout.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 |

10 | Welcome back {#if user}{user?.fullName}{/if} 11 |

12 |
13 | 14 |
15 | -------------------------------------------------------------------------------- /src/routes/manage/users/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { usersMapper } from '$lib/data/mappers/users' 2 | import { fail } from '@sveltejs/kit' 3 | import supabase from '$lib/admin' 4 | import type { Actions, PageServerLoad } from './$types.js' 5 | 6 | export const load: PageServerLoad = async ({ locals: { supabase } }) => { 7 | const { error, data } = await supabase 8 | .from('profiles') 9 | .select('*') 10 | .not('is_admin', 'eq', true) 11 | .order('created_at', { ascending: false }) 12 | 13 | if (error) { 14 | return { 15 | users: [] 16 | } 17 | } 18 | 19 | return { 20 | users: usersMapper(data) 21 | } 22 | } 23 | 24 | export const actions: Actions = { 25 | remove: async (event) => { 26 | const { locals, request } = event 27 | if (!locals.user?.isAdmin) { 28 | return fail(401, { message: 'You are not authorized to make this request' }) 29 | } 30 | 31 | const formData = await request.formData() 32 | const userId = formData.get('userId') as string 33 | const userFullName = formData.get('userFullName') as string 34 | 35 | if (!userId) { 36 | return fail(400, { userId: userId, missing: true }) 37 | } 38 | 39 | // check if invited before allowing delete 40 | const { error } = await supabase.auth.admin.deleteUser(userId) 41 | 42 | if (error) { 43 | return fail(400, { 44 | message: `You cannot delete ${userFullName} from the waiting list` 45 | }) 46 | } 47 | 48 | return { success: true, message: 'User was deleted successfully' } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/routes/manage/users/+page.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | Users 15 | 19 | {form?.message} 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {#each users as user} 37 | 38 | 39 | 50 | 51 | {:else} 52 | 53 | 54 | 55 | {/each} 56 | 57 |
NameAction
NameAction
{user.fullName} 40 |
41 | 42 | 43 | 44 | 45 | 46 | Delete 47 | 48 |
49 |
No user has been invited as yet
58 |
59 |
60 | -------------------------------------------------------------------------------- /static/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/static/android-chrome-192x192.png -------------------------------------------------------------------------------- /static/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/static/android-chrome-512x512.png -------------------------------------------------------------------------------- /static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/static/apple-touch-icon.png -------------------------------------------------------------------------------- /static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/static/favicon-16x16.png -------------------------------------------------------------------------------- /static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/static/favicon-32x32.png -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/static/favicon.ico -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/static/favicon.png -------------------------------------------------------------------------------- /static/img/1280x960.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/static/img/1280x960.png -------------------------------------------------------------------------------- /static/img/WaitingList_Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/static/img/WaitingList_Icon.png -------------------------------------------------------------------------------- /static/img/WaitingList_Logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /static/img/WaitingList_Placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/static/img/WaitingList_Placeholder.png -------------------------------------------------------------------------------- /static/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /supabase/.gitignore: -------------------------------------------------------------------------------- 1 | # Supabase 2 | .branches 3 | .temp 4 | -------------------------------------------------------------------------------- /supabase/auth/email/confirmation.html: -------------------------------------------------------------------------------- 1 |

Sign up confirmation

2 | 3 |

Thank you for signing up! To complete the registration process and gain access to our platform, please click the link below to confirm your account:

4 | 5 |

Confirm your email address

6 | 7 |

This confirmation step is important to ensure that we have accurate and up-to-date information for all our users. Once you have confirmed your account, you will be logged in and you can start using our services.

8 | 9 |

Thank you for choosing our platform. We look forward to serving you.

10 | -------------------------------------------------------------------------------- /supabase/auth/email/email-change.html: -------------------------------------------------------------------------------- 1 |

Confirm Change of Email

2 | 3 |

4 | Follow this link to confirm the update of your email from {{ .Email }} to {{ .NewEmail }}: 5 |

6 |

Change Email

7 | 8 |

Or use the token {{ .Token }}

-------------------------------------------------------------------------------- /supabase/auth/email/invite.html: -------------------------------------------------------------------------------- 1 |

You have been invited

2 | 3 |

4 | You have been invited to create a user on {{ .SiteURL }}. Follow this link to 5 | accept the invite: 6 |

7 |

Accept the invite

8 | 9 |

or visit {{ .SiteURL }}/auth/invite-code and enter your email and code: {{ .Token }}

10 | 11 |

The link and code will remain valid for 24 hours or until it is used, whichever comes first. If you need to request another link, please contact the website admin.

12 | -------------------------------------------------------------------------------- /supabase/auth/email/magic-link.html: -------------------------------------------------------------------------------- 1 |

Magic Link

2 | 3 |

Follow this link to login:

4 |

Log In

5 | 6 |

The link will remain valid for 24 hours or until it is used, whichever comes first. If you need to request another link, please click here.

-------------------------------------------------------------------------------- /supabase/auth/email/recovery.html: -------------------------------------------------------------------------------- 1 |

Password Reset

2 | 3 |

We're sorry to hear that you're having trouble accessing your account. To reset your password and regain access, please click the link below:

4 | 5 |

Reset Password

6 | 7 |

Once you've clicked the link, you'll be prompted to enter a new password for your account. Please choose a strong, unique password that you haven't used before, and make sure to remember it for future logins.

8 | 9 |

If you did not request a password reset, please ignore this message and do not click the link. Your account security is important to us, and we take all necessary steps to protect it.

10 | -------------------------------------------------------------------------------- /supabase/config.toml: -------------------------------------------------------------------------------- 1 | # A string used to distinguish different Supabase projects on the same host. Defaults to the working 2 | # directory name when running `supabase init`. 3 | project_id = "waiting-list" 4 | 5 | [api] 6 | # Port to use for the API URL. 7 | port = 58721 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 = 58722 20 | # The database major version to use. This has to be the same as your remote database's. Run `SHOW 21 | # server_version;` on the remote database to check. 22 | major_version = 15 23 | 24 | [studio] 25 | # Port to use for Supabase Studio. 26 | port = 58723 27 | 28 | # Email testing server. Emails sent with the local dev setup are not actually sent - rather, they 29 | # are monitored, and you can view the emails that would have been sent from the web interface. 30 | [inbucket] 31 | # Port to use for the email testing server web interface. 32 | port = 58724 33 | smtp_port = 58725 34 | pop3_port = 58726 35 | 36 | [storage] 37 | # The maximum file size allowed (e.g. "5MB", "500KB"). 38 | file_size_limit = "50MiB" 39 | 40 | [auth] 41 | # The base URL of your website. Used as an allow-list for redirects and for constructing URLs used 42 | # in emails. 43 | site_url = "http://localhost:5173" 44 | # A list of *exact* URLs that auth providers are permitted to redirect to post authentication. 45 | additional_redirect_urls = ["https://localhost:5173"] 46 | # How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one 47 | # week). 48 | jwt_expiry = 3600 49 | # Allow/disallow new user signups to your project. 50 | enable_signup = true 51 | 52 | [auth.email] 53 | # Allow/disallow new user signups via email to your project. 54 | enable_signup = true 55 | # If enabled, a user will be required to confirm any email change on both the old, and new email 56 | # addresses. If disabled, only the new email is required to confirm. 57 | double_confirm_changes = true 58 | # If enabled, users need to confirm their email address before signing in. 59 | enable_confirmations = true 60 | 61 | # Uncomment to customize email template 62 | [auth.email.template.invite] 63 | subject = "You have been invited" 64 | content_path = "./supabase/auth/email/invite.html" 65 | 66 | [auth.email.template.confirmation] 67 | subject = "Confirm Your Email for Auth Flows" 68 | content_path = "./supabase/auth/email/confirmation.html" 69 | 70 | [auth.email.template.recovery] 71 | subject = "Reset Your Password for Auth Flows" 72 | content_path = "./supabase/auth/email/recovery.html" 73 | 74 | [auth.email.template.magic_link] 75 | subject = "Your Magic Link for Auth Flows" 76 | content_path = "./supabase/auth/email/magic-link.html" 77 | 78 | [auth.email.template.email_change] 79 | subject = "Confirm Email Change for Auth Flows" 80 | content_path = "./supabase/auth/email/email-change.html" 81 | 82 | # Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, 83 | # `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin`, `notion`, `twitch`, 84 | # `twitter`, `slack`, `spotify`, `workos`, `zoom`. 85 | [auth.external.apple] 86 | enabled = false 87 | client_id = "" 88 | secret = "" 89 | # Overrides the default auth redirectUrl. 90 | redirect_uri = "" 91 | # Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, 92 | # or any other third-party OIDC providers. 93 | url = "" 94 | 95 | 96 | [analytics] 97 | enabled = false 98 | port = 54327 99 | vector_port = 54328 100 | # Setup BigQuery project to enable log viewer on local development stack. 101 | # See: https://logflare.app/guides/bigquery-setup 102 | gcp_project_id = "" 103 | gcp_project_number = "" 104 | gcp_jwt_path = "supabase/gcloud.json" 105 | -------------------------------------------------------------------------------- /supabase/migrations/20230529164842_create_profile_table.sql: -------------------------------------------------------------------------------- 1 | create table if not exists public.profiles ( 2 | id uuid PRIMARY KEY REFERENCES auth.users NOT NULL, 3 | full_name VARCHAR NULL, 4 | is_admin BOOL DEFAULT FALSE, 5 | created_at TIMESTAMPTZ DEFAULT now() NOT NULL, 6 | updated_at TIMESTAMPTZ 7 | ); 8 | 9 | alter table public.profiles enable row level security; -------------------------------------------------------------------------------- /supabase/migrations/20230529164939_handle_new_profile_function.sql: -------------------------------------------------------------------------------- 1 | create or replace function public.handle_new_profile() 2 | returns trigger as $$ 3 | begin 4 | insert into public.profiles (id, full_name, is_admin) 5 | values (new.id, new.raw_user_meta_data->>'full_name', (new.raw_user_meta_data->>'is_admin')::boolean); 6 | return new; 7 | end; 8 | $$ language plpgsql security definer; 9 | 10 | create or replace trigger on_auth_user_created 11 | after insert on auth.users 12 | for each row execute procedure public.handle_new_profile(); -------------------------------------------------------------------------------- /supabase/migrations/20230529170733_create_waiting_list_table.sql: -------------------------------------------------------------------------------- 1 | create table if not exists public.waiting_list ( 2 | id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), 3 | full_name VARCHAR NOT NULL, 4 | email VARCHAR UNIQUE NOT NULL, 5 | email_confirmed_at TIMESTAMPTZ, 6 | invited_at TIMESTAMPTZ, 7 | created_at TIMESTAMPTZ DEFAULT now() NOT NULL, 8 | updated_at TIMESTAMPTZ 9 | ); 10 | 11 | alter table public.waiting_list enable row level security; -------------------------------------------------------------------------------- /supabase/migrations/20230529170749_create_is_admin_function.sql: -------------------------------------------------------------------------------- 1 | -- admin check with boolean 2 | create or replace function public.is_admin(user_id uuid) 3 | returns boolean as $$ 4 | declare 5 | admin int; 6 | begin 7 | select count(*) 8 | from public.profiles 9 | where profiles.is_admin 10 | and profiles.id = is_admin.user_id 11 | into admin; 12 | 13 | return admin > 0; 14 | end; 15 | $$ language plpgsql security definer; -------------------------------------------------------------------------------- /supabase/migrations/20230529170805_create_rls_policy_profiles.sql: -------------------------------------------------------------------------------- 1 | CREATE POLICY "Allow select for admin users or own profile only" 2 | ON public.profiles 3 | FOR SELECT USING ( 4 | is_admin(auth.uid()) or auth.uid() = id 5 | ); 6 | 7 | CREATE POLICY "Allow insert for own profile only" 8 | ON public.profiles 9 | FOR INSERT WITH CHECK (auth.uid() = id); 10 | 11 | -- update policy 12 | CREATE POLICY "Allow update for own profile only" 13 | ON public.profiles 14 | FOR UPDATE USING (auth.uid() = id); 15 | 16 | -- delete policy 17 | CREATE POLICY "Allow delete for own profile only" 18 | ON public.profiles 19 | FOR DELETE USING (auth.uid() = id); 20 | 21 | -------------------------------------------------------------------------------- /supabase/migrations/20230529170821_create_rls_policy_waiting_list.sql: -------------------------------------------------------------------------------- 1 | CREATE POLICY "Allow select for admin users only" 2 | ON public.waiting_list 3 | FOR SELECT USING ( 4 | is_admin(auth.uid()) 5 | ); 6 | 7 | 8 | CREATE POLICY "Allow insert for all users" 9 | ON public.waiting_list 10 | FOR INSERT WITH CHECK (true); 11 | 12 | 13 | -- update policy 14 | CREATE POLICY "Allow update for admin users only" 15 | ON public.waiting_list 16 | FOR UPDATE USING ( 17 | is_admin(auth.uid()) 18 | ); 19 | 20 | 21 | -- delete policy 22 | CREATE POLICY "Allow delete for admin users only" 23 | ON public.waiting_list 24 | FOR DELETE USING ( 25 | is_admin(auth.uid()) 26 | ); 27 | -------------------------------------------------------------------------------- /supabase/migrations/20230529170846_handle_waiting_list_invited_at_function.sql: -------------------------------------------------------------------------------- 1 | create or replace function public.handle_waiting_list_invited_at() 2 | returns trigger as $$ 3 | begin 4 | IF ((NEW.raw_user_meta_data->>'waiting_list_id')::uuid is null) THEN 5 | RETURN NULL; 6 | ELSE 7 | UPDATE public.waiting_list 8 | SET invited_at = NOW(), 9 | updated_at = NOW() 10 | WHERE id = (NEW.raw_user_meta_data->>'waiting_list_id')::uuid; 11 | RETURN NEW; 12 | END IF; 13 | end; 14 | $$ language plpgsql security definer; 15 | 16 | 17 | create or replace trigger on_invite_sent 18 | after insert on auth.users 19 | for each row execute procedure public.handle_waiting_list_invited_at(); -------------------------------------------------------------------------------- /supabase/migrations/20230529170913_add_cascade_delete_constraint_profiles.sql: -------------------------------------------------------------------------------- 1 | alter table profiles 2 | drop constraint if exists profiles_id_fkey, 3 | add constraint profiles_id_fkey 4 | foreign key (id) 5 | references auth.users 6 | on delete cascade; 7 | -------------------------------------------------------------------------------- /supabase/migrations/20230529170940_add_reference_from_users_to_waiting_list.sql: -------------------------------------------------------------------------------- 1 | alter table waiting_list 2 | add column profile_id uuid; 3 | 4 | alter table waiting_list 5 | add constraint waiting_list_id_fkey 6 | foreign key (profile_id) 7 | references profiles (id) 8 | on delete cascade; 9 | 10 | -- Replace handle waiting list function with additional profile_id entry 11 | create or replace function public.handle_waiting_list_invited_at() 12 | returns trigger as $$ 13 | begin 14 | IF ((NEW.raw_user_meta_data->>'waiting_list_id')::uuid is null) THEN 15 | RETURN NULL; 16 | ELSE 17 | UPDATE public.waiting_list 18 | SET profile_id = new.id, 19 | invited_at = NOW(), 20 | updated_at = NOW() 21 | WHERE id = (NEW.raw_user_meta_data->>'waiting_list_id')::uuid; 22 | RETURN NEW; 23 | END IF; 24 | end; 25 | $$ language plpgsql security definer; 26 | -------------------------------------------------------------------------------- /supabase/migrations/20230601000442_update_profile_table_and_add_trigger_function.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE profiles 2 | ADD COLUMN confirmed_at TIMESTAMPTZ; 3 | 4 | create or replace function public.handle_admin_user_confirmed_at() 5 | returns trigger as $$ 6 | begin 7 | IF (NEW.confirmed_at is not null) THEN 8 | UPDATE public.profiles 9 | SET confirmed_at = NEW.confirmed_at 10 | WHERE id = (NEW.id)::uuid; 11 | RETURN NEW; 12 | END IF; 13 | RETURN NULL; 14 | end; 15 | $$ language plpgsql security definer; 16 | 17 | 18 | create or replace trigger on_admin_user_confirmation 19 | after update on auth.users 20 | for each row execute procedure public.handle_admin_user_confirmed_at(); -------------------------------------------------------------------------------- /supabase/migrations/20230903015359_waiting_list_email_confirmed_function.sql: -------------------------------------------------------------------------------- 1 | create or replace function public.handle_waiting_list_email_confirmed_at() 2 | returns trigger as $$ 3 | begin 4 | IF (NEW.confirmed_at is not null) THEN 5 | UPDATE public.waiting_list 6 | SET email_confirmed_at = NEW.confirmed_at 7 | WHERE profile_id = (NEW.id)::uuid; 8 | RETURN NEW; 9 | END IF; 10 | RETURN NULL; 11 | end; 12 | $$ language plpgsql security definer; 13 | 14 | 15 | create or replace trigger on_waiting_list_user_confirmation 16 | after update on auth.users 17 | for each row execute procedure public.handle_waiting_list_email_confirmed_at(); -------------------------------------------------------------------------------- /supabase/seed.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silentworks/waiting-list/bc122bacc5128aa6d9d18b198012fb9640386f82/supabase/seed.sql -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-node' 2 | import preprocess from 'svelte-preprocess' 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://github.com/sveltejs/svelte-preprocess 7 | // for more information about preprocessors 8 | preprocess: preprocess(), 9 | 10 | kit: { 11 | adapter: adapter() 12 | } 13 | } 14 | 15 | export default config 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | // vite.config.js 2 | import { sveltekit } from '@sveltejs/kit/vite'; 3 | 4 | // const dev = process.env.NODE_ENV === 'development' 5 | 6 | /** @type {import('vite').UserConfig} */ 7 | const config = { 8 | plugins: [sveltekit()], 9 | // optimizeDeps: { 10 | // exclude: dev ? [] : ['@supabase/supabase-js'] 11 | // } 12 | }; 13 | 14 | export default config; 15 | --------------------------------------------------------------------------------