├── web ├── .npmrc ├── src │ ├── routes │ │ ├── +layout.js │ │ ├── base.css │ │ ├── +layout.svelte │ │ ├── Counter.svelte │ │ ├── Header.svelte │ │ ├── styles.css │ │ └── +page.svelte │ ├── lib │ │ ├── images │ │ │ ├── svelte-welcome.png │ │ │ ├── svelte-welcome.webp │ │ │ ├── github.svg │ │ │ └── svelte-logo.svg │ │ ├── auth.js │ │ └── Logo.svelte │ ├── app.d.ts │ └── app.html ├── static │ ├── robots.txt │ ├── favicon.png │ └── favicon.svg ├── vite.config.js ├── .gitignore ├── svelte.config.js ├── jsconfig.json ├── package.json └── README.md ├── docs ├── .npmrc ├── src │ ├── routes │ │ ├── +layout.js │ │ ├── +layout.svelte │ │ ├── global.css │ │ ├── selfhost │ │ │ └── +page.svelte │ │ ├── roadmap │ │ │ └── +page.svelte │ │ └── +page.svelte │ ├── lib │ │ ├── index.js │ │ └── ui │ │ │ ├── index.js │ │ │ ├── BottomBar.svelte │ │ │ ├── Github.svelte │ │ │ ├── Navbar.svelte │ │ │ ├── Logo.svelte │ │ │ └── HostingCalculator.svelte │ ├── app.d.ts │ └── app.html ├── .dockerignore ├── static │ ├── favicon.png │ ├── github.svg │ └── favicon.svg ├── vite.config.js ├── .gitignore ├── Dockerfile ├── svelte.config.js ├── jsconfig.json ├── package.json ├── README.md └── package-lock.json ├── api ├── data │ ├── auth.json │ └── pocketbase-ADzCZJPL_details.json ├── globals │ └── globals.go ├── functions │ ├── proxy.go │ └── projects.go ├── paths │ └── paths.go ├── filesystem │ ├── filesystem.go │ └── projects.go ├── go.mod ├── docker │ ├── compose.go │ ├── network.go │ └── docker.go ├── main.go ├── auth │ └── auth.go └── go.sum ├── .dockerignore ├── go.work ├── .gitattributes ├── testing ├── go.mod ├── Dockerfile ├── lastworking.txt └── main.go ├── images ├── app.jpeg └── containers.png ├── .gitignore ├── todo.txt ├── dev.sh ├── go.work.sum ├── Buildpocketbase ├── Dockerfile ├── apiProtection.txt ├── commands.txt ├── .github └── workflows │ ├── build-pocketbase.yml │ ├── build-dashboard.yml │ └── deploy-docs.yml └── README.md /web/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /docs/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /api/data/auth.json: -------------------------------------------------------------------------------- 1 | {"password": "lazar"} -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | ./web/node_modules 2 | ./web/build 3 | ./testing -------------------------------------------------------------------------------- /docs/src/routes/+layout.js: -------------------------------------------------------------------------------- 1 | export const prerender = true 2 | -------------------------------------------------------------------------------- /web/src/routes/+layout.js: -------------------------------------------------------------------------------- 1 | export const prerender = true 2 | -------------------------------------------------------------------------------- /docs/.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/build 3 | **/.svelte-kit -------------------------------------------------------------------------------- /go.work: -------------------------------------------------------------------------------- 1 | go 1.20 2 | 3 | use ( 4 | ./api 5 | ./proxy 6 | ) 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /testing/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lazarcloud/pocketbase-dashbaord/testing 2 | 3 | go 1.20 4 | -------------------------------------------------------------------------------- /images/app.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazarcloud/pocketbase-dashboard/HEAD/images/app.jpeg -------------------------------------------------------------------------------- /docs/src/lib/index.js: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /web/static/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/build 3 | ./api/secure/ 4 | ./api/secure/* 5 | ./api/data/ 6 | ./api/data/* -------------------------------------------------------------------------------- /docs/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazarcloud/pocketbase-dashboard/HEAD/docs/static/favicon.png -------------------------------------------------------------------------------- /images/containers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazarcloud/pocketbase-dashboard/HEAD/images/containers.png -------------------------------------------------------------------------------- /web/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazarcloud/pocketbase-dashboard/HEAD/web/static/favicon.png -------------------------------------------------------------------------------- /web/src/lib/images/svelte-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazarcloud/pocketbase-dashboard/HEAD/web/src/lib/images/svelte-welcome.png -------------------------------------------------------------------------------- /web/src/lib/images/svelte-welcome.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazarcloud/pocketbase-dashboard/HEAD/web/src/lib/images/svelte-welcome.webp -------------------------------------------------------------------------------- /api/data/pocketbase-ADzCZJPL_details.json: -------------------------------------------------------------------------------- 1 | {"created_at":"2023-11-02T12:54:19.6042075+02:00","name":"pocketbase-ADzCZJPL","description":"Default description"} -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | password hashing 2 | pocketbase image creation with proper versioning 3 | data backup 4 | add individual cors for every project 5 | move to a database -------------------------------------------------------------------------------- /api/globals/globals.go: -------------------------------------------------------------------------------- 1 | package globals 2 | 3 | const DataFolder = "./data" 4 | 5 | const AuthFileDirectory = "./secure" 6 | const AuthFilePath = AuthFileDirectory + "/auth.json" 7 | -------------------------------------------------------------------------------- /docs/vite.config.js: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()] 6 | }); 7 | -------------------------------------------------------------------------------- /web/vite.config.js: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()] 6 | }); 7 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | .vercel 10 | .output 11 | vite.config.js.timestamp-* 12 | vite.config.ts.timestamp-* 13 | -------------------------------------------------------------------------------- /dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker build . -t monsieurlazar/lazarbase 4 | docker run -d -p 8081:80 -e ORIGIN=http://localhost:8081 --name lazar-dash -v /var/run/docker.sock:/var/run/docker.sock -v /home/pocketbase/metadata:/data --network=lazar-static monsieurlazar/lazarbase -------------------------------------------------------------------------------- /docs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-alpine AS build 2 | 3 | COPY ./docs/package*.json ./ 4 | 5 | RUN npm i 6 | 7 | COPY ./docs/ . 8 | RUN npm run build 9 | 10 | FROM busybox:latest AS runtime 11 | COPY --from=build /dist . 12 | CMD ["busybox", "httpd", "-f", "-v", "-p", "80"] -------------------------------------------------------------------------------- /web/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /docs/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /docs/src/lib/ui/index.js: -------------------------------------------------------------------------------- 1 | import HostingCalculator from "./HostingCalculator.svelte" 2 | import Navbar from "./Navbar.svelte" 3 | import Logo from "./Logo.svelte" 4 | import Github from "./Github.svelte" 5 | import BottomBar from "./BottomBar.svelte" 6 | 7 | export { HostingCalculator, Navbar, Logo, Github, BottomBar } 8 | -------------------------------------------------------------------------------- /docs/src/lib/ui/BottomBar.svelte: -------------------------------------------------------------------------------- 1 |
2 |

© 2023 PocketBase Dashboard

3 |

4 | Crafted by 5 | Lazar 6 |

7 |
8 | 9 | 17 | -------------------------------------------------------------------------------- /web/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /go.work.sum: -------------------------------------------------------------------------------- 1 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 2 | golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= 3 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 4 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 5 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 6 | -------------------------------------------------------------------------------- /api/functions/proxy.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httputil" 6 | "net/url" 7 | ) 8 | 9 | func ServeReverseProxy(target string, w http.ResponseWriter, r *http.Request) { 10 | url, _ := url.Parse(target) 11 | 12 | proxy := httputil.NewSingleHostReverseProxy(url) 13 | 14 | r.URL.Host = url.Host 15 | r.URL.Scheme = url.Scheme 16 | r.Header.Set("X-Forwarded-Host", r.Header.Get("Host")) 17 | r.Host = url.Host 18 | 19 | proxy.ServeHTTP(w, r) 20 | } 21 | -------------------------------------------------------------------------------- /docs/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 |
9 |
10 | 11 |
12 | 13 | 14 | 28 | -------------------------------------------------------------------------------- /docs/src/routes/global.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600;700&display=swap"); 2 | 3 | /* * { 4 | outline: 1px solid red; 5 | } */ 6 | 7 | :root { 8 | --accent: #00e3ba; 9 | } 10 | html { 11 | font-family: "Raleway", sans-serif; 12 | font-weight: 500; 13 | background: #fafafa; 14 | color: rgb(22, 22, 22); 15 | } 16 | body { 17 | margin: 0; 18 | padding: 0; 19 | min-height: 100vh; 20 | } 21 | 22 | *, 23 | *::before, 24 | *::after { 25 | box-sizing: border-box; 26 | } 27 | -------------------------------------------------------------------------------- /web/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from "@sveltejs/adapter-static" 2 | 3 | /** @type {import('@sveltejs/kit').Config} */ 4 | const config = { 5 | kit: { 6 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 7 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 8 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 9 | adapter: adapter(), 10 | }, 11 | } 12 | 13 | export default config 14 | -------------------------------------------------------------------------------- /docs/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from "@sveltejs/adapter-static" 2 | 3 | /** @type {import('@sveltejs/kit').Config} */ 4 | const config = { 5 | kit: { 6 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 7 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 8 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 9 | adapter: adapter(), 10 | alias: { 11 | $ui: "./src/lib/ui", 12 | }, 13 | }, 14 | } 15 | 16 | export default config 17 | -------------------------------------------------------------------------------- /docs/jsconfig.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 and https://kit.svelte.dev/docs/configuration#files 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /web/jsconfig.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 and https://kit.svelte.dev/docs/configuration#files 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /Buildpocketbase: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | ARG PB_VERSION=0.19.0 4 | 5 | RUN apk add --no-cache \ 6 | unzip \ 7 | ca-certificates 8 | 9 | # download and unzip PocketBase 10 | ADD https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_arm64.zip /tmp/pb.zip 11 | RUN unzip /tmp/pb.zip -d /pb/ 12 | 13 | # uncomment to copy the local pb_migrations dir into the image 14 | # COPY ./pb_migrations /pb/pb_migrations 15 | 16 | # uncomment to copy the local pb_hooks dir into the image 17 | # COPY ./pb_hooks /pb/pb_hooks 18 | 19 | EXPOSE 8080 20 | 21 | # start PocketBase 22 | CMD ["/pb/pocketbase", "serve", "--http=0.0.0.0:8080"] -------------------------------------------------------------------------------- /api/paths/paths.go: -------------------------------------------------------------------------------- 1 | package paths 2 | 3 | import ( 4 | "net/http" 5 | "strings" 6 | ) 7 | 8 | type PathManager struct { 9 | r *http.Request 10 | parts []string 11 | } 12 | 13 | func NewPathManager(r *http.Request) *PathManager { 14 | return &PathManager{ 15 | r: r, 16 | parts: strings.Split(r.URL.Path, "/"), 17 | } 18 | } 19 | 20 | func (pm *PathManager) GetPartsLength() int { 21 | return len(pm.parts) 22 | } 23 | func (pm *PathManager) GetFirstPart() string { 24 | return pm.parts[1] 25 | } 26 | 27 | func (pm *PathManager) GetSecondPart() string { 28 | return pm.parts[2] 29 | } 30 | func (pm *PathManager) Parts() []string { 31 | return pm.parts 32 | } 33 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json", 10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch" 11 | }, 12 | "devDependencies": { 13 | "@sveltejs/adapter-auto": "^2.0.0", 14 | "@sveltejs/kit": "^1.20.4", 15 | "svelte": "^4.0.5", 16 | "svelte-check": "^3.4.3", 17 | "typescript": "^5.0.0", 18 | "vite": "^4.4.2" 19 | }, 20 | "type": "module", 21 | "dependencies": { 22 | "@sveltejs/adapter-static": "^2.0.3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/src/routes/selfhost/+page.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | PB Dash Self-hosting 7 | 8 | 9 |

Self-hosting Guide

10 | 11 |
12 |
13 |

Getting Started

14 | 15 |

Follow the steps below to set up PocketBase Dashboard using Docker.

16 | 17 |

Prerequisites

18 | 19 |

20 | Make sure you have Docker installed on your system. If not, you can 21 | download and install it from the official Docker website. 24 |

25 |
26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /api/filesystem/filesystem.go: -------------------------------------------------------------------------------- 1 | package filesystem 2 | 3 | import "os" 4 | 5 | func PrepareFolderStructure() { 6 | CreateFolderIfNotExists("data") 7 | CreateFolderIfNotExists("data/projects") 8 | 9 | CreateFile("./data/test.txt", "Hello World\n") 10 | } 11 | 12 | func CreateFile(path string, content string) { 13 | 14 | f, err := os.Create(path) 15 | if err != nil { 16 | panic(err) 17 | } 18 | defer f.Close() 19 | 20 | _, err = f.WriteString(content) 21 | if err != nil { 22 | panic(err) 23 | } 24 | } 25 | func CreateFolder(path string) { 26 | err := os.Mkdir(path, 0755) 27 | if err != nil { 28 | panic(err) 29 | } 30 | } 31 | 32 | func CreateFolderIfNotExists(path string) { 33 | if _, err := os.Stat(path); os.IsNotExist(err) { 34 | CreateFolder(path) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dashboard", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "dev": "vite dev", 6 | "build": "vite build", 7 | "preview": "vite preview", 8 | "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json", 9 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch" 10 | }, 11 | "devDependencies": { 12 | "@fontsource/fira-mono": "^4.5.10", 13 | "@neoconfetti/svelte": "^1.0.0", 14 | "@sveltejs/adapter-auto": "^2.0.0", 15 | "@sveltejs/kit": "^1.20.4", 16 | "@types/cookie": "^0.5.1", 17 | "svelte": "^4.0.5", 18 | "svelte-check": "^3.4.3", 19 | "typescript": "^5.0.0", 20 | "vite": "^4.4.2" 21 | }, 22 | "type": "module", 23 | "dependencies": { 24 | "@sveltejs/adapter-static": "^2.0.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine AS golang-build 2 | 3 | WORKDIR /golang 4 | 5 | COPY ./api/go.mod ./api/go.sum ./ 6 | 7 | RUN go mod download 8 | 9 | COPY ./api/ ./ 10 | 11 | RUN go build -o main . 12 | 13 | RUN chmod +x ./main 14 | 15 | 16 | FROM node:alpine AS svelte 17 | 18 | WORKDIR /svelte 19 | 20 | COPY ./web/package*.json ./ 21 | 22 | RUN npm install 23 | 24 | COPY ./web/ . 25 | 26 | RUN npm run build 27 | 28 | FROM busybox:latest AS runtime 29 | 30 | ENV ORIGIN=http://localhost:8080/ 31 | ENV DEFAULT_PASSWORD=password 32 | 33 | COPY --from=golang-build ./golang/main ./main 34 | 35 | # COPY ./api/clean-data ./clean-data 36 | 37 | COPY --from=svelte ./svelte/build ./website 38 | CMD /main -origin=$ORIGIN -default_password=$DEFAULT_PASSWORD & cd website && exec busybox httpd -f -v -p 5173 -------------------------------------------------------------------------------- /web/src/lib/auth.js: -------------------------------------------------------------------------------- 1 | import { writable } from "svelte/store" 2 | 3 | const maxTime = 3600 // 1 hour 4 | function persist(key, startValue) { 5 | let value = startValue 6 | 7 | if (typeof window !== "undefined") { 8 | const storedValue = document.cookie 9 | .split("; ") 10 | .find((row) => row.startsWith(key)) 11 | value = storedValue ? JSON.parse(storedValue.split("=")[1]) : startValue 12 | } 13 | 14 | const store = writable(value) 15 | 16 | store.subscribe(($value) => { 17 | if (typeof window !== "undefined") { 18 | document.cookie = `${key}=${JSON.stringify( 19 | $value 20 | )}; max-age=${maxTime}; secure; samesite=strict` 21 | } 22 | }) 23 | 24 | return store 25 | } 26 | 27 | export const auth = persist("auth", { 28 | password: null, 29 | error: "", 30 | }) 31 | -------------------------------------------------------------------------------- /api/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lazarcloud/pocketbase-dashboard/api 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/Microsoft/go-winio v0.6.1 // indirect 7 | github.com/distribution/reference v0.5.0 // indirect 8 | github.com/docker/distribution v2.8.3+incompatible // indirect 9 | github.com/docker/docker v24.0.6+incompatible // indirect 10 | github.com/docker/go-connections v0.4.0 // indirect 11 | github.com/docker/go-units v0.5.0 // indirect 12 | github.com/gogo/protobuf v1.3.2 // indirect 13 | github.com/opencontainers/go-digest v1.0.0 // indirect 14 | github.com/opencontainers/image-spec v1.0.2 // indirect 15 | github.com/pkg/errors v0.9.1 // indirect 16 | golang.org/x/mod v0.8.0 // indirect 17 | golang.org/x/net v0.6.0 // indirect 18 | golang.org/x/sys v0.5.0 // indirect 19 | golang.org/x/tools v0.6.0 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /api/docker/compose.go: -------------------------------------------------------------------------------- 1 | package docker 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | ) 7 | 8 | func StartCompose(path string) error { 9 | cmd := exec.Command("docker compose", "-f", path, "up", "-d") 10 | cmd.Stdout = os.Stdout 11 | cmd.Stderr = os.Stderr 12 | err := cmd.Run() 13 | if err != nil { 14 | return err 15 | } 16 | return nil 17 | } 18 | 19 | func ComposeStatus(path string) error { 20 | cmd := exec.Command("docker compose", "-f", path, "ps") 21 | cmd.Stdout = os.Stdout 22 | cmd.Stderr = os.Stderr 23 | err := cmd.Run() 24 | if err != nil { 25 | return err 26 | } 27 | return nil 28 | } 29 | 30 | func KillCompose(path string) error { 31 | cmd := exec.Command("docker compose", "-f", path, "down") 32 | cmd.Stdout = os.Stdout 33 | cmd.Stderr = os.Stderr 34 | err := cmd.Run() 35 | if err != nil { 36 | return err 37 | } 38 | return nil 39 | } 40 | -------------------------------------------------------------------------------- /testing/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine as builder 2 | WORKDIR /go/src/app 3 | # COPY go.mod go.sum ./ 4 | # RUN go mod download 5 | COPY . . 6 | RUN CGO_ENABLED=0 GOOS=linux go build -o /app/main . 7 | 8 | # FROM alpine do do, start with alpine and install docker compose 9 | FROM scratch 10 | # FROM alpine 11 | 12 | # RUN apk update 13 | # RUN apk add --no-cache docker-cli python3 14 | # RUN apk add --no-cache --virtual .docker-compose-deps python3-dev libffi-dev openssl-dev gcc libc-dev make 15 | # RUN pip3 install docker-compose 16 | # RUN apk del .docker-compose-deps 17 | 18 | # FROM ubuntu:20.04 19 | # USER root 20 | # RUN apt update 21 | # RUN apt install docker -y 22 | 23 | 24 | COPY --from=builder /app/main . 25 | # COPY ./data/exampleProject /app/data/projects/exampleProject 26 | # COPY ./clean-data ./clean-data 27 | # COPY ./compose.sh /app/compose.sh 28 | # WORKDIR /app 29 | EXPOSE 8080 30 | CMD ["./main"] -------------------------------------------------------------------------------- /apiProtection.txt: -------------------------------------------------------------------------------- 1 | Use TLS (Transport Layer Security): TLS encrypts your messages while they’re in transit, protecting sensitive information like API credentials and private data1. 2 | 3 | Implement an API Token: This behaves like a password for your API. You can use the Bearer Header with the token value to come from the API and include this token as a header in every request sent via your app2. 4 | 5 | Define Permissions and Consent: This process is called authorization. You need to define who can view or modify data on your server1. 6 | 7 | Use CSRF Tokens: CSRF tokens can help prevent outsiders from calling your web services3. 8 | 9 | Force HTTPS on the site: Automatically redirect any incoming HTTP requests to HTTPS ones3. 10 | 11 | Use One-Time Use Tokens: Each page needs to send a one-time use token to the client, to be used for the page. Any request coming back sends a hashed & salted response, along with the nonce salt3. 12 | 13 | an api token that can be seen on first page load / auth system? 14 | 15 | 16 | https://github.com/pocketbase/pocketbase/discussions/672 -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npm create svelte@latest 12 | 13 | # create a new project in my-app 14 | npm create svelte@latest my-app 15 | ``` 16 | 17 | ## Developing 18 | 19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 20 | 21 | ```bash 22 | npm run dev 23 | 24 | # or start the server and open the app in a new browser tab 25 | npm run dev -- --open 26 | ``` 27 | 28 | ## Building 29 | 30 | To create a production version of your app: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | You can preview the production build with `npm run preview`. 37 | 38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 39 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npm create svelte@latest 12 | 13 | # create a new project in my-app 14 | npm create svelte@latest my-app 15 | ``` 16 | 17 | ## Developing 18 | 19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 20 | 21 | ```bash 22 | npm run dev 23 | 24 | # or start the server and open the app in a new browser tab 25 | npm run dev -- --open 26 | ``` 27 | 28 | ## Building 29 | 30 | To create a production version of your app: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | You can preview the production build with `npm run preview`. 37 | 38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 39 | -------------------------------------------------------------------------------- /docs/src/routes/roadmap/+page.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | PB Dash Roadmap 6 | 7 | 8 |

Roadmap

9 | 10 |
11 |
12 |

Our future plans for PocketBase Dashboard include:

13 | 14 |
    15 |
  • 16 | Improved User Management: Enhance user roles and permissions 17 | management features. 18 |
  • 19 |
  • 20 | Easier Self Hosting: Auto network creation and management 21 | so that hosting becomes possible with one command. 22 |
  • 23 |
  • 24 | More Secure Auth Options: Improve the security of the system 25 | with more secure auth alternatives. 26 |
  • 27 |
  • 28 | API Support: Provide an API with auth keys for creating 29 | projects programmatically. 30 |
  • 31 |
  • 32 | Docs Website: A website that helps you generate deployment 33 | code. 34 |
  • 35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /commands.txt: -------------------------------------------------------------------------------- 1 | docker build . -t monsieurlazar/pocketbase 2 | docker run --name docker-nginx -p 80:80 nginx 3 | 4 | 5 | 6 | docker build . -t dash 7 | docker build . -t proxy 8 | docker run -d -p 8080:80 --name proxy --network=lazar-static proxy 9 | docker run -d -p 69:80 --name website --network=lazar-static static 10 | docker run -d -p 8000:8080 --name dashboard --network=lazar-static dash 11 | docker run -d -p 70:8080 --name pocketbase --network=lazar-static monsieurlazar/pocketbase 12 | docker run -d -p 71:8080 --name pocketbase-lazar --network=lazar-static monsieurlazar/pocketbase 13 | docker network create lazar-static 14 | 15 | 16 | docker build . -t monsieurlazar/lazarbase 17 | docker run -d -p 8081:80 -e ORIGIN=http://localhost:8081 -e DEFAULT_PASSWORD=lazar --name lazar-dash -v /var/run/docker.sock:/var/run/docker.sock -v /home/pocketbase/metadata:/data --network=lazar-static monsieurlazar/lazarbase 18 | 19 | 20 | #my VM 21 | 22 | docker network create lazar-static 23 | docker run -d -e ORIGIN=https://pocket.lazar.lol/ --name lazar-dash -v /var/run/docker.sock:/var/run/docker.sock -v /home/pocketbase/metadata:/data --network=lazar-static monsieurlazar/pocketbase-dashboard -------------------------------------------------------------------------------- /.github/workflows/build-pocketbase.yml: -------------------------------------------------------------------------------- 1 | name: Build LazarBase Pocketbase Container 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - status/** 8 | - .github/workflows/build-pocketbase.yml 9 | - Buildpocketbase 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build-and-deploy: 14 | name: Build and Deploy 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v1 21 | - name: Set up Docker Buildx 22 | uses: docker/setup-buildx-action@v1 23 | - name: Login to DockerHub 24 | uses: docker/login-action@v1 25 | with: 26 | username: ${{ secrets.DOCKER_USERNAME }} 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | - name: Build and push 29 | uses: docker/build-push-action@v2 30 | with: 31 | context: . 32 | file: ./Buildpocketbase 33 | platforms: linux/amd64,linux/arm64 34 | push: true 35 | tags: | 36 | monsieurlazar/pocketbase:${{ github.sha }} 37 | monsieurlazar/pocketbase:latest 38 | -------------------------------------------------------------------------------- /.github/workflows/build-dashboard.yml: -------------------------------------------------------------------------------- 1 | name: Build LazarBase PocketBase Dashboard 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - api/** 8 | - web/** 9 | - .github/workflows/build-dashboard.yml 10 | - Dockerfile 11 | - .dockerignore 12 | workflow_dispatch: 13 | 14 | jobs: 15 | build-and-deploy: 16 | name: Build and Deploy 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v3 21 | - name: Set up QEMU 22 | uses: docker/setup-qemu-action@v1 23 | - name: Set up Docker Buildx 24 | uses: docker/setup-buildx-action@v1 25 | - name: Login to DockerHub 26 | uses: docker/login-action@v1 27 | with: 28 | username: ${{ secrets.DOCKER_USERNAME }} 29 | password: ${{ secrets.DOCKER_PASSWORD }} 30 | - name: Build and push 31 | uses: docker/build-push-action@v2 32 | with: 33 | context: . 34 | platforms: linux/amd64,linux/arm64 35 | push: true 36 | tags: | 37 | monsieurlazar/pocketbase-dashboard:${{ github.sha }} 38 | monsieurlazar/pocketbase-dashboard:latest 39 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Docs Website to Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - .github/workflows/deploy-docs.yml 9 | - docs/** 10 | workflow_dispatch: 11 | 12 | permissions: 13 | contents: read 14 | pages: write 15 | id-token: write 16 | 17 | concurrency: 18 | group: "pages" 19 | cancel-in-progress: false 20 | 21 | jobs: 22 | build-site: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | 28 | - name: Install Node.js 29 | uses: actions/setup-node@v4 30 | with: 31 | node-version: 18 32 | 33 | - name: Install dependencies 34 | run: cd docs && npm i 35 | 36 | - name: Setup Pages 37 | uses: actions/configure-pages@v4 38 | with: 39 | static_site_generator: "sveltekit" 40 | 41 | - name: Build site 42 | run: cd docs && npm run build 43 | 44 | - name: Upload artifact 45 | uses: actions/upload-pages-artifact@v3 46 | with: 47 | path: "docs/build/" 48 | 49 | deploy: 50 | needs: build-site 51 | runs-on: ubuntu-latest 52 | 53 | environment: 54 | name: github-pages 55 | url: ${{ steps.deployment.outputs.page_url }} 56 | 57 | steps: 58 | - name: Deploy to GitHub Pages 59 | id: deployment 60 | uses: actions/deploy-pages@v4 61 | -------------------------------------------------------------------------------- /docs/static/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/lib/ui/Github.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /docs/src/lib/ui/Navbar.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 24 | 25 | 69 | -------------------------------------------------------------------------------- /web/src/lib/images/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 9 | 16 | -------------------------------------------------------------------------------- /testing/lastworking.txt: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "net/http" 8 | "net/url" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | reverseProxy := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { 14 | fmt.Printf("[reverse proxy server] received request at: %s\n", time.Now()) 15 | 16 | // define origin server URL 17 | originServerURL, err := url.Parse("http://pocketbase:8080/") 18 | if err != nil { 19 | log.Fatal("invalid origin server URL") 20 | } 21 | 22 | // set req Host, URL and RequestURI to forward a request to the origin server 23 | req.Host = originServerURL.Host 24 | req.URL.Host = originServerURL.Host 25 | req.URL.Scheme = originServerURL.Scheme 26 | req.RequestURI = "" 27 | 28 | req.Header.Set("X-Forwarded-Host", req.Header.Get("Host")) 29 | req.Header.Set("X-Real-IP", req.RemoteAddr) // Simulate X-Real-IP header behavior 30 | req.Header.Set("X-Forwarded-For", req.RemoteAddr) 31 | req.Header.Set("X-Forwarded-Proto", req.URL.Scheme) 32 | 33 | // send a request to the origin server 34 | resp, err := http.DefaultClient.Do(req) 35 | if err != nil { 36 | rw.WriteHeader(http.StatusInternalServerError) 37 | _, _ = fmt.Fprint(rw, err) 38 | return 39 | } 40 | defer resp.Body.Close() 41 | 42 | // Copy headers from the origin server response to the client response 43 | for key, values := range resp.Header { 44 | for _, value := range values { 45 | rw.Header().Add(key, value) 46 | } 47 | } 48 | 49 | // Copy status code from the origin server response to the client response 50 | rw.WriteHeader(resp.StatusCode) 51 | 52 | // Copy response body from the origin server response to the client response 53 | _, _ = io.Copy(rw, resp.Body) 54 | }) 55 | 56 | log.Fatal(http.ListenAndServe(":8080", reverseProxy)) 57 | } 58 | -------------------------------------------------------------------------------- /web/src/routes/base.css: -------------------------------------------------------------------------------- 1 | :focus-visible { 2 | outline-color: var(--primaryColor); 3 | outline-style: solid; 4 | } 5 | 6 | html, 7 | body { 8 | line-height: var(--baseLineHeight); 9 | font-family: var(--baseFontFamily); 10 | font-size: var(--baseFontSize); 11 | color: var(--txtPrimaryColor); 12 | background: var(--bodyColor); 13 | } 14 | 15 | #app { 16 | overflow: auto; 17 | display: block; 18 | width: 100%; 19 | height: 100vh; 20 | } 21 | 22 | h1, 23 | h2, 24 | h3, 25 | h4, 26 | h5, 27 | h6 { 28 | margin: 0; 29 | font-weight: normal; 30 | } 31 | h1 { 32 | font-size: 22px; 33 | line-height: 28px; 34 | } 35 | h2 { 36 | font-size: 20px; 37 | line-height: 26px; 38 | } 39 | h3 { 40 | font-size: 19px; 41 | line-height: 24px; 42 | } 43 | h4 { 44 | font-size: 18px; 45 | line-height: 24px; 46 | } 47 | h5 { 48 | font-size: 17px; 49 | line-height: 24px; 50 | } 51 | h6 { 52 | font-size: 16px; 53 | line-height: 22px; 54 | } 55 | 56 | em { 57 | font-style: italic; 58 | } 59 | 60 | ins { 61 | color: var(--txtPrimaryColor); 62 | background: var(--successAltColor); 63 | text-decoration: none; 64 | } 65 | 66 | del { 67 | color: var(--txtPrimaryColor); 68 | background: var(--dangerAltColor); 69 | text-decoration: none; 70 | } 71 | 72 | strong { 73 | font-weight: 600; 74 | } 75 | 76 | small { 77 | font-size: var(--smFontSize); 78 | line-height: var(--smLineHeight); 79 | } 80 | 81 | sub, 82 | sup { 83 | position: relative; 84 | font-size: 0.75em; 85 | line-height: 1; 86 | } 87 | sup { 88 | vertical-align: top; 89 | } 90 | sub { 91 | vertical-align: bottom; 92 | } 93 | 94 | p { 95 | margin: 5px 0; 96 | } 97 | 98 | img { 99 | max-width: 100%; 100 | vertical-align: top; 101 | } 102 | -------------------------------------------------------------------------------- /api/docker/network.go: -------------------------------------------------------------------------------- 1 | package docker 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | 8 | "github.com/docker/docker/api/types" 9 | "github.com/docker/docker/client" 10 | "github.com/lazarcloud/lazarbase/leader/globals" 11 | ) 12 | 13 | func CheckNetwork() { 14 | cli, err := client.NewClientWithOpts(client.FromEnv) 15 | if err != nil { 16 | log.Fatal(err) 17 | } 18 | 19 | networks, err := cli.NetworkList(context.Background(), types.NetworkListOptions{}) 20 | if err != nil { 21 | log.Fatal(err) 22 | } 23 | 24 | exists := false 25 | 26 | for _, network := range networks { 27 | if network.Name == globals.NetworkName { 28 | exists = true 29 | } 30 | } 31 | 32 | if !exists { 33 | fmt.Printf("Created new network with name: %s\n", globals.NetworkName) 34 | CreateNetwork() 35 | } else { 36 | fmt.Printf("Network with name: %s already exists\n", globals.NetworkName) 37 | } 38 | } 39 | 40 | func EnsureContainerInNetwork(containerID string, networkID string) error { 41 | 42 | ctx := context.Background() 43 | 44 | cli, err := client.NewClientWithOpts(client.FromEnv) 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | // Get the container's information 49 | containerJSON, err := cli.ContainerInspect(ctx, containerID) 50 | if err != nil { 51 | return err 52 | } 53 | 54 | // Check if the container is already in the network 55 | for _, network := range containerJSON.NetworkSettings.Networks { 56 | if network.NetworkID == networkID { 57 | fmt.Printf("Container is already in network: %s\n", networkID) 58 | return nil 59 | } 60 | } 61 | 62 | // If not, connect the container to the network 63 | err = cli.NetworkConnect(ctx, networkID, containerID, nil) 64 | if err != nil { 65 | return err 66 | } 67 | 68 | fmt.Printf("Connected container: %s to network: %s\n", containerID, networkID) 69 | return nil 70 | } 71 | -------------------------------------------------------------------------------- /web/src/lib/images/svelte-logo.svg: -------------------------------------------------------------------------------- 1 | svelte-logo -------------------------------------------------------------------------------- /docs/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | PB Dash Home 6 | 7 | 8 |

Pocketbase Dashboard

9 |
10 |
11 |

12 | PocketBase Dashboard is a self-hosted solution that allows you to manage 13 | and use PocketBase for personal use. With this, you can have full control 14 | over your data and applications in a convenient and user-friendly way. 15 |

16 |
17 |
18 | 19 |
20 |
21 |
    22 |
  • 23 | 24 | Self-Hosting 25 |
  • 26 |
  • 27 | 28 | User-Friendly Interface 29 |
  • 30 |
  • 31 | 32 | Unlimited Projects 33 |
  • 34 |
35 |
36 |
37 |
38 | App Usage 42 |

Example App Usage

43 |
44 | 45 |
46 | Docker Containers 50 |

Generated Containers

51 |
52 | 53 | 85 | -------------------------------------------------------------------------------- /web/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | {#if $auth.password != null} 10 | 11 | {:else} 12 | 37 | {/if} 38 |
39 | 40 | 90 | -------------------------------------------------------------------------------- /web/src/routes/Counter.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 |
21 | 26 | 27 |
28 |
29 | 30 | {Math.floor($displayed_count)} 31 |
32 |
33 | 34 | 39 |
40 | 41 | 107 | -------------------------------------------------------------------------------- /testing/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "net/http" 8 | "net/url" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func main() { 14 | reverseProxy := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { 15 | fmt.Printf("[reverse proxy server] received request at: %s\n", time.Now()) 16 | 17 | // Handle requests to /dashboard/ 18 | if strings.HasPrefix(req.URL.Path, "/dashboard/") { 19 | // id := strings.TrimPrefix(req.URL.Path, "/dashboard/") 20 | // Construct a new URL with the pocketbase server address 21 | // req.URL.Path 22 | //remove from path /dashboard/id 23 | // newPath := strings.TrimPrefix(req.URL.Path, "/dashboard/") 24 | // pocketbaseURL := fmt.Sprintf("http://pocketbase-lazar:8080/%s", newPath) 25 | // // Parse the new URL 26 | // proxyURL, err := url.Parse(pocketbaseURL) 27 | // if err != nil { 28 | // rw.WriteHeader(http.StatusInternalServerError) 29 | // _, _ = fmt.Fprint(rw, err) 30 | // return 31 | // } 32 | // // Update the request URL with the new URL 33 | // req.URL = proxyURL 34 | newPath := strings.TrimPrefix(req.URL.Path, "/dashboard/") 35 | originServerURL, err := url.Parse("http://pocketbase-lazar:8080") 36 | fmt.Println(fmt.Sprintf("http://pocketbase-lazar:8080/%s", newPath)) 37 | if err != nil { 38 | log.Fatal("invalid origin server URL") 39 | } 40 | 41 | req.Host = originServerURL.Host 42 | req.URL.Host = originServerURL.Host 43 | req.URL.Scheme = originServerURL.Scheme 44 | req.RequestURI = "" 45 | } else { 46 | // For other requests, forward to the original server 47 | originServerURL, err := url.Parse("http://pocketbase:8080/") 48 | if err != nil { 49 | log.Fatal("invalid origin server URL") 50 | } 51 | 52 | req.Host = originServerURL.Host 53 | req.URL.Host = originServerURL.Host 54 | req.URL.Scheme = originServerURL.Scheme 55 | req.RequestURI = "" 56 | } 57 | 58 | req.Header.Set("X-Forwarded-Host", req.Host) 59 | req.Header.Set("X-Real-IP", req.RemoteAddr) 60 | req.Header.Set("X-Forwarded-For", req.RemoteAddr) 61 | req.Header.Set("X-Forwarded-Proto", req.URL.Scheme) 62 | 63 | resp, err := http.DefaultClient.Do(req) 64 | if err != nil { 65 | rw.WriteHeader(http.StatusInternalServerError) 66 | _, _ = fmt.Fprint(rw, err) 67 | return 68 | } 69 | defer resp.Body.Close() 70 | 71 | for key, values := range resp.Header { 72 | for _, value := range values { 73 | rw.Header().Add(key, value) 74 | } 75 | } 76 | 77 | rw.WriteHeader(resp.StatusCode) 78 | 79 | _, _ = io.Copy(rw, resp.Body) 80 | }) 81 | 82 | log.Fatal(http.ListenAndServe(":8080", reverseProxy)) 83 | } 84 | -------------------------------------------------------------------------------- /api/filesystem/projects.go: -------------------------------------------------------------------------------- 1 | package filesystem 2 | 3 | import ( 4 | "encoding/json" 5 | "log" 6 | "os" 7 | "path/filepath" 8 | 9 | uuid "github.com/nu7hatch/gouuid" 10 | ) 11 | 12 | func RandomId() string { 13 | u, err := uuid.NewV4() 14 | if err != nil { 15 | panic(err) 16 | } 17 | return u.String() 18 | } 19 | 20 | func GetProjectsPath() string { 21 | return "./data/projects/" 22 | } 23 | 24 | type Project struct { 25 | Name string `json:"name"` 26 | Id string `json:"id"` 27 | // add other fields here 28 | } 29 | 30 | func GetProjects() []Project { 31 | var projects []Project 32 | 33 | // Get the path to the projects directory 34 | projectsPath := GetProjectsPath() 35 | 36 | // Read all the subdirectories within the projects directory 37 | files, err := os.ReadDir(projectsPath) 38 | if err != nil { 39 | log.Fatal(err) 40 | } 41 | 42 | // Loop through all subdirectories in projects 43 | for _, f := range files { 44 | if f.IsDir() { 45 | // For each subdirectory, read the projectinfo.json file 46 | projectInfoPath := filepath.Join(projectsPath, f.Name(), "projectinfo.json") 47 | //check if file exists, if not pass to next iteration 48 | if _, err := os.Stat(projectInfoPath); os.IsNotExist(err) { 49 | continue 50 | } else { 51 | // log.Println("ProjectInfo file exists") 52 | } 53 | 54 | data, err := os.ReadFile(projectInfoPath) 55 | if err != nil { 56 | log.Fatal(err) 57 | } 58 | 59 | var projectInfo Project 60 | err = json.Unmarshal(data, &projectInfo) 61 | if err != nil { 62 | log.Fatal(err) 63 | } 64 | 65 | projects = append(projects, projectInfo) 66 | } 67 | } 68 | 69 | // Return the projects array 70 | return projects 71 | } 72 | func CreateProject(name string) string { 73 | // Generate a unique ID for the project 74 | id := RandomId() 75 | 76 | // Create a new project object 77 | project := Project{ 78 | Id: id, 79 | Name: name, 80 | } 81 | 82 | // Convert the project object to JSON 83 | projectJson, err := json.Marshal(project) 84 | if err != nil { 85 | log.Fatal(err) 86 | } 87 | 88 | // Get the path to the projects directory 89 | projectsPath := GetProjectsPath() 90 | 91 | // Create a new directory for the project 92 | projectPath := filepath.Join(projectsPath, id) 93 | err = os.Mkdir(projectPath, 0755) 94 | if err != nil { 95 | log.Fatal(err) 96 | } 97 | 98 | // Write the project JSON to a file in the new directory 99 | err = os.WriteFile(filepath.Join(projectPath, "projectinfo.json"), projectJson, 0644) 100 | if err != nil { 101 | log.Fatal(err) 102 | } 103 | 104 | // Return the ID of the new project 105 | return id 106 | } 107 | -------------------------------------------------------------------------------- /web/src/routes/Header.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 |
9 | 10 | SvelteKit 11 | 12 |
13 | 14 | 33 | 34 |
35 | 36 | GitHub 37 | 38 |
39 |
40 | 41 | 130 | -------------------------------------------------------------------------------- /docs/static/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /web/static/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /api/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "net/http" 7 | "strings" 8 | 9 | "github.com/lazarcloud/pocketbase-dashboard/api/auth" 10 | "github.com/lazarcloud/pocketbase-dashboard/api/functions" 11 | "github.com/lazarcloud/pocketbase-dashboard/api/paths" 12 | ) 13 | 14 | var origin string 15 | 16 | func enableCORSStatic(next http.HandlerFunc) http.HandlerFunc { 17 | return func(w http.ResponseWriter, r *http.Request) { 18 | w.Header().Set("Access-Control-Allow-Origin", origin) 19 | w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") 20 | w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With") 21 | 22 | if r.Method == http.MethodOptions { 23 | w.WriteHeader(http.StatusOK) 24 | return 25 | } 26 | 27 | next.ServeHTTP(w, r) 28 | } 29 | } 30 | func enableCORS(next http.HandlerFunc) http.HandlerFunc { 31 | return func(w http.ResponseWriter, r *http.Request) { 32 | w.Header().Set("Access-Control-Allow-Origin", origin) 33 | w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") 34 | w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With") 35 | 36 | if r.Method == http.MethodOptions { 37 | w.WriteHeader(http.StatusOK) 38 | return 39 | } 40 | 41 | next(w, r) 42 | } 43 | } 44 | 45 | func main() { 46 | flag.StringVar(&origin, "origin", "http://localhost:8080/", "Define website origin") 47 | defaultPassword := flag.String("default_password", "password", "Define default password") 48 | flag.Parse() 49 | 50 | fmt.Printf("Origin: %s\n", origin) 51 | 52 | err := auth.PrepareDefaultAuth(*defaultPassword) 53 | if err != nil { 54 | panic(err) 55 | } 56 | 57 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 58 | fmt.Printf("New request: %s\n", r.URL.Path) 59 | pathManager := paths.NewPathManager(r) 60 | if pathManager.GetPartsLength() >= 3 && pathManager.GetFirstPart() == "project" { 61 | targetURL := "http://pocketbase-" + pathManager.Parts()[2] + ":8080" 62 | r.URL.Path = "/" + strings.Join(pathManager.Parts()[3:], "/") 63 | functions.ServeReverseProxy(targetURL, w, r) 64 | } else if strings.HasPrefix(r.URL.Path, "/_app/immutable/") { 65 | // Add CORS headers here 66 | http.StripPrefix("/_app/immutable/", http.FileServer(http.Dir("/website/_app/immutable/"))).ServeHTTP(w, r) 67 | } else if strings.Contains(pathManager.GetFirstPart(), ".") { 68 | // Add CORS headers here 69 | http.StripPrefix("/", http.FileServer(http.Dir("/website/"))).ServeHTTP(w, r) 70 | } else { 71 | // Add CORS headers here 72 | fmt.Print("http://localhost:5173" + r.URL.Path + "\n") 73 | functions.ServeReverseProxy("http://localhost:5173"+r.URL.Path, w, r) 74 | 75 | } 76 | }) 77 | 78 | http.HandleFunc("/create", enableCORS(auth.CheckAuth(functions.CreateProject))) 79 | http.HandleFunc("/projects", enableCORS(auth.CheckAuth(functions.GetProjects))) 80 | http.HandleFunc("/stop", enableCORS(auth.CheckAuth(functions.StopProject))) 81 | http.HandleFunc("/start", enableCORS(auth.CheckAuth(functions.StartProject))) 82 | 83 | http.ListenAndServe(":80", nil) 84 | } 85 | -------------------------------------------------------------------------------- /web/src/lib/Logo.svelte: -------------------------------------------------------------------------------- 1 | 8 | 16 | 20 | 27 | 31 | 38 | 42 | 46 | 47 | -------------------------------------------------------------------------------- /docs/src/lib/ui/Logo.svelte: -------------------------------------------------------------------------------- 1 | 8 | 16 | 20 | 27 | 31 | 38 | 42 | 46 | 47 | -------------------------------------------------------------------------------- /api/auth/auth.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/lazarcloud/pocketbase-dashboard/api/functions" 10 | "github.com/lazarcloud/pocketbase-dashboard/api/globals" 11 | ) 12 | 13 | func FileExists(path string) bool { 14 | if _, err := os.Stat(path); os.IsNotExist(err) { 15 | return false 16 | } 17 | return true 18 | } 19 | 20 | func EnsurePathDirectoryExists(path string) error { 21 | err := os.MkdirAll(path, 0777) 22 | if err != nil { 23 | return err 24 | } 25 | return nil 26 | } 27 | 28 | func CheckAuth(next http.HandlerFunc) http.HandlerFunc { 29 | return func(w http.ResponseWriter, r *http.Request) { 30 | //get Authorizations Header 31 | //check if password is correct 32 | //if not return 401 33 | 34 | authHeader := r.Header.Get("Authorization") 35 | if authHeader == "" { 36 | functions.RespondWithJSON(w, http.StatusUnauthorized, map[string]string{ 37 | "errortype": "auth", 38 | "error": "Unauthorized", 39 | }) 40 | return 41 | } 42 | 43 | isBearer := authHeader[:7] == "Bearer " 44 | if !isBearer { 45 | functions.RespondWithJSON(w, http.StatusUnauthorized, map[string]string{ 46 | "errortype": "auth", 47 | "error": "Unauthorized, use Bearer Auth", 48 | }) 49 | return 50 | } 51 | 52 | token := authHeader[7:] 53 | 54 | type Password struct { 55 | Password string `json:"password"` 56 | } 57 | 58 | passwordJSON, err := os.ReadFile(globals.AuthFilePath) 59 | if err != nil { 60 | functions.RespondWithJSON(w, http.StatusUnauthorized, map[string]string{ 61 | "errortype": "auth", 62 | "error": fmt.Sprintf("failed reading file: %s, try recreating the dashboard container.", err.Error()), 63 | }) 64 | return 65 | } 66 | 67 | passwordData := Password{} 68 | err = json.Unmarshal(passwordJSON, &passwordData) 69 | if err != nil { 70 | functions.RespondWithJSON(w, http.StatusUnauthorized, map[string]string{ 71 | "errortype": "auth", 72 | "error": fmt.Sprintf("error unmarshalling json: %s", err.Error()), 73 | }) 74 | return 75 | } 76 | 77 | password := passwordData.Password 78 | 79 | if err != nil { 80 | functions.RespondWithJSON(w, http.StatusUnauthorized, map[string]string{ 81 | "errortype": "auth", 82 | "error": err.Error(), 83 | }) 84 | return 85 | } 86 | 87 | if string(password) != token { 88 | functions.RespondWithJSON(w, http.StatusUnauthorized, map[string]string{ 89 | "errortype": "auth", 90 | "error": "Unauthorized, wrong password.", 91 | }) 92 | return 93 | } 94 | 95 | next(w, r) 96 | } 97 | } 98 | 99 | func WriteJSONToFile(path string, data []byte) error { 100 | file, err := os.OpenFile( 101 | path, 102 | os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 103 | 0666, 104 | ) 105 | if err != nil { 106 | return err 107 | } 108 | defer file.Close() 109 | 110 | _, err = file.Write(data) 111 | if err != nil { 112 | return err 113 | } 114 | 115 | return nil 116 | } 117 | 118 | func PrepareDefaultAuth(defaultPassword string) error { 119 | err := EnsurePathDirectoryExists(globals.AuthFileDirectory) 120 | if err != nil { 121 | return err 122 | } 123 | if !FileExists(globals.AuthFilePath) { 124 | err = WriteJSONToFile(globals.AuthFilePath, []byte(fmt.Sprintf(`{"password": "%s"}`, defaultPassword))) 125 | if err != nil { 126 | return err 127 | } 128 | } 129 | return nil 130 | } 131 | -------------------------------------------------------------------------------- /web/src/routes/styles.css: -------------------------------------------------------------------------------- 1 | @import "@fontsource/fira-mono"; 2 | 3 | :root { 4 | --baseFontFamily: "Source Sans Pro", sans-serif, emoji; 5 | --monospaceFontFamily: "Ubuntu Mono", monospace, emoji; 6 | --iconFontFamily: "remixicon"; 7 | --txtPrimaryColor: #16161a; 8 | --txtHintColor: #666f75; 9 | --txtDisabledColor: #a0a6ac; 10 | --primaryColor: #16161a; 11 | --bodyColor: #f8f9fa; 12 | --baseColor: #ffffff; 13 | --baseAlt1Color: #e4e9ec; 14 | --baseAlt2Color: #d7dde4; 15 | --baseAlt3Color: #c6cdd7; 16 | --baseAlt4Color: #a5b0c0; 17 | --infoColor: #5499e8; 18 | --infoAltColor: #cee2f8; 19 | --successColor: #32ad84; 20 | --successAltColor: #c4eedc; 21 | --dangerColor: #e34562; 22 | --dangerAltColor: #f7cad2; 23 | --warningColor: #ff944d; 24 | --warningAltColor: #ffd4b8; 25 | --overlayColor: rgba(53, 71, 104, 0.28); 26 | --tooltipColor: rgba(0, 0, 0, 0.85); 27 | --shadowColor: rgba(0, 0, 0, 0.06); 28 | --baseFontSize: 14.5px; 29 | --xsFontSize: 12px; 30 | --smFontSize: 13px; 31 | --lgFontSize: 15px; 32 | --xlFontSize: 16px; 33 | --baseLineHeight: 22px; 34 | --smLineHeight: 16px; 35 | --lgLineHeight: 24px; 36 | --inputHeight: 34px; 37 | --btnHeight: 40px; 38 | --xsBtnHeight: 22px; 39 | --smBtnHeight: 30px; 40 | --lgBtnHeight: 54px; 41 | --baseSpacing: 30px; 42 | --xsSpacing: 15px; 43 | --smSpacing: 20px; 44 | --lgSpacing: 50px; 45 | --xlSpacing: 60px; 46 | --wrapperWidth: 850px; 47 | --smWrapperWidth: 420px; 48 | --lgWrapperWidth: 1200px; 49 | --appSidebarWidth: 75px; 50 | --pageSidebarWidth: 230px; 51 | --baseAnimationSpeed: 0.15s; 52 | --activeAnimationSpeed: 70ms; 53 | --entranceAnimationSpeed: 0.25s; 54 | --baseRadius: 4px; 55 | --lgRadius: 12px; 56 | --btnRadius: 4px; 57 | --accent-color: var(--primaryColor); 58 | } 59 | *, 60 | *::before, 61 | *::after { 62 | box-sizing: border-box; 63 | } 64 | body { 65 | min-height: 100vh; 66 | margin: 0; 67 | background-attachment: fixed; 68 | background-color: var(--color-bg-1); 69 | background-size: 100vw 100vh; 70 | background-image: radial-gradient( 71 | 50% 50% at 50% 50%, 72 | rgba(255, 255, 255, 0.75) 0%, 73 | rgba(255, 255, 255, 0) 100% 74 | ), 75 | linear-gradient( 76 | 180deg, 77 | var(--color-bg-0) 0%, 78 | var(--color-bg-1) 15%, 79 | var(--color-bg-2) 50% 80 | ); 81 | } 82 | 83 | h1, 84 | h2, 85 | p { 86 | font-weight: 400; 87 | } 88 | 89 | p { 90 | line-height: 1.5; 91 | } 92 | 93 | a { 94 | color: var(--color-theme-1); 95 | text-decoration: none; 96 | } 97 | 98 | a:hover { 99 | text-decoration: underline; 100 | } 101 | 102 | h1 { 103 | font-size: 2rem; 104 | text-align: center; 105 | } 106 | 107 | h2 { 108 | font-size: 1rem; 109 | } 110 | 111 | pre { 112 | font-size: 16px; 113 | font-family: var(--font-mono); 114 | background-color: rgba(255, 255, 255, 0.45); 115 | border-radius: 3px; 116 | box-shadow: 2px 2px 6px rgb(255 255 255 / 25%); 117 | padding: 0.5em; 118 | overflow-x: auto; 119 | color: var(--color-text); 120 | } 121 | 122 | .text-column { 123 | display: flex; 124 | max-width: 48rem; 125 | flex: 0.6; 126 | flex-direction: column; 127 | justify-content: center; 128 | margin: 0 auto; 129 | } 130 | 131 | input, 132 | button { 133 | font-size: inherit; 134 | font-family: inherit; 135 | } 136 | 137 | button:focus:not(:focus-visible) { 138 | outline: none; 139 | } 140 | 141 | @media (min-width: 720px) { 142 | h1 { 143 | font-size: 2.4rem; 144 | } 145 | } 146 | 147 | .visually-hidden { 148 | border: 0; 149 | clip: rect(0 0 0 0); 150 | height: auto; 151 | margin: 0; 152 | overflow: hidden; 153 | padding: 0; 154 | position: absolute; 155 | width: 1px; 156 | white-space: nowrap; 157 | } 158 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PocketBase Dashboard 2 | 3 | > **Status:** Archived - no longer maintained. Feel free to fork it. 4 | 5 | For a more up-to-date guide use the [official website](https://pocketbase.bylazar.com). 6 | 7 | [PocketBase Dashboard](https://pocketbase.bylazar.com) is a self-hosted solution that allows you to manage and use PocketBase for personal use. With this, you can have full control over your data and applications in a convenient and user-friendly way. 8 | 9 | ![App Usage](https://github.com/lazarcloud/pocketbase-dashboard/blob/main/images/app.jpeg?raw=true) 10 | Example App Usage 11 | ![Docker Containers](https://github.com/lazarcloud/pocketbase-dashboard/blob/main/images/containers.png?raw=true) 12 | Generated Containers 13 | 14 | ## Features 15 | 16 | - **Self-Hosting**: Host PocketBase Dashboard on your own server, ensuring privacy and security. 17 | - **User-Friendly Interface**: Easy-to-use dashboard for managing your PocketBase instances. 18 | 19 | ## Getting Started 20 | 21 | Follow the steps below to set up PocketBase Dashboard using Docker. 22 | 23 | ### Prerequisites 24 | 25 | Make sure you have Docker installed on your system. If not, you can download and install it from the [official Docker website](https://www.docker.com/get-started). 26 | 27 | ### Self-Hosting Guide 28 | 29 | For more help check out [PB Dash Self-hosting Guide](https://pocketbase.bylazar.com/selfhost). 30 | 1. Create the pocketbase-dashboard docker network 31 | 32 | ```bash 33 | docker network create lazar-static 34 | ``` 35 | 36 | 2. Create a `docker-compose.yml` file with the following content: 37 | 38 | ```yaml 39 | version: '3.8' 40 | services: 41 | lazar-dash: 42 | image: monsieurlazar/pocketbase-dashboard 43 | container_name: lazar-dash 44 | environment: 45 | - ORIGIN=https://pocket.example.com/ 46 | - DEFAULT_PASSWORD=example //defaults to password 47 | volumes: 48 | - /var/run/docker.sock:/var/run/docker.sock 49 | - /home/pocketbase/metadata:/data 50 | networks: 51 | - lazar-static 52 | - lazar-network 53 | restart: always 54 | 55 | networks: 56 | lazar-static: 57 | external: true 58 | lazar-network: 59 | external: true 60 | ``` 61 | 3. Or you can use a docker run command. 62 | 63 | ```bash 64 | docker run -d -p 8081:80 -e ORIGIN=http://localhost:8081 -e DEFAULT_PASSWORD=example --name lazar-dash -v /var/run/docker.sock:/var/run/docker.sock -v /home/pocketbase/metadata:/data --network=lazar-static monsieurlazar/pocketbase-dashboard 65 | ``` 66 | 67 | 4. Start the PocketBase Dashboard container using Docker Compose: 68 | 69 | ```bash 70 | docker-compose up -d 71 | ``` 72 | 73 | This will pull the necessary Docker image and start the PocketBase Dashboard container in the background. 74 | 75 | 5. Access PocketBase Dashboard in your web browser by navigating to `http://your-server-ip:port` (replace `your-server-ip` and `port` with your server's IP address and the port you specified in the `docker-compose.yml` file). 76 | 77 | 6. Log in using the default credentials: 78 | 79 | - **Password:** password 80 | 81 | ## Roadmap 82 | 83 | Our future plans for PocketBase Dashboard include: 84 | 85 | - **Improved User Management**: Enhance user roles and permissions management features. 86 | - **Easier self hosting**: Auto network creation and management so that hosting becomes possible with one command. 87 | - **More Secury Auth Options**: Improve the security of the system with more secure auth alternatives. 88 | - **API Support**: Provide an api with auth keys for creating projects programatically. 89 | - **Docs Website**: A website that helps you generate deployment code. 90 | 91 | 92 | 93 | --- 94 | 95 | **Note:** Please ensure that you follow best practices for security and server management while self-hosting PocketBase Dashboard. 96 | -------------------------------------------------------------------------------- /api/docker/docker.go: -------------------------------------------------------------------------------- 1 | package docker 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | 9 | "github.com/docker/docker/api/types" 10 | "github.com/docker/docker/api/types/container" 11 | "github.com/docker/docker/client" 12 | "github.com/docker/go-connections/nat" 13 | "github.com/lazarcloud/lazarbase/leader/globals" 14 | ) 15 | 16 | func PrepareContainers() { 17 | 18 | CheckDashboard() 19 | 20 | CheckNetwork() 21 | 22 | containerID, err := GetMyCurrentContainerId() 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | 27 | err = EnsureContainerInNetwork(containerID, globals.NetworkName) 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | 32 | } 33 | 34 | func PullImage(image string) { 35 | cli, err := client.NewClientWithOpts(client.FromEnv) 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | 40 | out, err := cli.ImagePull(context.Background(), image, types.ImagePullOptions{}) 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | 45 | defer out.Close() 46 | } 47 | 48 | func CheckDashboard() { 49 | 50 | cli, err := client.NewClientWithOpts(client.FromEnv) 51 | if err != nil { 52 | log.Fatal(err) 53 | } 54 | 55 | containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | 60 | exists := false 61 | 62 | for _, container := range containers { 63 | fmt.Println(container.Names) 64 | if container.Names[0] == "/lazarbase-dashboard" { 65 | exists = true 66 | } 67 | } 68 | 69 | if !exists { 70 | fmt.Println("Creating new container") 71 | CreateDashboard() 72 | } else { 73 | fmt.Println("Container already exists") 74 | } 75 | 76 | } 77 | 78 | func CreateNetwork() { 79 | cli, err := client.NewClientWithOpts(client.FromEnv) 80 | if err != nil { 81 | log.Fatal(err) 82 | } 83 | 84 | resp, err := cli.NetworkCreate(context.Background(), "lazarbase-network", types.NetworkCreate{}) 85 | if err != nil { 86 | log.Fatal(err) 87 | } 88 | 89 | fmt.Println(resp.ID) 90 | } 91 | func CreateDashboard() { 92 | // create a new container with name lazarbase-dashboard 93 | // pullImage("lazarbase-dashboard") 94 | cli, err := client.NewClientWithOpts(client.FromEnv) 95 | if err != nil { 96 | log.Fatal(err) 97 | } 98 | resp, err := cli.ContainerCreate( 99 | context.Background(), 100 | &container.Config{ 101 | Image: globals.DashboardImage, 102 | ExposedPorts: nat.PortSet{ 103 | "80/tcp": struct{}{}, 104 | }, 105 | }, 106 | &container.HostConfig{ 107 | PortBindings: nat.PortMap{ 108 | "80/tcp": []nat.PortBinding{ 109 | { 110 | HostIP: "0.0.0.0", 111 | HostPort: "8081", 112 | }, 113 | }, 114 | }, 115 | NetworkMode: container.NetworkMode("lazarbase-network"), 116 | }, nil, nil, "lazarbase-dashboard", 117 | ) 118 | if err != nil { 119 | log.Fatal(err) 120 | } 121 | 122 | err = cli.NetworkConnect(context.Background(), "lazarbase-network", resp.ID, nil) 123 | if err != nil { 124 | log.Fatal(err) 125 | } 126 | 127 | // Start the container 128 | err = cli.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{}) 129 | if err != nil { 130 | log.Fatal(err) 131 | } 132 | } 133 | 134 | func GetContainers(w http.ResponseWriter, r *http.Request) { 135 | cli, err := client.NewClientWithOpts(client.FromEnv) 136 | if err != nil { 137 | http.Error(w, err.Error(), http.StatusInternalServerError) 138 | return 139 | } 140 | 141 | containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) 142 | if err != nil { 143 | http.Error(w, err.Error(), http.StatusInternalServerError) 144 | return 145 | } 146 | 147 | for _, container := range containers { 148 | fmt.Fprintln(w, container.ID) 149 | } 150 | } 151 | func GetMyCurrentContainerId() (string, error) { 152 | cli, err := client.NewClientWithOpts(client.FromEnv) 153 | if err != nil { 154 | return "", err 155 | } 156 | 157 | container, err := cli.ContainerInspect(context.Background(), "/lazarbase-leader") 158 | if err != nil { 159 | return "", err 160 | } 161 | 162 | return container.ID, nil 163 | } 164 | -------------------------------------------------------------------------------- /api/go.sum: -------------------------------------------------------------------------------- 1 | github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= 2 | github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= 3 | github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= 4 | github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= 5 | github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= 6 | github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 7 | github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= 8 | github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 9 | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= 10 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= 11 | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= 12 | github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 13 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 14 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 15 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 16 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 17 | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 18 | github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= 19 | github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= 20 | github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= 21 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 22 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 23 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 24 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 25 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 26 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 27 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 28 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 29 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 30 | golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= 31 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 32 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 33 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 34 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 35 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 36 | golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= 37 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 38 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 39 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 40 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 41 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 42 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 43 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 44 | golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= 45 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 46 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 47 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 48 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 49 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 50 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 51 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 52 | golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= 53 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 54 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 55 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 56 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 57 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 58 | -------------------------------------------------------------------------------- /docs/src/lib/ui/HostingCalculator.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 |
12 |

Choose your hosting method

13 | 14 |
15 | 22 | 23 | 30 | 31 |
32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | 48 |
49 |

Create docker network.

50 |
docker network create lazar-static
51 | {#if method == "dockerRun"} 52 |

Run with a docker run command.

53 |

54 | docker run -d -p 8081:80 -e ORIGIN={serverOrigin} -e DEFAULT_PASSWORD={password} 55 | --name 56 | {containerName} -v /var/run/docker.sock:/var/run/docker.sock -v {storagePath}:/data 57 | --network=lazar-static {imageName} 58 |

59 | {:else if method == "dockerCompose"} 60 |

Run with a docker compose file.

61 |
62 | 63 | version: "3.8" 64 |
65 | 66 | services: 67 |
68 | 69 | lazar-dash: 70 |
71 | 72 | image: 73 | {imageName} 74 |
75 | 76 | container_name: 77 | {containerName} 78 |
79 | 80 | environment: 81 |
82 | 83 | - ORIGIN={serverOrigin} 84 |
85 | 86 | - DEFAULT_PASSWORD={password} 87 | //defaults to password 88 |
89 | 90 | volumes: 91 |
92 | 93 | - /var/run/docker.sock:/var/run/docker.sock 94 |
95 | 96 | - {storagePath}:/data 97 |
98 | 99 | networks: 100 |
101 | 102 | - lazar-static 103 |
104 | 105 | restart: always 106 |
107 |
108 | 109 | networks: 110 |
111 | 112 | lazar-static: 113 |
114 | 115 | external: true 116 |
117 |
118 | {/if} 119 |
120 |
121 | 122 | 223 | -------------------------------------------------------------------------------- /api/functions/projects.go: -------------------------------------------------------------------------------- 1 | package functions 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "net/http" 8 | "os" 9 | "path/filepath" 10 | "strings" 11 | "time" 12 | 13 | "github.com/docker/docker/api/types" 14 | "github.com/docker/docker/api/types/container" 15 | "github.com/docker/docker/client" 16 | "github.com/lazarcloud/pocketbase-dashboard/api/globals" 17 | ) 18 | 19 | type ContainerDetails struct { 20 | CreatedAt time.Time `json:"created_at"` 21 | Name string `json:"name"` 22 | Description string `json:"description"` 23 | } 24 | 25 | func RespondWithJSON(w http.ResponseWriter, statusCode int, data interface{}) { 26 | w.Header().Set("Content-Type", "application/json") 27 | w.WriteHeader(statusCode) 28 | err := json.NewEncoder(w).Encode(data) 29 | if err != nil { 30 | http.Error(w, err.Error(), http.StatusInternalServerError) 31 | } 32 | } 33 | 34 | func GetProjects(w http.ResponseWriter, r *http.Request) { 35 | cli, err := client.NewClientWithOpts(client.FromEnv) 36 | if err != nil { 37 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 38 | "message": "Error creating Docker client", 39 | "error": err.Error(), 40 | }) 41 | return 42 | } 43 | // Get list of all containers 44 | containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{ 45 | All: true, 46 | }) 47 | if err != nil { 48 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 49 | "message": "Error getting container list", 50 | "error": err.Error(), 51 | }) 52 | return 53 | } 54 | 55 | // Filter containers whose names start with "pocketbase-" 56 | var pocketbaseContainers []map[string]interface{} 57 | for _, container := range containers { 58 | if strings.HasPrefix(container.Names[0], "/pocketbase-") && container.NetworkSettings.Networks["lazar-static"] != nil { 59 | containerInfo := map[string]interface{}{ 60 | "Name": container.Names[0][1:], // Remove leading '/' 61 | "Status": container.State, 62 | } 63 | 64 | // Check if details file exists, if not, create one with default values 65 | detailsFilePath := filepath.Join(globals.DataFolder, container.Names[0][1:]+"_details.json") 66 | _, err := os.Stat(detailsFilePath) 67 | if os.IsNotExist(err) { 68 | details := ContainerDetails{ 69 | CreatedAt: time.Now(), 70 | Name: container.Names[0][1:], 71 | Description: "Default description", 72 | } 73 | jsonBytes, _ := json.Marshal(details) 74 | os.WriteFile(detailsFilePath, jsonBytes, 0644) 75 | } 76 | 77 | // Read details from the file and append to the response 78 | detailsBytes, err := os.ReadFile(detailsFilePath) 79 | if err == nil { 80 | var details ContainerDetails 81 | json.Unmarshal(detailsBytes, &details) 82 | containerInfo["Details"] = details 83 | } 84 | 85 | pocketbaseContainers = append(pocketbaseContainers, containerInfo) 86 | } 87 | } 88 | 89 | // Convert the container list to JSON and send it as the response 90 | jsonBytes, err := json.Marshal(pocketbaseContainers) 91 | if err != nil { 92 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 93 | "message": "Error converting container list to JSON", 94 | "error": err.Error(), 95 | }) 96 | return 97 | } 98 | 99 | w.Header().Set("Content-Type", "application/json") 100 | w.Write(jsonBytes) 101 | } 102 | func CreateProject(w http.ResponseWriter, r *http.Request) { 103 | 104 | id := r.URL.Query().Get("slug") 105 | if id == "" { 106 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 107 | "message": "Provide a slug wirh ?slug=", 108 | "error": "No slug provided", 109 | }) 110 | return 111 | } 112 | 113 | detailsFilePath := filepath.Join(globals.DataFolder, "pocketbase-"+id+"_details.json") 114 | _, err := os.Stat(detailsFilePath) 115 | if os.IsExist(err) { 116 | os.Remove(detailsFilePath) 117 | } 118 | 119 | cli, err := client.NewClientWithOpts(client.FromEnv) 120 | if err != nil { 121 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 122 | "message": "Error creating Docker client", 123 | "error": err.Error(), 124 | }) 125 | return 126 | } 127 | 128 | volumeMapping := fmt.Sprintf("/home/pocketbase/projects/%s:/pb/pb_data", id) 129 | resp, err := cli.ContainerCreate( 130 | context.Background(), 131 | &container.Config{ 132 | Image: "monsieurlazar/pocketbase", 133 | }, 134 | &container.HostConfig{ 135 | Binds: []string{volumeMapping}, 136 | }, nil, nil, "pocketbase-"+id, 137 | ) 138 | if err != nil { 139 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 140 | "message": "Error creating container", 141 | "error": err.Error(), 142 | }) 143 | return 144 | } 145 | 146 | err = cli.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{}) 147 | if err != nil { 148 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 149 | "message": "Error starting container", 150 | "error": err.Error(), 151 | }) 152 | return 153 | } 154 | 155 | err = cli.NetworkConnect(context.Background(), "lazar-static", resp.ID, nil) 156 | if err != nil { 157 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 158 | "message": "Error connecting container to network", 159 | "error": err.Error(), 160 | }) 161 | return 162 | } 163 | 164 | fmt.Println(resp.ID) 165 | RespondWithJSON(w, http.StatusOK, map[string]string{ 166 | "message": "Container created successfully", 167 | "id": resp.ID, 168 | }) 169 | } 170 | 171 | func StopProject(w http.ResponseWriter, r *http.Request) { 172 | id := r.URL.Query().Get("slug") 173 | if id == "" { 174 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 175 | "message": "Provide a slug wirh ?slug=", 176 | "error": "No slug provided", 177 | }) 178 | return 179 | } 180 | cli, err := client.NewClientWithOpts(client.FromEnv) 181 | if err != nil { 182 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 183 | "message": "Error creating Docker client", 184 | "error": err.Error(), 185 | }) 186 | return 187 | } 188 | 189 | // Stop the container with the given ID 190 | err = cli.ContainerStop(context.Background(), "pocketbase-"+id, container.StopOptions{}) 191 | if err != nil { 192 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 193 | "message": "Error stopping container", 194 | "error": err.Error(), 195 | }) 196 | return 197 | } 198 | 199 | RespondWithJSON(w, http.StatusOK, map[string]string{ 200 | "message": "Container stopped successfully", 201 | "id": "pocketbase-" + id, 202 | }) 203 | 204 | } 205 | 206 | func StartProject(w http.ResponseWriter, r *http.Request) { 207 | id := r.URL.Query().Get("slug") 208 | if id == "" { 209 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 210 | "message": "Provide a slug wirh ?slug=", 211 | "error": "No slug provided", 212 | }) 213 | return 214 | } 215 | cli, err := client.NewClientWithOpts(client.FromEnv) 216 | if err != nil { 217 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 218 | "message": "Error creating Docker client", 219 | "error": err.Error(), 220 | }) 221 | return 222 | } 223 | 224 | // Start the container with the given ID 225 | err = cli.ContainerStart(context.Background(), "pocketbase-"+id, types.ContainerStartOptions{}) 226 | if err != nil { 227 | RespondWithJSON(w, http.StatusInternalServerError, map[string]string{ 228 | "message": "Error starting container", 229 | "error": err.Error(), 230 | }) 231 | return 232 | } 233 | 234 | RespondWithJSON(w, http.StatusOK, map[string]string{ 235 | "message": "Container started successfully", 236 | "id": "pocketbase-" + id, 237 | }) 238 | } 239 | -------------------------------------------------------------------------------- /web/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 82 | 83 |
84 | 89 | 90 |
91 | 92 | 96 |
97 |
98 |
99 | {#if baseURL != null} 100 | {#if projectsData == ""} 101 |

Loading...

102 | {:else if projectsData == null} 103 |

No projects found

104 | {:else} 105 | {#each projectsData as project} 106 |
107 |

{project.Name} - {project.Status}

108 |

Project description

109 |

Created: 2021-01-01

110 |

111 | API URL: {window.location.href}project/{project.Name.split( 112 | "pocketbase-" 113 | )[1]}/api/ 114 |

115 |

116 | Dashnoard URL: {window.location.href}project/{project.Name.split( 117 | "pocketbase-" 118 | )[1]}/_/ 119 |

120 |
121 |
122 | 127 | {#if project.Status == "running"} 128 | 133 | {:else if project.Status == "stopped" || project.Status == "exited"} 134 | 139 | {/if} 140 |
141 |
142 | {/each} 143 | {/if} 144 | {:else} 145 |

Loading...

146 | {/if} 147 |
148 | {#if showPopup} 149 |
{ 152 | showPopup = false 153 | }} 154 | /> 155 | 194 | {/if} 195 | 196 | 289 | -------------------------------------------------------------------------------- /docs/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "docs", 9 | "version": "0.0.1", 10 | "dependencies": { 11 | "@sveltejs/adapter-static": "^2.0.3" 12 | }, 13 | "devDependencies": { 14 | "@sveltejs/adapter-auto": "^2.0.0", 15 | "@sveltejs/kit": "^1.20.4", 16 | "svelte": "^4.0.5", 17 | "svelte-check": "^3.4.3", 18 | "typescript": "^5.0.0", 19 | "vite": "^4.4.2" 20 | } 21 | }, 22 | "node_modules/@ampproject/remapping": { 23 | "version": "2.2.1", 24 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", 25 | "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", 26 | "dependencies": { 27 | "@jridgewell/gen-mapping": "^0.3.0", 28 | "@jridgewell/trace-mapping": "^0.3.9" 29 | }, 30 | "engines": { 31 | "node": ">=6.0.0" 32 | } 33 | }, 34 | "node_modules/@esbuild/android-arm": { 35 | "version": "0.18.20", 36 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", 37 | "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", 38 | "cpu": [ 39 | "arm" 40 | ], 41 | "optional": true, 42 | "os": [ 43 | "android" 44 | ], 45 | "engines": { 46 | "node": ">=12" 47 | } 48 | }, 49 | "node_modules/@esbuild/android-arm64": { 50 | "version": "0.18.20", 51 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", 52 | "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", 53 | "cpu": [ 54 | "arm64" 55 | ], 56 | "optional": true, 57 | "os": [ 58 | "android" 59 | ], 60 | "engines": { 61 | "node": ">=12" 62 | } 63 | }, 64 | "node_modules/@esbuild/android-x64": { 65 | "version": "0.18.20", 66 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", 67 | "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", 68 | "cpu": [ 69 | "x64" 70 | ], 71 | "optional": true, 72 | "os": [ 73 | "android" 74 | ], 75 | "engines": { 76 | "node": ">=12" 77 | } 78 | }, 79 | "node_modules/@esbuild/darwin-arm64": { 80 | "version": "0.18.20", 81 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", 82 | "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", 83 | "cpu": [ 84 | "arm64" 85 | ], 86 | "optional": true, 87 | "os": [ 88 | "darwin" 89 | ], 90 | "engines": { 91 | "node": ">=12" 92 | } 93 | }, 94 | "node_modules/@esbuild/darwin-x64": { 95 | "version": "0.18.20", 96 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", 97 | "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", 98 | "cpu": [ 99 | "x64" 100 | ], 101 | "optional": true, 102 | "os": [ 103 | "darwin" 104 | ], 105 | "engines": { 106 | "node": ">=12" 107 | } 108 | }, 109 | "node_modules/@esbuild/freebsd-arm64": { 110 | "version": "0.18.20", 111 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", 112 | "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", 113 | "cpu": [ 114 | "arm64" 115 | ], 116 | "optional": true, 117 | "os": [ 118 | "freebsd" 119 | ], 120 | "engines": { 121 | "node": ">=12" 122 | } 123 | }, 124 | "node_modules/@esbuild/freebsd-x64": { 125 | "version": "0.18.20", 126 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", 127 | "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", 128 | "cpu": [ 129 | "x64" 130 | ], 131 | "optional": true, 132 | "os": [ 133 | "freebsd" 134 | ], 135 | "engines": { 136 | "node": ">=12" 137 | } 138 | }, 139 | "node_modules/@esbuild/linux-arm": { 140 | "version": "0.18.20", 141 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", 142 | "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", 143 | "cpu": [ 144 | "arm" 145 | ], 146 | "optional": true, 147 | "os": [ 148 | "linux" 149 | ], 150 | "engines": { 151 | "node": ">=12" 152 | } 153 | }, 154 | "node_modules/@esbuild/linux-arm64": { 155 | "version": "0.18.20", 156 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", 157 | "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", 158 | "cpu": [ 159 | "arm64" 160 | ], 161 | "optional": true, 162 | "os": [ 163 | "linux" 164 | ], 165 | "engines": { 166 | "node": ">=12" 167 | } 168 | }, 169 | "node_modules/@esbuild/linux-ia32": { 170 | "version": "0.18.20", 171 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", 172 | "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", 173 | "cpu": [ 174 | "ia32" 175 | ], 176 | "optional": true, 177 | "os": [ 178 | "linux" 179 | ], 180 | "engines": { 181 | "node": ">=12" 182 | } 183 | }, 184 | "node_modules/@esbuild/linux-loong64": { 185 | "version": "0.18.20", 186 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", 187 | "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", 188 | "cpu": [ 189 | "loong64" 190 | ], 191 | "optional": true, 192 | "os": [ 193 | "linux" 194 | ], 195 | "engines": { 196 | "node": ">=12" 197 | } 198 | }, 199 | "node_modules/@esbuild/linux-mips64el": { 200 | "version": "0.18.20", 201 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", 202 | "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", 203 | "cpu": [ 204 | "mips64el" 205 | ], 206 | "optional": true, 207 | "os": [ 208 | "linux" 209 | ], 210 | "engines": { 211 | "node": ">=12" 212 | } 213 | }, 214 | "node_modules/@esbuild/linux-ppc64": { 215 | "version": "0.18.20", 216 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", 217 | "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", 218 | "cpu": [ 219 | "ppc64" 220 | ], 221 | "optional": true, 222 | "os": [ 223 | "linux" 224 | ], 225 | "engines": { 226 | "node": ">=12" 227 | } 228 | }, 229 | "node_modules/@esbuild/linux-riscv64": { 230 | "version": "0.18.20", 231 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", 232 | "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", 233 | "cpu": [ 234 | "riscv64" 235 | ], 236 | "optional": true, 237 | "os": [ 238 | "linux" 239 | ], 240 | "engines": { 241 | "node": ">=12" 242 | } 243 | }, 244 | "node_modules/@esbuild/linux-s390x": { 245 | "version": "0.18.20", 246 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", 247 | "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", 248 | "cpu": [ 249 | "s390x" 250 | ], 251 | "optional": true, 252 | "os": [ 253 | "linux" 254 | ], 255 | "engines": { 256 | "node": ">=12" 257 | } 258 | }, 259 | "node_modules/@esbuild/linux-x64": { 260 | "version": "0.18.20", 261 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", 262 | "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", 263 | "cpu": [ 264 | "x64" 265 | ], 266 | "optional": true, 267 | "os": [ 268 | "linux" 269 | ], 270 | "engines": { 271 | "node": ">=12" 272 | } 273 | }, 274 | "node_modules/@esbuild/netbsd-x64": { 275 | "version": "0.18.20", 276 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", 277 | "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", 278 | "cpu": [ 279 | "x64" 280 | ], 281 | "optional": true, 282 | "os": [ 283 | "netbsd" 284 | ], 285 | "engines": { 286 | "node": ">=12" 287 | } 288 | }, 289 | "node_modules/@esbuild/openbsd-x64": { 290 | "version": "0.18.20", 291 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", 292 | "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", 293 | "cpu": [ 294 | "x64" 295 | ], 296 | "optional": true, 297 | "os": [ 298 | "openbsd" 299 | ], 300 | "engines": { 301 | "node": ">=12" 302 | } 303 | }, 304 | "node_modules/@esbuild/sunos-x64": { 305 | "version": "0.18.20", 306 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", 307 | "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", 308 | "cpu": [ 309 | "x64" 310 | ], 311 | "optional": true, 312 | "os": [ 313 | "sunos" 314 | ], 315 | "engines": { 316 | "node": ">=12" 317 | } 318 | }, 319 | "node_modules/@esbuild/win32-arm64": { 320 | "version": "0.18.20", 321 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", 322 | "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", 323 | "cpu": [ 324 | "arm64" 325 | ], 326 | "optional": true, 327 | "os": [ 328 | "win32" 329 | ], 330 | "engines": { 331 | "node": ">=12" 332 | } 333 | }, 334 | "node_modules/@esbuild/win32-ia32": { 335 | "version": "0.18.20", 336 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", 337 | "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", 338 | "cpu": [ 339 | "ia32" 340 | ], 341 | "optional": true, 342 | "os": [ 343 | "win32" 344 | ], 345 | "engines": { 346 | "node": ">=12" 347 | } 348 | }, 349 | "node_modules/@esbuild/win32-x64": { 350 | "version": "0.18.20", 351 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", 352 | "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", 353 | "cpu": [ 354 | "x64" 355 | ], 356 | "optional": true, 357 | "os": [ 358 | "win32" 359 | ], 360 | "engines": { 361 | "node": ">=12" 362 | } 363 | }, 364 | "node_modules/@fastify/busboy": { 365 | "version": "2.0.0", 366 | "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", 367 | "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==", 368 | "engines": { 369 | "node": ">=14" 370 | } 371 | }, 372 | "node_modules/@jridgewell/gen-mapping": { 373 | "version": "0.3.3", 374 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 375 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 376 | "dependencies": { 377 | "@jridgewell/set-array": "^1.0.1", 378 | "@jridgewell/sourcemap-codec": "^1.4.10", 379 | "@jridgewell/trace-mapping": "^0.3.9" 380 | }, 381 | "engines": { 382 | "node": ">=6.0.0" 383 | } 384 | }, 385 | "node_modules/@jridgewell/resolve-uri": { 386 | "version": "3.1.1", 387 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 388 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 389 | "engines": { 390 | "node": ">=6.0.0" 391 | } 392 | }, 393 | "node_modules/@jridgewell/set-array": { 394 | "version": "1.1.2", 395 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 396 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 397 | "engines": { 398 | "node": ">=6.0.0" 399 | } 400 | }, 401 | "node_modules/@jridgewell/sourcemap-codec": { 402 | "version": "1.4.15", 403 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 404 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" 405 | }, 406 | "node_modules/@jridgewell/trace-mapping": { 407 | "version": "0.3.20", 408 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", 409 | "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", 410 | "dependencies": { 411 | "@jridgewell/resolve-uri": "^3.1.0", 412 | "@jridgewell/sourcemap-codec": "^1.4.14" 413 | } 414 | }, 415 | "node_modules/@nodelib/fs.scandir": { 416 | "version": "2.1.5", 417 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 418 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 419 | "dev": true, 420 | "dependencies": { 421 | "@nodelib/fs.stat": "2.0.5", 422 | "run-parallel": "^1.1.9" 423 | }, 424 | "engines": { 425 | "node": ">= 8" 426 | } 427 | }, 428 | "node_modules/@nodelib/fs.stat": { 429 | "version": "2.0.5", 430 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 431 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 432 | "dev": true, 433 | "engines": { 434 | "node": ">= 8" 435 | } 436 | }, 437 | "node_modules/@nodelib/fs.walk": { 438 | "version": "1.2.8", 439 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 440 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 441 | "dev": true, 442 | "dependencies": { 443 | "@nodelib/fs.scandir": "2.1.5", 444 | "fastq": "^1.6.0" 445 | }, 446 | "engines": { 447 | "node": ">= 8" 448 | } 449 | }, 450 | "node_modules/@polka/url": { 451 | "version": "1.0.0-next.23", 452 | "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", 453 | "integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==" 454 | }, 455 | "node_modules/@sveltejs/adapter-auto": { 456 | "version": "2.1.0", 457 | "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-2.1.0.tgz", 458 | "integrity": "sha512-o2pZCfATFtA/Gw/BB0Xm7k4EYaekXxaPGER3xGSY3FvzFJGTlJlZjBseaXwYSM94lZ0HniOjTokN3cWaLX6fow==", 459 | "dev": true, 460 | "dependencies": { 461 | "import-meta-resolve": "^3.0.0" 462 | }, 463 | "peerDependencies": { 464 | "@sveltejs/kit": "^1.0.0" 465 | } 466 | }, 467 | "node_modules/@sveltejs/adapter-static": { 468 | "version": "2.0.3", 469 | "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-2.0.3.tgz", 470 | "integrity": "sha512-VUqTfXsxYGugCpMqQv1U0LIdbR3S5nBkMMDmpjGVJyM6Q2jHVMFtdWJCkeHMySc6mZxJ+0eZK3T7IgmUCDrcUQ==", 471 | "peerDependencies": { 472 | "@sveltejs/kit": "^1.5.0" 473 | } 474 | }, 475 | "node_modules/@sveltejs/kit": { 476 | "version": "1.27.2", 477 | "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.27.2.tgz", 478 | "integrity": "sha512-2w2VbPpK8DI3QCSVa2UNAv5sKNks1LT8GsEdpk41ffOyO2znGx2ZwcRWacsqlvh3d9lncZuDdANvCbTbuKvy3Q==", 479 | "hasInstallScript": true, 480 | "dependencies": { 481 | "@sveltejs/vite-plugin-svelte": "^2.4.1", 482 | "@types/cookie": "^0.5.1", 483 | "cookie": "^0.5.0", 484 | "devalue": "^4.3.1", 485 | "esm-env": "^1.0.0", 486 | "kleur": "^4.1.5", 487 | "magic-string": "^0.30.0", 488 | "mrmime": "^1.0.1", 489 | "sade": "^1.8.1", 490 | "set-cookie-parser": "^2.6.0", 491 | "sirv": "^2.0.2", 492 | "tiny-glob": "^0.2.9", 493 | "undici": "~5.26.2" 494 | }, 495 | "bin": { 496 | "svelte-kit": "svelte-kit.js" 497 | }, 498 | "engines": { 499 | "node": "^16.14 || >=18" 500 | }, 501 | "peerDependencies": { 502 | "svelte": "^3.54.0 || ^4.0.0-next.0", 503 | "vite": "^4.0.0" 504 | } 505 | }, 506 | "node_modules/@sveltejs/vite-plugin-svelte": { 507 | "version": "2.4.6", 508 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.6.tgz", 509 | "integrity": "sha512-zO79p0+DZnXPnF0ltIigWDx/ux7Ni+HRaFOw720Qeivc1azFUrJxTl0OryXVibYNx1hCboGia1NRV3x8RNv4cA==", 510 | "dependencies": { 511 | "@sveltejs/vite-plugin-svelte-inspector": "^1.0.4", 512 | "debug": "^4.3.4", 513 | "deepmerge": "^4.3.1", 514 | "kleur": "^4.1.5", 515 | "magic-string": "^0.30.3", 516 | "svelte-hmr": "^0.15.3", 517 | "vitefu": "^0.2.4" 518 | }, 519 | "engines": { 520 | "node": "^14.18.0 || >= 16" 521 | }, 522 | "peerDependencies": { 523 | "svelte": "^3.54.0 || ^4.0.0", 524 | "vite": "^4.0.0" 525 | } 526 | }, 527 | "node_modules/@sveltejs/vite-plugin-svelte-inspector": { 528 | "version": "1.0.4", 529 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.4.tgz", 530 | "integrity": "sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==", 531 | "dependencies": { 532 | "debug": "^4.3.4" 533 | }, 534 | "engines": { 535 | "node": "^14.18.0 || >= 16" 536 | }, 537 | "peerDependencies": { 538 | "@sveltejs/vite-plugin-svelte": "^2.2.0", 539 | "svelte": "^3.54.0 || ^4.0.0", 540 | "vite": "^4.0.0" 541 | } 542 | }, 543 | "node_modules/@types/cookie": { 544 | "version": "0.5.3", 545 | "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.3.tgz", 546 | "integrity": "sha512-SLg07AS9z1Ab2LU+QxzU8RCmzsja80ywjf/t5oqw+4NSH20gIGlhLOrBDm1L3PBWzPa4+wkgFQVZAjE6Ioj2ug==" 547 | }, 548 | "node_modules/@types/estree": { 549 | "version": "1.0.4", 550 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.4.tgz", 551 | "integrity": "sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw==" 552 | }, 553 | "node_modules/@types/pug": { 554 | "version": "2.0.8", 555 | "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.8.tgz", 556 | "integrity": "sha512-QzhsZ1dMGyJbn/D9V80zp4GIA4J4rfAjCCxc3MP+new0E8dyVdSkR735Lx+n3LIaHNFcjHL5+TbziccuT+fdoQ==", 557 | "dev": true 558 | }, 559 | "node_modules/acorn": { 560 | "version": "8.11.2", 561 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", 562 | "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", 563 | "bin": { 564 | "acorn": "bin/acorn" 565 | }, 566 | "engines": { 567 | "node": ">=0.4.0" 568 | } 569 | }, 570 | "node_modules/anymatch": { 571 | "version": "3.1.3", 572 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 573 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 574 | "dev": true, 575 | "dependencies": { 576 | "normalize-path": "^3.0.0", 577 | "picomatch": "^2.0.4" 578 | }, 579 | "engines": { 580 | "node": ">= 8" 581 | } 582 | }, 583 | "node_modules/aria-query": { 584 | "version": "5.3.0", 585 | "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", 586 | "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", 587 | "dependencies": { 588 | "dequal": "^2.0.3" 589 | } 590 | }, 591 | "node_modules/axobject-query": { 592 | "version": "3.2.1", 593 | "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", 594 | "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", 595 | "dependencies": { 596 | "dequal": "^2.0.3" 597 | } 598 | }, 599 | "node_modules/balanced-match": { 600 | "version": "1.0.2", 601 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 602 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 603 | "dev": true 604 | }, 605 | "node_modules/binary-extensions": { 606 | "version": "2.2.0", 607 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 608 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 609 | "dev": true, 610 | "engines": { 611 | "node": ">=8" 612 | } 613 | }, 614 | "node_modules/brace-expansion": { 615 | "version": "1.1.11", 616 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 617 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 618 | "dev": true, 619 | "dependencies": { 620 | "balanced-match": "^1.0.0", 621 | "concat-map": "0.0.1" 622 | } 623 | }, 624 | "node_modules/braces": { 625 | "version": "3.0.2", 626 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 627 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 628 | "dev": true, 629 | "dependencies": { 630 | "fill-range": "^7.0.1" 631 | }, 632 | "engines": { 633 | "node": ">=8" 634 | } 635 | }, 636 | "node_modules/buffer-crc32": { 637 | "version": "0.2.13", 638 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 639 | "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", 640 | "dev": true, 641 | "engines": { 642 | "node": "*" 643 | } 644 | }, 645 | "node_modules/callsites": { 646 | "version": "3.1.0", 647 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 648 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 649 | "dev": true, 650 | "engines": { 651 | "node": ">=6" 652 | } 653 | }, 654 | "node_modules/chokidar": { 655 | "version": "3.5.3", 656 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 657 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 658 | "dev": true, 659 | "funding": [ 660 | { 661 | "type": "individual", 662 | "url": "https://paulmillr.com/funding/" 663 | } 664 | ], 665 | "dependencies": { 666 | "anymatch": "~3.1.2", 667 | "braces": "~3.0.2", 668 | "glob-parent": "~5.1.2", 669 | "is-binary-path": "~2.1.0", 670 | "is-glob": "~4.0.1", 671 | "normalize-path": "~3.0.0", 672 | "readdirp": "~3.6.0" 673 | }, 674 | "engines": { 675 | "node": ">= 8.10.0" 676 | }, 677 | "optionalDependencies": { 678 | "fsevents": "~2.3.2" 679 | } 680 | }, 681 | "node_modules/code-red": { 682 | "version": "1.0.4", 683 | "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", 684 | "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", 685 | "dependencies": { 686 | "@jridgewell/sourcemap-codec": "^1.4.15", 687 | "@types/estree": "^1.0.1", 688 | "acorn": "^8.10.0", 689 | "estree-walker": "^3.0.3", 690 | "periscopic": "^3.1.0" 691 | } 692 | }, 693 | "node_modules/concat-map": { 694 | "version": "0.0.1", 695 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 696 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 697 | "dev": true 698 | }, 699 | "node_modules/cookie": { 700 | "version": "0.5.0", 701 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 702 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 703 | "engines": { 704 | "node": ">= 0.6" 705 | } 706 | }, 707 | "node_modules/css-tree": { 708 | "version": "2.3.1", 709 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", 710 | "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", 711 | "dependencies": { 712 | "mdn-data": "2.0.30", 713 | "source-map-js": "^1.0.1" 714 | }, 715 | "engines": { 716 | "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" 717 | } 718 | }, 719 | "node_modules/debug": { 720 | "version": "4.3.4", 721 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 722 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 723 | "dependencies": { 724 | "ms": "2.1.2" 725 | }, 726 | "engines": { 727 | "node": ">=6.0" 728 | }, 729 | "peerDependenciesMeta": { 730 | "supports-color": { 731 | "optional": true 732 | } 733 | } 734 | }, 735 | "node_modules/deepmerge": { 736 | "version": "4.3.1", 737 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", 738 | "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", 739 | "engines": { 740 | "node": ">=0.10.0" 741 | } 742 | }, 743 | "node_modules/dequal": { 744 | "version": "2.0.3", 745 | "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", 746 | "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", 747 | "engines": { 748 | "node": ">=6" 749 | } 750 | }, 751 | "node_modules/detect-indent": { 752 | "version": "6.1.0", 753 | "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", 754 | "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", 755 | "dev": true, 756 | "engines": { 757 | "node": ">=8" 758 | } 759 | }, 760 | "node_modules/devalue": { 761 | "version": "4.3.2", 762 | "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz", 763 | "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==" 764 | }, 765 | "node_modules/es6-promise": { 766 | "version": "3.3.1", 767 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", 768 | "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", 769 | "dev": true 770 | }, 771 | "node_modules/esbuild": { 772 | "version": "0.18.20", 773 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", 774 | "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", 775 | "hasInstallScript": true, 776 | "bin": { 777 | "esbuild": "bin/esbuild" 778 | }, 779 | "engines": { 780 | "node": ">=12" 781 | }, 782 | "optionalDependencies": { 783 | "@esbuild/android-arm": "0.18.20", 784 | "@esbuild/android-arm64": "0.18.20", 785 | "@esbuild/android-x64": "0.18.20", 786 | "@esbuild/darwin-arm64": "0.18.20", 787 | "@esbuild/darwin-x64": "0.18.20", 788 | "@esbuild/freebsd-arm64": "0.18.20", 789 | "@esbuild/freebsd-x64": "0.18.20", 790 | "@esbuild/linux-arm": "0.18.20", 791 | "@esbuild/linux-arm64": "0.18.20", 792 | "@esbuild/linux-ia32": "0.18.20", 793 | "@esbuild/linux-loong64": "0.18.20", 794 | "@esbuild/linux-mips64el": "0.18.20", 795 | "@esbuild/linux-ppc64": "0.18.20", 796 | "@esbuild/linux-riscv64": "0.18.20", 797 | "@esbuild/linux-s390x": "0.18.20", 798 | "@esbuild/linux-x64": "0.18.20", 799 | "@esbuild/netbsd-x64": "0.18.20", 800 | "@esbuild/openbsd-x64": "0.18.20", 801 | "@esbuild/sunos-x64": "0.18.20", 802 | "@esbuild/win32-arm64": "0.18.20", 803 | "@esbuild/win32-ia32": "0.18.20", 804 | "@esbuild/win32-x64": "0.18.20" 805 | } 806 | }, 807 | "node_modules/esm-env": { 808 | "version": "1.0.0", 809 | "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", 810 | "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==" 811 | }, 812 | "node_modules/estree-walker": { 813 | "version": "3.0.3", 814 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", 815 | "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", 816 | "dependencies": { 817 | "@types/estree": "^1.0.0" 818 | } 819 | }, 820 | "node_modules/fast-glob": { 821 | "version": "3.3.1", 822 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", 823 | "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", 824 | "dev": true, 825 | "dependencies": { 826 | "@nodelib/fs.stat": "^2.0.2", 827 | "@nodelib/fs.walk": "^1.2.3", 828 | "glob-parent": "^5.1.2", 829 | "merge2": "^1.3.0", 830 | "micromatch": "^4.0.4" 831 | }, 832 | "engines": { 833 | "node": ">=8.6.0" 834 | } 835 | }, 836 | "node_modules/fastq": { 837 | "version": "1.15.0", 838 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 839 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 840 | "dev": true, 841 | "dependencies": { 842 | "reusify": "^1.0.4" 843 | } 844 | }, 845 | "node_modules/fill-range": { 846 | "version": "7.0.1", 847 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 848 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 849 | "dev": true, 850 | "dependencies": { 851 | "to-regex-range": "^5.0.1" 852 | }, 853 | "engines": { 854 | "node": ">=8" 855 | } 856 | }, 857 | "node_modules/fs.realpath": { 858 | "version": "1.0.0", 859 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 860 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 861 | "dev": true 862 | }, 863 | "node_modules/fsevents": { 864 | "version": "2.3.3", 865 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 866 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 867 | "hasInstallScript": true, 868 | "optional": true, 869 | "os": [ 870 | "darwin" 871 | ], 872 | "engines": { 873 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 874 | } 875 | }, 876 | "node_modules/glob": { 877 | "version": "7.2.3", 878 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 879 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 880 | "dev": true, 881 | "dependencies": { 882 | "fs.realpath": "^1.0.0", 883 | "inflight": "^1.0.4", 884 | "inherits": "2", 885 | "minimatch": "^3.1.1", 886 | "once": "^1.3.0", 887 | "path-is-absolute": "^1.0.0" 888 | }, 889 | "engines": { 890 | "node": "*" 891 | }, 892 | "funding": { 893 | "url": "https://github.com/sponsors/isaacs" 894 | } 895 | }, 896 | "node_modules/glob-parent": { 897 | "version": "5.1.2", 898 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 899 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 900 | "dev": true, 901 | "dependencies": { 902 | "is-glob": "^4.0.1" 903 | }, 904 | "engines": { 905 | "node": ">= 6" 906 | } 907 | }, 908 | "node_modules/globalyzer": { 909 | "version": "0.1.0", 910 | "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", 911 | "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==" 912 | }, 913 | "node_modules/globrex": { 914 | "version": "0.1.2", 915 | "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", 916 | "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==" 917 | }, 918 | "node_modules/graceful-fs": { 919 | "version": "4.2.11", 920 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 921 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 922 | "dev": true 923 | }, 924 | "node_modules/import-fresh": { 925 | "version": "3.3.0", 926 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 927 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 928 | "dev": true, 929 | "dependencies": { 930 | "parent-module": "^1.0.0", 931 | "resolve-from": "^4.0.0" 932 | }, 933 | "engines": { 934 | "node": ">=6" 935 | }, 936 | "funding": { 937 | "url": "https://github.com/sponsors/sindresorhus" 938 | } 939 | }, 940 | "node_modules/import-meta-resolve": { 941 | "version": "3.0.0", 942 | "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-3.0.0.tgz", 943 | "integrity": "sha512-4IwhLhNNA8yy445rPjD/lWh++7hMDOml2eHtd58eG7h+qK3EryMuuRbsHGPikCoAgIkkDnckKfWSk2iDla/ejg==", 944 | "dev": true, 945 | "funding": { 946 | "type": "github", 947 | "url": "https://github.com/sponsors/wooorm" 948 | } 949 | }, 950 | "node_modules/inflight": { 951 | "version": "1.0.6", 952 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 953 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 954 | "dev": true, 955 | "dependencies": { 956 | "once": "^1.3.0", 957 | "wrappy": "1" 958 | } 959 | }, 960 | "node_modules/inherits": { 961 | "version": "2.0.4", 962 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 963 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 964 | "dev": true 965 | }, 966 | "node_modules/is-binary-path": { 967 | "version": "2.1.0", 968 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 969 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 970 | "dev": true, 971 | "dependencies": { 972 | "binary-extensions": "^2.0.0" 973 | }, 974 | "engines": { 975 | "node": ">=8" 976 | } 977 | }, 978 | "node_modules/is-extglob": { 979 | "version": "2.1.1", 980 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 981 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 982 | "dev": true, 983 | "engines": { 984 | "node": ">=0.10.0" 985 | } 986 | }, 987 | "node_modules/is-glob": { 988 | "version": "4.0.3", 989 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 990 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 991 | "dev": true, 992 | "dependencies": { 993 | "is-extglob": "^2.1.1" 994 | }, 995 | "engines": { 996 | "node": ">=0.10.0" 997 | } 998 | }, 999 | "node_modules/is-number": { 1000 | "version": "7.0.0", 1001 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1002 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1003 | "dev": true, 1004 | "engines": { 1005 | "node": ">=0.12.0" 1006 | } 1007 | }, 1008 | "node_modules/is-reference": { 1009 | "version": "3.0.2", 1010 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", 1011 | "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", 1012 | "dependencies": { 1013 | "@types/estree": "*" 1014 | } 1015 | }, 1016 | "node_modules/kleur": { 1017 | "version": "4.1.5", 1018 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", 1019 | "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", 1020 | "engines": { 1021 | "node": ">=6" 1022 | } 1023 | }, 1024 | "node_modules/locate-character": { 1025 | "version": "3.0.0", 1026 | "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", 1027 | "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" 1028 | }, 1029 | "node_modules/magic-string": { 1030 | "version": "0.30.5", 1031 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", 1032 | "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", 1033 | "dependencies": { 1034 | "@jridgewell/sourcemap-codec": "^1.4.15" 1035 | }, 1036 | "engines": { 1037 | "node": ">=12" 1038 | } 1039 | }, 1040 | "node_modules/mdn-data": { 1041 | "version": "2.0.30", 1042 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", 1043 | "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" 1044 | }, 1045 | "node_modules/merge2": { 1046 | "version": "1.4.1", 1047 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1048 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1049 | "dev": true, 1050 | "engines": { 1051 | "node": ">= 8" 1052 | } 1053 | }, 1054 | "node_modules/micromatch": { 1055 | "version": "4.0.5", 1056 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 1057 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 1058 | "dev": true, 1059 | "dependencies": { 1060 | "braces": "^3.0.2", 1061 | "picomatch": "^2.3.1" 1062 | }, 1063 | "engines": { 1064 | "node": ">=8.6" 1065 | } 1066 | }, 1067 | "node_modules/min-indent": { 1068 | "version": "1.0.1", 1069 | "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", 1070 | "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", 1071 | "dev": true, 1072 | "engines": { 1073 | "node": ">=4" 1074 | } 1075 | }, 1076 | "node_modules/minimatch": { 1077 | "version": "3.1.2", 1078 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1079 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1080 | "dev": true, 1081 | "dependencies": { 1082 | "brace-expansion": "^1.1.7" 1083 | }, 1084 | "engines": { 1085 | "node": "*" 1086 | } 1087 | }, 1088 | "node_modules/minimist": { 1089 | "version": "1.2.8", 1090 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 1091 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 1092 | "dev": true, 1093 | "funding": { 1094 | "url": "https://github.com/sponsors/ljharb" 1095 | } 1096 | }, 1097 | "node_modules/mkdirp": { 1098 | "version": "0.5.6", 1099 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", 1100 | "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", 1101 | "dev": true, 1102 | "dependencies": { 1103 | "minimist": "^1.2.6" 1104 | }, 1105 | "bin": { 1106 | "mkdirp": "bin/cmd.js" 1107 | } 1108 | }, 1109 | "node_modules/mri": { 1110 | "version": "1.2.0", 1111 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", 1112 | "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", 1113 | "engines": { 1114 | "node": ">=4" 1115 | } 1116 | }, 1117 | "node_modules/mrmime": { 1118 | "version": "1.0.1", 1119 | "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", 1120 | "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", 1121 | "engines": { 1122 | "node": ">=10" 1123 | } 1124 | }, 1125 | "node_modules/ms": { 1126 | "version": "2.1.2", 1127 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1128 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 1129 | }, 1130 | "node_modules/nanoid": { 1131 | "version": "3.3.6", 1132 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 1133 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 1134 | "funding": [ 1135 | { 1136 | "type": "github", 1137 | "url": "https://github.com/sponsors/ai" 1138 | } 1139 | ], 1140 | "bin": { 1141 | "nanoid": "bin/nanoid.cjs" 1142 | }, 1143 | "engines": { 1144 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1145 | } 1146 | }, 1147 | "node_modules/normalize-path": { 1148 | "version": "3.0.0", 1149 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1150 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1151 | "dev": true, 1152 | "engines": { 1153 | "node": ">=0.10.0" 1154 | } 1155 | }, 1156 | "node_modules/once": { 1157 | "version": "1.4.0", 1158 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1159 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 1160 | "dev": true, 1161 | "dependencies": { 1162 | "wrappy": "1" 1163 | } 1164 | }, 1165 | "node_modules/parent-module": { 1166 | "version": "1.0.1", 1167 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1168 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1169 | "dev": true, 1170 | "dependencies": { 1171 | "callsites": "^3.0.0" 1172 | }, 1173 | "engines": { 1174 | "node": ">=6" 1175 | } 1176 | }, 1177 | "node_modules/path-is-absolute": { 1178 | "version": "1.0.1", 1179 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1180 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 1181 | "dev": true, 1182 | "engines": { 1183 | "node": ">=0.10.0" 1184 | } 1185 | }, 1186 | "node_modules/periscopic": { 1187 | "version": "3.1.0", 1188 | "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", 1189 | "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", 1190 | "dependencies": { 1191 | "@types/estree": "^1.0.0", 1192 | "estree-walker": "^3.0.0", 1193 | "is-reference": "^3.0.0" 1194 | } 1195 | }, 1196 | "node_modules/picocolors": { 1197 | "version": "1.0.0", 1198 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1199 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 1200 | }, 1201 | "node_modules/picomatch": { 1202 | "version": "2.3.1", 1203 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1204 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1205 | "dev": true, 1206 | "engines": { 1207 | "node": ">=8.6" 1208 | }, 1209 | "funding": { 1210 | "url": "https://github.com/sponsors/jonschlinkert" 1211 | } 1212 | }, 1213 | "node_modules/postcss": { 1214 | "version": "8.4.31", 1215 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", 1216 | "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", 1217 | "funding": [ 1218 | { 1219 | "type": "opencollective", 1220 | "url": "https://opencollective.com/postcss/" 1221 | }, 1222 | { 1223 | "type": "tidelift", 1224 | "url": "https://tidelift.com/funding/github/npm/postcss" 1225 | }, 1226 | { 1227 | "type": "github", 1228 | "url": "https://github.com/sponsors/ai" 1229 | } 1230 | ], 1231 | "dependencies": { 1232 | "nanoid": "^3.3.6", 1233 | "picocolors": "^1.0.0", 1234 | "source-map-js": "^1.0.2" 1235 | }, 1236 | "engines": { 1237 | "node": "^10 || ^12 || >=14" 1238 | } 1239 | }, 1240 | "node_modules/queue-microtask": { 1241 | "version": "1.2.3", 1242 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1243 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1244 | "dev": true, 1245 | "funding": [ 1246 | { 1247 | "type": "github", 1248 | "url": "https://github.com/sponsors/feross" 1249 | }, 1250 | { 1251 | "type": "patreon", 1252 | "url": "https://www.patreon.com/feross" 1253 | }, 1254 | { 1255 | "type": "consulting", 1256 | "url": "https://feross.org/support" 1257 | } 1258 | ] 1259 | }, 1260 | "node_modules/readdirp": { 1261 | "version": "3.6.0", 1262 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1263 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1264 | "dev": true, 1265 | "dependencies": { 1266 | "picomatch": "^2.2.1" 1267 | }, 1268 | "engines": { 1269 | "node": ">=8.10.0" 1270 | } 1271 | }, 1272 | "node_modules/resolve-from": { 1273 | "version": "4.0.0", 1274 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1275 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1276 | "dev": true, 1277 | "engines": { 1278 | "node": ">=4" 1279 | } 1280 | }, 1281 | "node_modules/reusify": { 1282 | "version": "1.0.4", 1283 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1284 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1285 | "dev": true, 1286 | "engines": { 1287 | "iojs": ">=1.0.0", 1288 | "node": ">=0.10.0" 1289 | } 1290 | }, 1291 | "node_modules/rimraf": { 1292 | "version": "2.7.1", 1293 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1294 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 1295 | "dev": true, 1296 | "dependencies": { 1297 | "glob": "^7.1.3" 1298 | }, 1299 | "bin": { 1300 | "rimraf": "bin.js" 1301 | } 1302 | }, 1303 | "node_modules/rollup": { 1304 | "version": "3.29.4", 1305 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", 1306 | "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", 1307 | "bin": { 1308 | "rollup": "dist/bin/rollup" 1309 | }, 1310 | "engines": { 1311 | "node": ">=14.18.0", 1312 | "npm": ">=8.0.0" 1313 | }, 1314 | "optionalDependencies": { 1315 | "fsevents": "~2.3.2" 1316 | } 1317 | }, 1318 | "node_modules/run-parallel": { 1319 | "version": "1.2.0", 1320 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1321 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1322 | "dev": true, 1323 | "funding": [ 1324 | { 1325 | "type": "github", 1326 | "url": "https://github.com/sponsors/feross" 1327 | }, 1328 | { 1329 | "type": "patreon", 1330 | "url": "https://www.patreon.com/feross" 1331 | }, 1332 | { 1333 | "type": "consulting", 1334 | "url": "https://feross.org/support" 1335 | } 1336 | ], 1337 | "dependencies": { 1338 | "queue-microtask": "^1.2.2" 1339 | } 1340 | }, 1341 | "node_modules/sade": { 1342 | "version": "1.8.1", 1343 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", 1344 | "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", 1345 | "dependencies": { 1346 | "mri": "^1.1.0" 1347 | }, 1348 | "engines": { 1349 | "node": ">=6" 1350 | } 1351 | }, 1352 | "node_modules/sander": { 1353 | "version": "0.5.1", 1354 | "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", 1355 | "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", 1356 | "dev": true, 1357 | "dependencies": { 1358 | "es6-promise": "^3.1.2", 1359 | "graceful-fs": "^4.1.3", 1360 | "mkdirp": "^0.5.1", 1361 | "rimraf": "^2.5.2" 1362 | } 1363 | }, 1364 | "node_modules/set-cookie-parser": { 1365 | "version": "2.6.0", 1366 | "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", 1367 | "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" 1368 | }, 1369 | "node_modules/sirv": { 1370 | "version": "2.0.3", 1371 | "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", 1372 | "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", 1373 | "dependencies": { 1374 | "@polka/url": "^1.0.0-next.20", 1375 | "mrmime": "^1.0.0", 1376 | "totalist": "^3.0.0" 1377 | }, 1378 | "engines": { 1379 | "node": ">= 10" 1380 | } 1381 | }, 1382 | "node_modules/sorcery": { 1383 | "version": "0.11.0", 1384 | "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", 1385 | "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==", 1386 | "dev": true, 1387 | "dependencies": { 1388 | "@jridgewell/sourcemap-codec": "^1.4.14", 1389 | "buffer-crc32": "^0.2.5", 1390 | "minimist": "^1.2.0", 1391 | "sander": "^0.5.0" 1392 | }, 1393 | "bin": { 1394 | "sorcery": "bin/sorcery" 1395 | } 1396 | }, 1397 | "node_modules/source-map-js": { 1398 | "version": "1.0.2", 1399 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1400 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 1401 | "engines": { 1402 | "node": ">=0.10.0" 1403 | } 1404 | }, 1405 | "node_modules/strip-indent": { 1406 | "version": "3.0.0", 1407 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", 1408 | "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", 1409 | "dev": true, 1410 | "dependencies": { 1411 | "min-indent": "^1.0.0" 1412 | }, 1413 | "engines": { 1414 | "node": ">=8" 1415 | } 1416 | }, 1417 | "node_modules/svelte": { 1418 | "version": "4.2.2", 1419 | "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.2.tgz", 1420 | "integrity": "sha512-My2tytF2e2NnHSpn2M7/3VdXT4JdTglYVUuSuK/mXL2XtulPYbeBfl8Dm1QiaKRn0zoULRnL+EtfZHHP0k4H3A==", 1421 | "dependencies": { 1422 | "@ampproject/remapping": "^2.2.1", 1423 | "@jridgewell/sourcemap-codec": "^1.4.15", 1424 | "@jridgewell/trace-mapping": "^0.3.18", 1425 | "acorn": "^8.9.0", 1426 | "aria-query": "^5.3.0", 1427 | "axobject-query": "^3.2.1", 1428 | "code-red": "^1.0.3", 1429 | "css-tree": "^2.3.1", 1430 | "estree-walker": "^3.0.3", 1431 | "is-reference": "^3.0.1", 1432 | "locate-character": "^3.0.0", 1433 | "magic-string": "^0.30.4", 1434 | "periscopic": "^3.1.0" 1435 | }, 1436 | "engines": { 1437 | "node": ">=16" 1438 | } 1439 | }, 1440 | "node_modules/svelte-check": { 1441 | "version": "3.5.2", 1442 | "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.5.2.tgz", 1443 | "integrity": "sha512-5a/YWbiH4c+AqAUP+0VneiV5bP8YOk9JL3jwvN+k2PEPLgpu85bjQc5eE67+eIZBBwUEJzmO3I92OqKcqbp3fw==", 1444 | "dev": true, 1445 | "dependencies": { 1446 | "@jridgewell/trace-mapping": "^0.3.17", 1447 | "chokidar": "^3.4.1", 1448 | "fast-glob": "^3.2.7", 1449 | "import-fresh": "^3.2.1", 1450 | "picocolors": "^1.0.0", 1451 | "sade": "^1.7.4", 1452 | "svelte-preprocess": "^5.0.4", 1453 | "typescript": "^5.0.3" 1454 | }, 1455 | "bin": { 1456 | "svelte-check": "bin/svelte-check" 1457 | }, 1458 | "peerDependencies": { 1459 | "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0" 1460 | } 1461 | }, 1462 | "node_modules/svelte-hmr": { 1463 | "version": "0.15.3", 1464 | "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", 1465 | "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", 1466 | "engines": { 1467 | "node": "^12.20 || ^14.13.1 || >= 16" 1468 | }, 1469 | "peerDependencies": { 1470 | "svelte": "^3.19.0 || ^4.0.0" 1471 | } 1472 | }, 1473 | "node_modules/svelte-preprocess": { 1474 | "version": "5.0.4", 1475 | "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz", 1476 | "integrity": "sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==", 1477 | "dev": true, 1478 | "hasInstallScript": true, 1479 | "dependencies": { 1480 | "@types/pug": "^2.0.6", 1481 | "detect-indent": "^6.1.0", 1482 | "magic-string": "^0.27.0", 1483 | "sorcery": "^0.11.0", 1484 | "strip-indent": "^3.0.0" 1485 | }, 1486 | "engines": { 1487 | "node": ">= 14.10.0" 1488 | }, 1489 | "peerDependencies": { 1490 | "@babel/core": "^7.10.2", 1491 | "coffeescript": "^2.5.1", 1492 | "less": "^3.11.3 || ^4.0.0", 1493 | "postcss": "^7 || ^8", 1494 | "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0", 1495 | "pug": "^3.0.0", 1496 | "sass": "^1.26.8", 1497 | "stylus": "^0.55.0", 1498 | "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", 1499 | "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0", 1500 | "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" 1501 | }, 1502 | "peerDependenciesMeta": { 1503 | "@babel/core": { 1504 | "optional": true 1505 | }, 1506 | "coffeescript": { 1507 | "optional": true 1508 | }, 1509 | "less": { 1510 | "optional": true 1511 | }, 1512 | "postcss": { 1513 | "optional": true 1514 | }, 1515 | "postcss-load-config": { 1516 | "optional": true 1517 | }, 1518 | "pug": { 1519 | "optional": true 1520 | }, 1521 | "sass": { 1522 | "optional": true 1523 | }, 1524 | "stylus": { 1525 | "optional": true 1526 | }, 1527 | "sugarss": { 1528 | "optional": true 1529 | }, 1530 | "typescript": { 1531 | "optional": true 1532 | } 1533 | } 1534 | }, 1535 | "node_modules/svelte-preprocess/node_modules/magic-string": { 1536 | "version": "0.27.0", 1537 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", 1538 | "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", 1539 | "dev": true, 1540 | "dependencies": { 1541 | "@jridgewell/sourcemap-codec": "^1.4.13" 1542 | }, 1543 | "engines": { 1544 | "node": ">=12" 1545 | } 1546 | }, 1547 | "node_modules/tiny-glob": { 1548 | "version": "0.2.9", 1549 | "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", 1550 | "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", 1551 | "dependencies": { 1552 | "globalyzer": "0.1.0", 1553 | "globrex": "^0.1.2" 1554 | } 1555 | }, 1556 | "node_modules/to-regex-range": { 1557 | "version": "5.0.1", 1558 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1559 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1560 | "dev": true, 1561 | "dependencies": { 1562 | "is-number": "^7.0.0" 1563 | }, 1564 | "engines": { 1565 | "node": ">=8.0" 1566 | } 1567 | }, 1568 | "node_modules/totalist": { 1569 | "version": "3.0.1", 1570 | "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", 1571 | "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", 1572 | "engines": { 1573 | "node": ">=6" 1574 | } 1575 | }, 1576 | "node_modules/typescript": { 1577 | "version": "5.2.2", 1578 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", 1579 | "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", 1580 | "dev": true, 1581 | "bin": { 1582 | "tsc": "bin/tsc", 1583 | "tsserver": "bin/tsserver" 1584 | }, 1585 | "engines": { 1586 | "node": ">=14.17" 1587 | } 1588 | }, 1589 | "node_modules/undici": { 1590 | "version": "5.26.5", 1591 | "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.5.tgz", 1592 | "integrity": "sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==", 1593 | "dependencies": { 1594 | "@fastify/busboy": "^2.0.0" 1595 | }, 1596 | "engines": { 1597 | "node": ">=14.0" 1598 | } 1599 | }, 1600 | "node_modules/vite": { 1601 | "version": "4.5.0", 1602 | "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", 1603 | "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", 1604 | "dependencies": { 1605 | "esbuild": "^0.18.10", 1606 | "postcss": "^8.4.27", 1607 | "rollup": "^3.27.1" 1608 | }, 1609 | "bin": { 1610 | "vite": "bin/vite.js" 1611 | }, 1612 | "engines": { 1613 | "node": "^14.18.0 || >=16.0.0" 1614 | }, 1615 | "funding": { 1616 | "url": "https://github.com/vitejs/vite?sponsor=1" 1617 | }, 1618 | "optionalDependencies": { 1619 | "fsevents": "~2.3.2" 1620 | }, 1621 | "peerDependencies": { 1622 | "@types/node": ">= 14", 1623 | "less": "*", 1624 | "lightningcss": "^1.21.0", 1625 | "sass": "*", 1626 | "stylus": "*", 1627 | "sugarss": "*", 1628 | "terser": "^5.4.0" 1629 | }, 1630 | "peerDependenciesMeta": { 1631 | "@types/node": { 1632 | "optional": true 1633 | }, 1634 | "less": { 1635 | "optional": true 1636 | }, 1637 | "lightningcss": { 1638 | "optional": true 1639 | }, 1640 | "sass": { 1641 | "optional": true 1642 | }, 1643 | "stylus": { 1644 | "optional": true 1645 | }, 1646 | "sugarss": { 1647 | "optional": true 1648 | }, 1649 | "terser": { 1650 | "optional": true 1651 | } 1652 | } 1653 | }, 1654 | "node_modules/vitefu": { 1655 | "version": "0.2.5", 1656 | "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", 1657 | "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", 1658 | "peerDependencies": { 1659 | "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" 1660 | }, 1661 | "peerDependenciesMeta": { 1662 | "vite": { 1663 | "optional": true 1664 | } 1665 | } 1666 | }, 1667 | "node_modules/wrappy": { 1668 | "version": "1.0.2", 1669 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1670 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1671 | "dev": true 1672 | } 1673 | } 1674 | } 1675 | --------------------------------------------------------------------------------