diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..264a84aa9 --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +NODE_ENV=production +PORT=3000 +GH_TOKEN=your_github_token +API_TOKEN=your_api_token +API_IP="" +API_IP_REGEX="" +KENER_BASE_PATH="" \ No newline at end of file diff --git a/.github/workflows/publishImage.yml b/.github/workflows/publishImage.yml index d2453f048..cc95914bc 100644 --- a/.github/workflows/publishImage.yml +++ b/.github/workflows/publishImage.yml @@ -1,40 +1,32 @@ +--- name: Publish Docker image to Dockerhub and GHCR - on: push: branches: - - 'main' - # add additional branches that should build to images here - # they will be tagged based on the branch name IE kener:test - #- 'test' + - main tags: - - '*.*.*' - # don't trigger if just updating docs + - "*.*.*" paths-ignore: - - 'docs.md' - - 'README.md' - + - docs.md + - README.md jobs: push_to_registry: name: Push Docker image to Docker Hub runs-on: ubuntu-latest - # only run if we've specified image tag to push to if: ${{ vars.DOCKERHUB_IMAGE_NAME != '' || vars.GHCR_IMAGE_NAME != '' }} - # https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token permissions: packages: write contents: read steps: - name: Check out the repo uses: actions/checkout@v2 - - name: Log in to Docker Hub - if: ${{ github.event_name != 'pull_request' && vars.DOCKERHUB_IMAGE_NAME != '' }} + if: ${{ github.event_name != 'pull_request' && vars.DOCKERHUB_IMAGE_NAME != '' + }} uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Login to GitHub Container Registry if: ${{ github.event_name != 'pull_request' && vars.GHCR_IMAGE_NAME != '' }} uses: docker/login-action@v2 @@ -42,7 +34,6 @@ jobs: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@v3 @@ -50,20 +41,16 @@ jobs: images: | ${{ vars.DOCKERHUB_IMAGE_NAME }} ${{ vars.GHCR_IMAGE_NAME }} - # generate Docker tags based on the following events/attributes tags: | type=raw,value=latest,enable=${{ endsWith(github.ref, 'main') }} type=ref,event=branch,enable=${{ !endsWith(github.ref, 'main') }} type=semver,pattern={{version}} flavor: | latest=false - - name: Set up QEMU uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - name: Build and push Docker image uses: docker/build-push-action@v4 with: diff --git a/.gitignore b/.gitignore index 0f0f68ff4..caa9c131e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,10 @@ vite.config.ts.timestamp-* nodemon.json .okgit/ config/static/* -!config/static/.kener \ No newline at end of file +!config/static/.kener +db/* +!db/.kener +database/* +!database/.kener +src/lib/server/config/monitors.yaml +src/lib/server/config/site.yaml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index a3581b95c..ef4e95084 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,16 +15,11 @@ RUN \ # set OS timezone specified by docker ENV RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone -ARG data_dir=/config -VOLUME $data_dir -ENV CONFIG_DIR=$data_dir + COPY docker/root/ / -# Dir ENVs need to be set before building or else build throws errors -ENV PUBLIC_KENER_FOLDER=/config/static \ - MONITOR_YAML_PATH=/config/monitors.yaml \ - SITE_YAML_PATH=/config/site.yaml + # build requires devDependencies which are not used by production deploy # so build in a stage so we can copy results to clean "deploy" stage later @@ -34,12 +29,9 @@ WORKDIR /app COPY --chown=abc:abc . /app -# build requires PUBLIC_KENER_FOLDER dir exists so create temporarily -# -- it is non-existent in final stage to allow proper startup and chown'ing/example population -RUN mkdir -p "${CONFIG_DIR}"/static \ - && npm install \ +RUN npm install \ && chown -R root:root node_modules \ - && npm run kener:build + && npm run build FROM base as app @@ -48,13 +40,16 @@ FROM base as app COPY --chown=abc:abc package*.json ./ COPY --from=base /usr/local/bin /usr/local/bin COPY --from=base /usr/local/lib /usr/local/lib -COPY --chown=abc:abc scripts /app/scripts + COPY --chown=abc:abc static /app/static -COPY --chown=abc:abc locales /app/locales -COPY --chown=abc:abc config /app/config +COPY --chown=abc:abc database /app/database +COPY --chown=abc:abc build.js /app/build.js +COPY --chown=abc:abc sitemap.js /app/sitemap.js +COPY --chown=abc:abc src/lib/server /app/src/lib/server COPY --chown=abc:abc src/lib/helpers.js /app/src/lib/helpers.js + COPY --from=build --chown=abc:abc /app/build /app/build -COPY --from=build --chown=abc:abc /app/prod.js /app/prod.js +COPY --from=build --chown=abc:abc /app/main.js /app/main.js ENV NODE_ENV=production diff --git a/README.md b/README.md index 9fc6778da..a76269506 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ +# Kener - A Sveltekit NodeJS Status Page System +

- kener example illustration + kener example illustration

@@ -8,19 +10,23 @@ Docker Kener

-#### 👉 Visit a live server [here](https://kener.ing) +#### [👉 Visit a live server](https://kener.ing) + +#### [👉 Quick Start](https://kener.ing/docs/quick-start) + +#### [👉 Documentation](https://kener.ing/docs) -#### 👉 Read the documentation [here](https://kener.ing/kener-docs) +## What is Kener? -# Kener - Status Page System +Kener: Open-source sveltekit status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents. Kener integrates seamlessly with GitHub, making incident management a team effort—making. -Kener: Open-source Node.js status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents. And the best part? Kener integrates seamlessly with GitHub, making incident management a team effort—making it easier for us to track and fix issues together in a collaborative and friendly environment. +It uses files to store the data. -It uses files to store the data. Other adapters are coming soon +Kener name is derived from the word "Kene" which means "how is it going" in Assamese, then .ing is added to make cooler. ## Features -**Monitoring and Tracking:** +### Monitoring and Tracking - Real-time monitoring - Polls HTTP endpoint or Push data to monitor using Rest APIs @@ -29,11 +35,11 @@ It uses files to store the data. Other adapters are coming soon - Cron-based scheduling for monitors. Minimum per minute - Flexible monitor configuration using YAML. Define your own parsing for monitor being UP/DOWN/DEGRADED - Construct complex API Polls - Chain, Secrets etc -- Supports a Default Status for Monitors. Example defaultStatus=DOWN if you dont hit API per minute with Status UP +- Supports a Default Status for Monitors. Example defaultStatus=DOWN if you don't hit API per minute with Status UP - Supports base path for hosting in k8s - Pre-built docker image for easy deployment -**Customization and Branding:** +### Customization and Branding - Customizable status page using yaml or code - Badge generation for status and uptime of Monitors @@ -42,12 +48,12 @@ It uses files to store the data. Other adapters are coming soon - Light + Dark Theme - Internationalization support -**Incident Management:** +### Incident Management - Create Incidents using Github Issues - Rich Text - Or use APIs to create Incidents -**User Experience and Design:** +### User Experience and Design - 100% Accessibility Score - Easy installation and setup @@ -64,13 +70,6 @@ It uses files to store the data. Other adapters are coming soon - [Upptime](https://upptime.js.org/) -## Roadmap - -- [x] Add api to create incident -- [x] Add docker file -- [ ] Add notification -- [ ] Add Mysql adapter - ## Screenshots ![image](static/marken_90.png) @@ -85,8 +84,8 @@ It uses files to store the data. Other adapters are coming soon ## Support Me -[Sponsor Me](https://github.com/sponsors/rajnandan1) +If you are using Kener and want to support me, you can do so by sponsoring me on GitHub or buying me a coffee. - +[Sponsor Me Using Github](https://github.com/sponsors/rajnandan1) - +[Buy Me a Coffee](https://www.buymeacoffee.com/rajnandan1) diff --git a/scripts/startup.js b/build.js similarity index 60% rename from scripts/startup.js rename to build.js index 8e8042ebb..4329052fe 100644 --- a/scripts/startup.js +++ b/build.js @@ -1,29 +1,17 @@ -/* -The startup js script will -check if monitors.yaml exists -if it does, it will read the file and parse it into a json array of objects -each objects will have a name, url, method: required -name of each of these objects need to be unique -*/ -import * as dotenv from "dotenv"; -import fs from "fs-extra"; import yaml from "js-yaml"; -import { Cron } from "croner"; -import { FOLDER, FOLDER_MONITOR, FOLDER_SITE, API_TIMEOUT } from "./constants.js"; +import fs from "fs-extra"; +import axios from "axios"; import { IsValidURL, + checkIfDuplicateExists, + getWordsStartingWithDollar, IsValidHTTPMethod, - LoadMonitorsPath, - LoadSitePath, ValidateIpAddress -} from "./tool.js"; -import { GetAllGHLabels, CreateGHLabel } from "./github.js"; -import { Minuter } from "./cron-minute.js"; -import axios from "axios"; -import { Ninety } from "./ninety.js"; -let monitors = []; -let site = {}; -const envSecrets = []; +} from "./src/lib/server/tool.js"; +import { API_TIMEOUT, AnalyticsProviders } from "./src/lib/server/constants.js"; + +const configPathFolder = "./config"; +const databaseFolder = process.argv[2] || "./database"; const defaultEval = `(function (statusCode, responseTime, responseData) { let statusCodeShort = Math.floor(statusCode/100); if(statusCode == 429 || (statusCodeShort >=2 && statusCodeShort <= 3)) { @@ -37,37 +25,34 @@ const defaultEval = `(function (statusCode, responseTime, responseData) { latency: responseTime, } })`; - -function checkIfDuplicateExists(arr) { - return new Set(arr).size !== arr.length; -} -function getWordsStartingWithDollar(text) { - const regex = /\$\w+/g; - const wordsArray = text.match(regex); - return wordsArray || []; -} -if (!fs.existsSync(FOLDER)) { - fs.mkdirSync(FOLDER); - console.log(".kener folder created successfully!"); -} - -const Startup = async () => { +async function Build() { + console.log("Building Kener..."); + let site = {}; + let monitors = []; try { - const fileContent = fs.readFileSync(LoadMonitorsPath(), "utf8"); - site = yaml.load(fs.readFileSync(LoadSitePath(), "utf8")); - monitors = yaml.load(fileContent); + site = yaml.load(fs.readFileSync(configPathFolder + "/site.yaml", "utf8")); + monitors = yaml.load(fs.readFileSync(configPathFolder + "/monitors.yaml", "utf8")); } catch (error) { console.log(error); process.exit(1); } - // Use the 'monitors' array of JSON objects as needed - //check if each object has name, url, method - //if not, exit with error - //if yes, check if name is unique + if ( + site.github === undefined || + site.github.owner === undefined || + site.github.repo === undefined + ) { + console.log("github owner and repo are required"); + process.exit(1); + } + + const FOLDER_DB = databaseFolder; + const FOLDER_SITE = FOLDER_DB + "/site.json"; + const FOLDER_MONITOR = FOLDER_DB + "/monitors.json"; for (let i = 0; i < monitors.length; i++) { const monitor = monitors[i]; + let name = monitor.name; let tag = monitor.tag; let hasAPI = monitor.api !== undefined && monitor.api !== null; @@ -143,6 +128,7 @@ const Startup = async () => { let evaluator = monitor.api.eval; let body = monitor.api.body; let timeout = monitor.api.timeout; + let hideURLForGet = !!monitor.api.hideURLForGet; //url if (!!url) { if (!IsValidURL(url)) { @@ -168,7 +154,7 @@ const Startup = async () => { try { JSON.parse(JSON.stringify(headers)); } catch (error) { - console.log("headers are not valid. Quiting"); + console.log("headers are not valid. Quitting"); process.exit(1); } } @@ -213,9 +199,10 @@ const Startup = async () => { } //add a description to the monitor if it is website using api.url and method = GET and headers == undefined - //call the it to see if recevied content-type is text/html + //call the it to see if received content-type is text/html //if yes, append to description if ( + !hideURLForGet && (headers === undefined || headers === null) && url !== undefined && method === "GET" @@ -240,8 +227,8 @@ const Startup = async () => { } } - monitors[i].path0Day = `${FOLDER}/${folderName}.0day.utc.json`; - monitors[i].path90Day = `${FOLDER}/${folderName}.90day.utc.json`; + monitors[i].path0Day = `${FOLDER_DB}/${folderName}.0day.utc.json`; + monitors[i].path90Day = `${FOLDER_DB}/${folderName}.90day.utc.json`; monitors[i].hasAPI = hasAPI; //secrets can be in url/body/headers @@ -260,16 +247,34 @@ const Startup = async () => { } } } - if ( - site.github === undefined || - site.github.owner === undefined || - site.github.repo === undefined - ) { - console.log("github owner and repo are required"); - process.exit(1); - } + if (site.github.incidentSince === undefined || site.github.incidentSince === null) { - site.github.incidentSince = 48; + site.github.incidentSince = 720; + } + if (site.siteName === undefined) { + site.siteName = site.title; + } + if (!!site.analytics) { + const providers = {}; + + for (let i = 0; i < site.analytics.length; i++) { + const element = site.analytics[i]; + if (!!AnalyticsProviders[element.type]) { + if (providers[element.type] === undefined) { + providers[element.type] = {}; + providers[element.type].measurementIds = []; + providers[element.type].script = AnalyticsProviders[element.type]; + } + providers[element.type].measurementIds.push(element.id); + } + } + site.analytics = providers; + } + if (!!!site.font || !!!site.font.cssSrc || !!!site.font.family) { + site.font = { + cssSrc: "https://fonts.googleapis.com/css2?family=Albert+Sans:ital,wght@0,100..900;1,100..900&display=swap", + family: "Albert Sans" + }; } if (checkIfDuplicateExists(monitors.map((monitor) => monitor.folderName)) === true) { console.log("duplicate monitor detected"); @@ -290,107 +295,6 @@ const Startup = async () => { console.log(error); process.exit(1); } +} - if (!!site.github && !!site.github.owner && !!site.github.repo) { - const ghowner = site.github.owner; - const ghrepo = site.github.repo; - const ghlabels = await GetAllGHLabels(ghowner, ghrepo); - const tagsAndDescription = monitors.map((monitor) => { - return { tag: monitor.tag, description: monitor.name }; - }); - //add incident label if does not exist - - if (ghlabels.indexOf("incident") === -1) { - await CreateGHLabel(ghowner, ghrepo, "incident", "Status of the site"); - } - if (ghlabels.indexOf("resolved") === -1) { - await CreateGHLabel(ghowner, ghrepo, "resolved", "Incident is resolved", "65dba6"); - } - if (ghlabels.indexOf("identified") === -1) { - await CreateGHLabel(ghowner, ghrepo, "identified", "Incident is Identified", "EBE3D5"); - } - if (ghlabels.indexOf("investigating") === -1) { - await CreateGHLabel( - ghowner, - ghrepo, - "investigating", - "Incident is investigated", - "D4E2D4" - ); - } - if (ghlabels.indexOf("incident-degraded") === -1) { - await CreateGHLabel( - ghowner, - ghrepo, - "incident-degraded", - "Status is degraded of the site", - "f5ba60" - ); - } - if (ghlabels.indexOf("incident-down") === -1) { - await CreateGHLabel( - ghowner, - ghrepo, - "incident-down", - "Status is down of the site", - "ea3462" - ); - } - //add tags if does not exist - for (let i = 0; i < tagsAndDescription.length; i++) { - const tag = tagsAndDescription[i].tag; - const description = tagsAndDescription[i].description; - if (ghlabels.indexOf(tag) === -1) { - await CreateGHLabel(ghowner, ghrepo, tag, description); - } - } - } - - // init monitors - for (let i = 0; i < monitors.length; i++) { - const monitor = monitors[i]; - if (!fs.existsSync(monitor.path0Day)) { - fs.ensureFileSync(monitor.path0Day); - fs.writeFileSync(monitor.path0Day, JSON.stringify({})); - } - if (!fs.existsSync(monitor.path90Day)) { - fs.ensureFileSync(monitor.path90Day); - fs.writeFileSync(monitor.path90Day, JSON.stringify({})); - } - - console.log("Initial Fetch for ", monitor.name); - await Minuter(envSecrets, monitor, site.github); - await Ninety(monitor); - } - - //trigger minute cron - - for (let i = 0; i < monitors.length; i++) { - const monitor = monitors[i]; - - let cronExpession = "* * * * *"; - if (monitor.cron !== undefined && monitor.cron !== null) { - cronExpession = monitor.cron; - } - console.log("Staring " + cronExpession + " Cron for ", monitor.name); - Cron(cronExpession, async () => { - await Minuter(envSecrets, monitor, site.github); - }); - } - - //pre compute 90 day data at 1 minute interval - Cron( - "* * * * *", - async () => { - for (let i = 0; i < monitors.length; i++) { - const monitor = monitors[i]; - Ninety(monitor); - } - }, - { - protect: true - } - ); -}; - -export { Startup }; +Build(); diff --git a/config/monitors.example.yaml b/config/monitors.example.yaml index 219c783d6..f6819498e 100644 --- a/config/monitors.example.yaml +++ b/config/monitors.example.yaml @@ -1,17 +1,10 @@ -- name: Google Search - description: Search the world's information, including webpages, images, videos and more. - tag: "google-search" - image: "/google.png" +- name: OkBookmarks + description: A free bookmark manager that lets you save and search your bookmarks in the cloud. + tag: "okbookmarks" + image: "https://okbookmarks.com/assets/img/extension_icon128.png" api: method: GET - url: https://www.google.com/webhp -- name: Svelte Website - description: Cybernetically enhanced web apps - tag: "svelte-website" - api: - method: GET - url: https://svelte.dev/ - image: "/svelte.svg" + url: https://okbookmarks.com - name: Earth description: Our blue planet tag: "earth" diff --git a/config/site.example.yaml b/config/site.example.yaml index fa73fdcd2..fe5e0a623 100644 --- a/config/site.example.yaml +++ b/config/site.example.yaml @@ -1,10 +1,13 @@ -title: "Kener" +title: "Kener - Open-Source and Modern looking Node.js Status Page for Effortless Incident Management" +siteName: "Kener.ing" home: "/" logo: "/logo.png" +siteURL: "https://kener.ing" +favicon: "/logo96.png" github: owner: "rajnandan1" repo: "kener" - incidentSince: 48 + incidentSince: 720 metaTags: description: "Kener: Open-source modern looking Node.js status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents. And the best part? Kener integrates seamlessly with GitHub, making incident management a team effort—making it easier for us to track and fix issues together in a collaborative and friendly environment." keywords: "Node.js status page, Incident management tool, Service monitoring, Service outage tracking, Real-time status updates, GitHub integration for incidents, Open-source status page, Node.js monitoring application, Service reliability, User-friendly incident management, Collaborative incident resolution, Seamless outage communication, Service disruption tracker, Real-time incident alerts, Node.js status reporting" @@ -21,11 +24,15 @@ metaTags: twitter:description: "Kener: Open-source Node.js status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents. And the best part? Kener integrates seamlessly with GitHub, making incident management a team effort—making it easier for us to track and fix issues together in a collaborative and friendly environment." nav: - name: "Documentation" - url: "/docs" + url: "/docs/home" - name: "Github" + iconURL: "/github.svg" url: "https://github.com/rajnandan1/kener" + - name: "Buy me a coffee" + iconURL: "/buymeacoffee.svg" + url: "https://buymeacoffee.com/rajnandan1" hero: - title: Kener is a Open-Source Status Page System + title: Kener is a Modern Open-Source Status Page System subtitle: Let your users know what's going on. footerHTML: | Made using @@ -41,4 +48,8 @@ i18n: zh-CN: "中文" ja: "日本語" vi: "Tiếng Việt" -theme: dark +pattern: "squares" +analytics: + - id: "G-Q3MLRXCBFT" + type: "GA" + diff --git a/config/static/.kener b/config/static/.kener deleted file mode 100644 index 53d195994..000000000 --- a/config/static/.kener +++ /dev/null @@ -1 +0,0 @@ -I am Empty File \ No newline at end of file diff --git a/database/.kener b/database/.kener new file mode 100644 index 000000000..251d0a516 --- /dev/null +++ b/database/.kener @@ -0,0 +1 @@ +database folder \ No newline at end of file diff --git a/db/.kener b/db/.kener new file mode 100644 index 000000000..d0ddae9a0 --- /dev/null +++ b/db/.kener @@ -0,0 +1 @@ +.kener \ No newline at end of file diff --git a/dev.js b/dev.js deleted file mode 100644 index 20d9bdc3b..000000000 --- a/dev.js +++ /dev/null @@ -1,2 +0,0 @@ -import { Startup } from "./scripts/startup.js"; -Startup(); diff --git a/docker-compose.yml b/docker-compose.yml index 3628d4387..d33da656c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,13 +1,16 @@ version: '3.7' services: kener: - image: rajnandan1/kener:latest # assuming this is final namespace/image - container_name: kener + image: rajnandan1/kener:release-candidate-0.0.16 # assuming this is final namespace/image + container_name: kener-rc + #env_file: .env #uncomment this, if you are using .env file environment: - TZ=Etc/GMT #- GH_TOKEN= #- API_TOKEN= - #- API_IP + #- API_IP= + #- API_IP_REGEX= + #- KENER_BASE_PATH= # If running on a LINUX HOST and not podman rootless these MUST BE SET # run "id $user" from command line and replace numbers below with output from command @@ -17,15 +20,8 @@ services: ### Most likely DO NOT need to change anything below this ### #- PORT=3000 Port app listens on IN CONTAINER - - ### If any of the below are changed make sure the bound volume is correct as well ### - #- CONFIG_DIR=/config - #- PUBLIC_KENER_FOLDER=/config/static - #- MONITOR_YAML_PATH=/config/monitors.yaml - #- SITE_YAML_PATH=/config/site.yaml - #- KENER_BASE_PATH=/status - ports: - '3000:3000/tcp' volumes: - - '/host/path/to/config:/config:rw' + - './database:/app/database:rw' + - './config:/app/config' diff --git a/docker/root/etc/s6-overlay/s6-rc.d/svc-app/run b/docker/root/etc/s6-overlay/s6-rc.d/svc-app/run index 6a00a2096..ff7586f96 100755 --- a/docker/root/etc/s6-overlay/s6-rc.d/svc-app/run +++ b/docker/root/etc/s6-overlay/s6-rc.d/svc-app/run @@ -3,5 +3,12 @@ echo -e "\nApp is starting!" export NODE_ENV=production cd /app || exit -exec \ - s6-setuidgid abc /usr/bin/node $NODE_ARGS /app/prod.js + +# Run build first +s6-setuidgid abc /usr/bin/node $NODE_ARGS /app/build.js && ( + # Run startup and main in parallel + s6-setuidgid abc /usr/bin/node $NODE_ARGS /app/src/lib/server/startup.js & + s6-setuidgid abc /usr/bin/node $NODE_ARGS /app/main.js & + # Wait for both processes + wait +) \ No newline at end of file diff --git a/docs/categorize-guide.md b/docs/categorize-guide.md new file mode 100644 index 000000000..54c0b23ac --- /dev/null +++ b/docs/categorize-guide.md @@ -0,0 +1,45 @@ +--- +title: Categorize Monitors Guide | Kener +description: Categorize Monitors in Kener +--- + +# Categorize Monitors + +Let us add a category to our monitors. + +## Sample monitors.yaml + +```yaml +- name: OkBookmarks + description: A free bookmark manager that lets you save and search your bookmarks in the cloud. + tag: "okbookmarks" + image: "https://okbookmarks.com/assets/img/extension_icon128.png" + api: + method: GET + url: https://okbookmarks.com +- name: Earth + description: Our blue planet + tag: "earth" + defaultStatus: "UP" + image: "/earth.png" + category: "Hello" +- name: Frogment + description: A free openAPI spec editor and linter that breaks down your spec into fragments to make editing easier and more intuitive. Visit https://www.frogment.com + tag: "frogment" + image: "/frogment.png" + api: + method: GET + url: https://www.frogment.com +``` + +## Sample site.yaml + +```yaml +#... +categories: + - name: Hello + description: Say Hello to the world +#... +``` + +The above will have OkBookmarks and Frogment under home. Earth will be under Hello category. diff --git a/docs/changelogs.md b/docs/changelogs.md new file mode 100644 index 000000000..75543bda6 --- /dev/null +++ b/docs/changelogs.md @@ -0,0 +1,42 @@ +--- +title: Changelogs | Kener +description: Changelogs for Kener +--- + +# Changelogs + +## v0.0.16 + + + + 🚀 + + +Here are the changes in this release + +### Features + +- Added support for `hideURLForGet` in monitors. Read more [here](/docs/monitors) +- New SVG badges for LIVE status. Read more [here](/docs/status-badges#live) +- `[Breaking Change]` Removed dependency on Environment variable `PUBLIC_KENER_FOLDER`. Read more [here](#v0-0-16-migration) +- Simplified build and deploy process +- Added support for fonts. Read more [here](/docs/customize-site#font) +- Added support for home page pattern. Read more [here](/docs/customize-site#pattern) +- Added support for adding your analytics provider. Read more [here](/docs/site-analytics) +- New Documentation Site +- Addes support for `sqaures` pattern in home page. Read more [here](/docs/customize-site#pattern) +- Redesigned the UI for better consistency +- Embed now supports background color using a parameter `bgc`. Read more [here](/docs/embed#javascript-parameters) +- Now title in `site.yaml` is `` and `siteName` is actually the name of the site. Read more [here](/docs/customize-site#siteName) + +### Migration + +#### Source + +- Move data from `PUBLIC_KENER_FOLDER` to `/database` file. +- Move `site.yaml` to `/config` folder +- Move `monitors.yaml` to `/config` folder + +#### Docker + +- Use `-v $(pwd)/database:/app/database` and `-v $(pwd)/config:/app/config` in your docker run command diff --git a/docs/custom-js-css-guide.md b/docs/custom-js-css-guide.md new file mode 100644 index 000000000..6d1b4a185 --- /dev/null +++ b/docs/custom-js-css-guide.md @@ -0,0 +1,24 @@ +--- +title: Custom JS and CSS Guide | Kener +description: Custom JS and CSS Guide for Kener +--- + +Here is a guide to add custom JS and CSS to your Kener instance. + +## Adding Custom JS + +Add your custom JS to `static/` file. And in the `src/app.html` file, add the following line: + +```html +<script src="/your-custom-js-file.js"></script> +``` + +## Adding Custom CSS + +Add your custom CSS to `static/` file. And in the `src/app.html` file, add the following line: + +```html +<link rel="stylesheet" href="/your-custom-css-file.css" /> +``` + +Do not forget to add the base path if you are using a subpath. For example, if you are using a subpath `/kener`, then the path should be `/kener/your-custom-js-file.js`. diff --git a/docs/customize-site.md b/docs/customize-site.md new file mode 100644 index 000000000..cce13056b --- /dev/null +++ b/docs/customize-site.md @@ -0,0 +1,337 @@ +--- +title: Customize Site - Site.yaml - Kener +description: Customize your Kener site using site.yaml +--- + +# Customize Site + +There is a folder called `./config`. Inside which there is a `site.yaml` file. You can modify this file to have your own branding and do few other things. + +## Sample site.yaml + +```yaml +title: "Kener" +siteName: "Kener.ing" +logo: "/logo.svg" +favicon: "/logo96.png" +home: "/" +theme: dark +github: + owner: "rajnandan1" + repo: "kener" + incidentSince: 72 +metaTags: + description: "Your description" + keywords: "keyword1, keyword2" +nav: + - name: "Documentation" + url: "/docs" + - name: "Github" + iconURL: "/github.svg" + url: "https://github.com/rajnandan1/kener" +siteURL: https://kener.ing +hero: + title: Kener is a Open-Source Status Page System + subtitle: Let your users know what's going on. +footerHTML: | + Made using + <a href="https://github.com/rajnandan1/kener" target="_blank" rel="noreferrer" class="font-medium underline underline-offset-4"> + Kener + </a> + an open source status page system built with Svelte and TailwindCSS. +i18n: + defaultLocale: "en" + locales: + en: "English" + hi: "हिन्दी" + zh-CN: "中文" + ja: "日本語" + vi: "Tiếng Việt" +pattern: "squares" +font: + cssSrc: "https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap" + family: '"Lato", sans-serif' +analytics: + - id: "G-QsFT" + type: "GA" + - id: "deasf0d350" + type: "AMPLITUDE" + - id: "FKOdsKener" + type: "MIXPANEL" +``` + +--- + +## title + +This translates to + +```html +<title>Your Title +``` + +--- + +## siteName + +This is the name that will be shown in the nav bar, top left corner of the page + +## logo + +URL of the logo that will be shown in the nav bar. You can also add your logo in the `static` folder. Use the path `/logo.svg` to refer to it if you have added `logo.svg` in the `static` folder. Otherwise, you can use any URL. + +## favicon + +URL of the favicon that will be shown in the browser tab. You can also add your favicon in the `static` folder. Use the path `/logo96.png` to refer to it if you have added `logo96.png` in the `static` folder. Otherwise, you can use any URL. + +## home + +This is the location where someone will be taken when they click on the site name in the nav bar + +## theme + +This is the default theme of the site that will be used when a user lands for the first time. It can be `light` or `dark`. Defaults to `light`. The user still gets the option to change the theme. + +As of now there is no option to change the colors of the theme using `site.yaml`. If you still want to change the colors you can do so by modifying the `src/app.postcss` file. + +## favicon + +It can be set by modifying the `` tag in `src/app.html` file. +Example add a png called `logo.png` file in `static/` and then + +```html +... + +... +``` + +--- + +## github + +For incident kener uses github comments. Create an empty [github](https://github.com) repo and add them to `site.yaml` + +```yaml +github: + owner: "username" + repo: "repository" + incidentSince: 72 +``` + +### owner + +Owner of the github repository. If the repository is `https://github.com/rajnandan1/kener` then the owner is `rajnandan1` + +### repo + +Repository name of the github repository. If the repository is `https://github.com/rajnandan1/kener` then the repo is `kener` + +### incidentSince + +`incidentSince` is in hours. It means if an issue is created before X hours then kener would not honor it. What it means is that kener would not show it active incident pages nor it will update the uptime. Default is 30\*24 hours. + +--- + +## metaTags + +Meta tags are nothing but html ``. You can use them for SEO purposes + +```yaml +metaTags: + description: "Your description" + keywords: "keyword1, keyword2" + og:image: "https://example.com/og.png" +``` + +will become + +```html + + + + + +``` + +--- + +## siteURL + +You can set this to generate SiteMaps + +```yaml +siteURL: https://kener.ing +``` + +Sitemaps urls will be `https://kener.ing/sitemap.xml` + +--- + +## hero + +Use hero to add a banner to your kener page + +```yaml +hero: + title: Kener is a Open-Source Status Page System + subtitle: Let your users know what's going on. +``` + +### title + +Title of the hero section + +### subtitle + +Subtitle of the hero section + +--- + +## nav + +You can add more links to your navbar. + +```yaml +nav: + - name: "Home" + url: "/home" +``` + +### name + +Name of the link + +### url + +URL of the link + +### iconURL + +Icon of the link. You can add an icon in the `static` folder and refer to it using the path `/github.svg` + +--- + +## categories + +You can define categories for your monitors. Each category can have a description. The monitors can be grouped by categories. +`name=home` will be shown in the home page. Categories are shown in the order they are defined in the yaml file. A dropdown will appear in the nav bar to select the category. + +```yaml +categories: + - name: API + description: "Kener provides a simple API for you to use to update your status page." + - name: home + description: "loroem ipsum lorem ipsum" +``` + +### name + +Name of the category + +### description + +Description of the category + +--- + +## footerHTML + +You can add HTML to the footer. You can add links to your social media or anything else. + +```yaml +footerHTML: | + Made using Kener an open source status page system built with Svelte and TailwindCSS. +``` + +--- + +## i18n + +You can add translations to your site. By default it is set to `en`. Available translations are present in `locales/` folders in the root directory. You can add more translations by adding a new file in the `locales` folder. + +### Enable + +Once you have added a new translation file in the `locales` folder, you can enable it by adding the locale code in the `site.yaml` file. + +Let us say you have added a `hi.json` file in the `locales` folder. You can enable it by adding the following to the `site.yaml` file. + +```yaml +i18n: + defaultLocale: en + locales: + en: English + hi: हिन्दी +``` + +### defaultLocale + +**_defaultLocale_**: The default locale to be used for a user when he or she visits for the first time. It is important to note that the default locale json file should be present in the locales folder. + +### locales + +**_locales_**: A list of locales that you want to enable. The key is the locale code and the value is the name of the language. The locale code should be the same as the json file name in the locales folder. `en` means `en.json` should be present in the locales folder. + +Adding more than one locales will enable a dropdown in the navbar to select the language. + +Selected languages are stored in cookies and will be used when the user visits the site again. + +There is no auto detection of the language. The user has to manually select the language. + +### Variables + +There are few variables that you you should not change, + +- %hours : This will be replaced by the hours +- %minutes : This will be replaced by the minutes +- %minute : This will be replaced by the minute +- %status : This will be replaced by the status + +--- + +## pattern + +You can set the background pattern of the site. It can be `squares`, `dots`, `none` + +--- + +## font + +You can set the font of the site. You can use google fonts or any other font. + +```yaml +font: + cssSrc: "https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap" + family: '"Lato", sans-serif' +``` + +### cssSrc + +URL of the font css + +### family + +Font family + +--- + +## analytics + +You can add analytics to your site. You can add multiple analytics. Supported analytics are `GA`, `AMPLITUDE`, `MIXPANEL` + +```yaml +analytics: + - id: "G-QsFT" + type: "GA" + - id: "deasf0d350" + type: "AMPLITUDE" + - id: "FKOdsKener" + type: "MIXPANEL" +``` + +## siteURL + +This is required for sitemap generation + +```yaml +siteURL: https://kener.ing +``` diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 000000000..9ad82999d --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,100 @@ +--- +title: Kener Deployment - From Source or Docker +description: Kener can be deployed in multiple ways. You can use the pre-built docker image or build from source. +--- + +# Deployment + +Kener can be deployed in multiple ways. You can use the pre-built docker image or build from source. + +## Prerequisites + +Make sure you have the following installed: + +- [Node.js](https://nodejs.org/en/download/) +- [npm](https://www.npmjs.com/get-npm) +- Make sure `./database` and `./config` directories are present in the root directory +- [config/site.yaml](/docs/customize-site) Contains information about the site +- [config/monitors.yaml](/docs/monitors) Contains your monitors and their related specifications +- [Set up Environment Variables](/docs/environment-vars). You can use a `.env` file or pass them as arguments. Be sure to add `NODE_ENV=production` for production deployment + +## NPM + +```shell +npm i +npm run build +npm run prod +``` + +## PM2 + +```shell +npm i +node build.js +pm2 start src/lib/server/startup.js +pm2 start main.js +``` + +## Docker + +[Dockerhub](https://hub.docker.com/r/rajnandan1/kener) + +```shell +docker.io/rajnandan1/kener:latest +``` + +[Github Packages](https://github.com/rajnandan1/kener/pkgs/container/kener) + +```shell +ghcr.io/rajnandan1/kener:latest +``` + +You should mount two host directories to persist your configuration and database. [Environmental variables](https://rajnandan1.github.io/kener-docs/docs/environment-vars) can be passed with `-e` An example `docker run` command: + +```shell +docker run \ + -v $(pwd)/database:/app/database \ + -v $(pwd)/config:/app/config \ + -p 3000:3000 \ + -e "GH_TOKEN=1234" \ + rajnandan1/kener +``` + +You can also use a .env file + +```shell +docker run \ + -v $(pwd)/database:/app/database \ + -v $(pwd)/config:/app/config \ + --env-file .env \ + -p 3000:3000 \ + rajnandan1/kener +``` + +Or use **Docker Compose** with the example [docker-compose.yaml](https://raw.githubusercontent.com/rajnandan1/kener/main/docker-compose.yml) + +## Using PUID and PGID + +If you are + +- running on a **linux host** (ie unraid) and +- **not** using [rootless containers with Podman](https://developers.redhat.com/blog/2020/09/25/rootless-containers-with-podman-the-basics#why_podman_) + +then you must set the [environmental variables **PUID** and **PGID**.](https://docs.linuxserver.io/general/understanding-puid-and-pgid) in the container in order for it to generate files/folders your normal user can interact it. + +Run these commands from your terminal + +- `id -u` -- prints UID for **PUID** +- `id -g` -- prints GID for **PGID** + +Then add to your docker command like so: + +```shell +docker run -d ... -e "PUID=1000" -e "PGID=1000" ... rajnandan1/kener +``` + +or substitute them in [docker-compose.yml](https://raw.githubusercontent.com/rajnandan1/kener/main/docker-compose.yml) + +## Base path + +By default kener runs on `/` but you can change it to `/status` or any other path. Read more about it [here](/docs/environment-vars/#kener-base-path) diff --git a/docs/embed.md b/docs/embed.md new file mode 100644 index 000000000..80c421f89 --- /dev/null +++ b/docs/embed.md @@ -0,0 +1,87 @@ +--- +title: Embed Monitor | Kener +description: Embed your monitor in your website +--- + +# Embed Monitor + +There are two ways to embed your monitor in your website + +## Javascript + +You can embed your monitor in your website using javascript. We recommend using this method as it takes care of the height of the embedded monitor. + +```html + +``` + +Here is an example + +```html + +``` + +### Parameters + +You can pass the following parameters to the embed code + +- `theme`: You can pass `light` or `dark` theme +- `monitor`: The monitor url +- `bgc`: Background color of the monitor. Only supports hex color codes. DO NOT include the `#` symbol + +Replace `[hostname]` with your kener hostname and `[tag]` with your monitor tag. + +### Demo + +
+ +
+ +## Iframe + +This is the simplest way to embed your monitor in your website. You can use the following code to embed your monitor in your website. + +```html + +``` + +Here is an example + +```html + +``` + +Replace `[hostname]` with your kener hostname and `[tag]` with your monitor tag. + +### Parameters + +You can pass the following parameters to the embed code + +- `theme`: You can pass `light` or `dark` theme +- `bgc`: Background color of the monitor. Only supports hex color codes. DO NOT include the `#` symbol + +### Demo + +
+ +
diff --git a/docs/environment-vars.md b/docs/environment-vars.md new file mode 100644 index 000000000..f1b5acf04 --- /dev/null +++ b/docs/environment-vars.md @@ -0,0 +1,100 @@ +--- +title: Environment Variables | Kener +description: Kener needs some environment variables to be set to run properly. Here are the list of environment variables that you need to set. +--- + +# Environment Variables + +Kener needs some environment variables to be set to run properly. Here are the list of environment variables that you need to set. + +All of these are optional but are required for specific features. + +## PORT + +Defaults to 3000 if not specified + +```shell +export PORT=4242 +``` + +## GH_TOKEN + +A github token to read issues and create labels. This is required for **incident management** + +```shell +export GH_TOKEN=your-github-token +``` + +## API_TOKEN + +To talk to **kener apis** you will need to set up a token. It uses Bearer Authorization + +```shell +export API_TOKEN=sometoken +``` + +## API_IP + +While using API you can set this variable to accept request from a **specific IP** + +```shell +export API_IP=127.0.0.1 +``` + +## API_IP_REGEX + +While using API you can set this variable to accept request from a specific IP that matches the regex. Below example shows an **IPv6 regex** + +```shell +export API_IP_REGEX=^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$ +``` + +If you set both API_IP and API_IP_REGEX, API_IP will be given preference + +## KENER_BASE_PATH + +By default kener runs on `/` but you can change it to `/status` or any other path. + +- Important: The base path should _**NOT**_ have a trailing slash and should start with `/` +- Important: This env variable should be present during both build and run time +- If you are using docker you will have to do your own build and set this env variable during `docker build` + +```shell +export KENER_BASE_PATH=/status +``` + +## Using .env + +You can also use a `.env` file to set these variables. Create a `.env` file in the root of the project and add the variables like below + +```shell +PORT=4242 +GH_TOKEN=your-github-token +API_TOKEN=sometoken +API_IP= +API_IP_REGEX= +KENER_BASE_PATH=/status +``` + +## Secrets + +Kener supports secrets in monitors. Let us say you have a monitor that is API based and you want to keep the API key secret. You can use the `secrets` key in the monitor to keep the API key secret. + +```yaml +- name: Example Secret Monitor + description: Monitor to show how to use secrets + tag: "secret" + api: + method: GET + url: https://api.example.com/users + headers: + Authorization: Bearer $CLIENT_SECRET +``` + +In the above example, the `CLIENT_SECRET` is a secret that you can set in the monitor. To properly make this work you will have to set up environment variables like below + +```shell +export CLIENT_SECRET=your-api-key +``` + +Remember to set the `CLIENT_SECRET` in your `.env` file if you are using one. diff --git a/docs/gh-setup.md b/docs/gh-setup.md new file mode 100644 index 000000000..7e7689e16 --- /dev/null +++ b/docs/gh-setup.md @@ -0,0 +1,46 @@ +--- +title: Github Setup | Kener +description: Kener uses github for incident management. Issues created in github using certain tags go to kener as incidents. +--- + +# Github Setup + +Kener uses github for incident management. Issues created in github using certain tags go to kener as incidents. + +## Step 1: Create Github Repository + +Create a Github Repository. It can be either public or private. After you have created a repository open `site.yaml` and add them like this + +```yaml +github: + owner: "username" + repo: "repository" +``` + +## Step 2: Create Github Token + +You can create either a classic token or personal access token + +### Creating Classic Token + +- Go to [Tokens](https://github.com/settings/tokens/new) +- Note: kener +- Expiration: No Expiration +- Scopes: write:packages +- Click on generate Token + +### Creating Personal Access Token + +- Go to [Personal Access Token](https://github.com/settings/personal-access-tokens/new) +- Token Name: kener +- Expiration: Use custom to select a calendar date +- Description: My Kener +- Repository access: Check Only Selected Repositories. Select your github repository +- Repository Permission: Select Issues Read Write +- Click on generate token + +## Step 3: Set environment + +```shell +export GH_TOKEN=github_pat_11AD3ZA3Y0 +``` diff --git a/docs/home.md b/docs/home.md new file mode 100644 index 000000000..f28523f45 --- /dev/null +++ b/docs/home.md @@ -0,0 +1,116 @@ +--- +title: Kener - A Sveltekit NodeJS Status Page System +description: Kener is an open-source Node.js status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents. +--- + +# Kener - A Sveltekit NodeJS Status Page System + +

+ kener example illustration +

+ +

+ + GitHub Repo stars + + + Awesome status page + + + Docker Kener + +

+
+ + + 🎊 + + + + 🔔 + + + + ⁉ + +
+
+
+ Live Demo +
+
+ Quick Start +
+
+ Clone +
+
+ Deploy +
+
+ APIs +
+
+ +## What is Kener? + +Kener: Open-source sveltekit status page tool, designed to make service monitoring and incident handling a breeze. It offers a sleek and user-friendly interface that simplifies tracking service outages and improves how we communicate during incidents. Kener integrates seamlessly with GitHub, making incident management a team effort—making. + +It uses files to store the data. + +Kener name is derived from the word "Kene" which means "how is it going" in Assamese, then .ing is added to make cooler. + +## Features + +### Monitoring and Tracking + +- Real-time monitoring +- Polls HTTP endpoint or Push data to monitor using Rest APIs +- Handles Timezones for visitors +- Categorize Monitors into different Sections +- Cron-based scheduling for monitors. Minimum per minute +- Flexible monitor configuration using YAML. Define your own parsing for monitor being UP/DOWN/DEGRADED +- Construct complex API Polls - Chain, Secrets etc +- Supports a Default Status for Monitors. Example defaultStatus=DOWN if you don't hit API per minute with Status UP +- Supports base path for hosting in k8s +- Pre-built docker image for easy deployment + +### Customization and Branding + +- Customizable status page using yaml or code +- Badge generation for status and uptime of Monitors +- Support for custom domains +- Embed Monitor as an iframe or widget +- Light + Dark Theme +- Internationalization support + +### Incident Management + +- Create Incidents using Github Issues - Rich Text +- Or use APIs to create Incidents + +### User Experience and Design + +- 100% Accessibility Score +- Easy installation and setup +- User-friendly interface +- Responsive design for various devices +- Auto SEO and Social Media ready + +## Technologies used + +- [SvelteKit](https://kit.svelte.dev/) +- [shadcn-svelte](https://www.shadcn-svelte.com/) + +## Inspired from + +- [Upptime](https://upptime.js.org/) + +## Support Me + +If you are using Kener and want to support me, you can do so by sponsoring me on GitHub or buying me a coffee. + +[Sponsor Me Using Github](https://github.com/sponsors/rajnandan1) + +[Buy Me a Coffee](https://www.buymeacoffee.com/rajnandan1) diff --git a/docs/how-it-works.md b/docs/how-it-works.md new file mode 100644 index 000000000..af60c3446 --- /dev/null +++ b/docs/how-it-works.md @@ -0,0 +1,38 @@ +--- +title: How it works | Kener +description: Folder structure and how Kener works +--- + +# How it works + +Kener has two parts. + +- Sveltekit application which is server rendered and is the frontend. It is running on Svelte 4. +- Hooks into the backend to get the data for your monitors + +## Folder structure + +```shell +├── src (svelte frontend files) +├── static (things put here can be referenced directly example static/logo.png -> /logo.png) +├── src +├──── routes +├────── (docs) (You can delete this, this has routes for documentation) +├──── lib +├────── server +├──────── config (Location for you site.yaml and monitos.yaml) +├──────── data (This is the location where server computate data is stored. Do not touch this) +├── docs (Documentation, you can delete this folder) +``` + +## Site.yaml + +This is the configuration file for your site. This is where you define the name of your site, the look and feel of your site etc. Read more about it [here](/docs/customize-site) + +## Monitors.yaml + +This is the configuration file for your monitors. This is where you define the monitors you want to show on your site. Read more about it [here](/docs/monitors) + +## Data + +Kener stores its data in a folder which is `./database`. This is where all the data is stored. You can delete this folder if you want to start fresh. diff --git a/docs/i18n.md b/docs/i18n.md new file mode 100644 index 000000000..8dfd2c4a2 --- /dev/null +++ b/docs/i18n.md @@ -0,0 +1,41 @@ +--- +title: i18n | Kener +description: Kener supports multiple languages. You can add translations to your site. +--- + +# i18n + +You can add translations to your site. By default it is set to `en`. Available translations are present in `/src/lib/locales/` folders in the root directory. You can add more translations by adding a new file in the `/src/lib/locales` folder. + +## How to enable a translation + +Once you have added a new translation file in the `locales` folder, you can enable it by adding the locale code in the `site.yaml` file. + +Let us say you have added a `hi.json` file in the `locales` folder. You can enable it by adding the following to the `site.yaml` file. + +```yaml +i18n: + defaultLocale: en + locales: + en: English + hi: हिन्दी +``` + +> **_defaultLocale:_** The default locale to be used. This will be the language used when a user visits the site for the first time. It is important to note that the default locale json file should be present in the locales folder. + +## Variables + +There are few variables that you you should not change, + +- %hours : This will be replaced by the hours +- %minutes : This will be replaced by the minutes +- %minute : This will be replaced by the minute +- %status : This will be replaced by the status + +> **locales:\_** A list of locales that you want to enable. The key is the locale code and the value is the name of the language. The locale code should be the same as the json file name in the locales folder. `en` means `en.json` should be present in the locales folder. + +Adding more than one locales will enable a dropdown in the navbar to select the language. + +Selected languages are stored in cookies and will be used when the user visits the site again. + +There is no auto detection of the language. The user has to manually select the language. diff --git a/docs/incident-management.md b/docs/incident-management.md new file mode 100644 index 000000000..f3ccd679b --- /dev/null +++ b/docs/incident-management.md @@ -0,0 +1,30 @@ +--- +title: Incident Management | Kener +description: Kener uses Github to power incident management using labels +--- + +# Incident Management + +Kener uses Github to power incident management using labels + +## Labels + +Kener auto creates labels for your monitors using the `tag` parameter + +- `incident`: If an issue is marked as incident it will show up in kener home page +- `incident-down`: If an issue is marked as incident-down and incident kener would make that monitor down +- `incident-degraded`: If an issue is marked as incident-degraded and incident then kener would make the monitor degraded +- `resolved`: Use this tag to mark the incident has RESOLVED +- `identified`: Use this tag to show that the root cause of the incident has been identified + +## Creating your first incident + +- Go to your github repo of kener +- Go to issues +- Create an issue. Give it a title +- In the body add [start_datetime:1702651340] and [end_datetime:1702651140] and add some description. Time is UTC +- Add `incident`, `incident-down` and the monitor tag. This will make the monitor down for 4 minutes + +If you clone the repo it gives you an issue template to create incidents + +Here is a [sample incident](https://github.com/rajnandan1/kener/issues/15) for your reference. diff --git a/docs/kener-apis.md b/docs/kener-apis.md new file mode 100644 index 000000000..e19a31e7e --- /dev/null +++ b/docs/kener-apis.md @@ -0,0 +1,409 @@ +--- +title: Kener APIs +description: Kener gives APIs to push data and create incident. +--- + +# Kener APIs + +Kener also gives APIs to push data and create incident. Before you use kener apis you will have to set an authorization token called `API_TOKEN`. This also has to be set as an environment variable. + +```shell +export API_TOKEN=some-token-set-by-you +``` + +Additonally you can set IP whitelisting by setting another environment token called `API_IP` or `API_IP_REGEX`. If you set both `API_IP` and `API_IP_REGEX`, `API_IP` will be given preference. Read more [here](/docs/environment-vars#api_ip) + +--- + +## Update Status - API + +![Static Badge](https://img.shields.io/badge/METHOD-POST-blue?style=flat-square) + +The update status API can be used to manually update the state of a monitor from a remote server. + +### Request Body + +| Parameter | Description | +| ------------------ | ------------------------------------------------------------------------------------ | +| status | `Required` Can be only UP/DOWN/DEGRADED | +| latency | `Required` In Seconds. Leave 0 if not required | +| timestampInSeconds | `Optional` Timestamp in UTC seconds. Defaults to now. Should between 90 Days and now | +| tag | `Required` Monitor Tag set in monitors.yaml | + +```shell +curl --request POST \ + --url http://your-kener.host/api/status \ + --header 'Authorization: Bearer some-token-set-by-you' \ + --header 'Content-Type: application/json' \ + --data '{ + "status": "DOWN", + "latency": 1213, + "timestampInSeconds": 1702405860, + "tag": "google-search" +}' +``` + +### Response + +```json +{ + "status": 200, + "message": "success at 1702405860" +} +``` + +This will update the status of the monitor with tag `google-search` to DOWN at UTC 1702405860 + +--- + +## Get Status - API + +![Static Badge](https://img.shields.io/badge/METHOD-GET-green?style=flat-square) + +Use this API to get the status of a monitor. + +### Request + +Replace `google-search` with your monitor tag in query param + +```shell +curl --request GET \ + --url 'http://your-kener.host/api/status?tag=google-search' \ + --header 'Authorization: Bearer some-token-set-by-you' +``` + +### Response + +```json +{ + "status": "UP", + "uptime": "9.0026", + "lastUpdatedAt": 1706447160 +} +``` + +--- + +## Create an Incident - API + +![Static Badge](https://img.shields.io/badge/METHOD-POST-blue?style=flat-square) + +Can be use to create an incident from a remote server + +### Request Body + +| Parameter | Description | +| ------------- | -------------------------------------------------------- | +| startDatetime | `Optional` When did the incident start in UTC second | +| endDatetime | `Optional` When did the incident end in UTC seconds | +| title | `Required` Title of the incident | +| body | `Optional` Body of the incident | +| tags | `Required` Array of String, Monitor Tags of the incident | +| impact | `Optional` Can be only DOWN/DEGRADED | +| isMaintenance | `Optional` Boolean if incident is a maintenance | +| isIdentified | `Optional` Incident identified | +| isResolved | `Optional` Incident resolved | + +```shell +curl --request POST \ + --url http://your-kener.host/api/incident \ + --header 'Authorization: Bearer some-token-set-by-you' \ + --header 'Content-Type: application/json' \ + --data '{ + "startDatetime": 1702405740, + "endDatetime": 1702405920, + "title": "Outage in Mumbai", + "body": "Login cluster is down in mumbai region", + "tags": ["google-search"], + "impact": "DOWN", + "isMaintenance": false, + "isIdentified": true, + "isResolved": false +}' +``` + +### Response + +```json +{ + "createdAt": 1703940450, + "closedAt": null, + "title": "Outage in Mumbai", + "tags": ["google-search"], + "incidentNumber": 12, + "startDatetime": 1702405740, + "endDatetime": 1702405920, + "body": "Login cluster is down in mumbai region", + "impact": "DOWN", + "isMaintenance": false, + "isIdentified": true, + "isResolved": false +} +``` + +--- + +## Update an Incident - API + +![Static Badge](https://img.shields.io/badge/METHOD-PATCH-yellow?style=flat-square) + +Can be use to update an incident from a remote server. It will clear values if not passed + +### Request Param + +- `incidentNumber`: Number of the incident + +### Request Body + +| Parameter | Description | +| ------------- | -------------------------------------------------------- | +| startDatetime | `Optional` When did the incident start in UTC second | +| endDatetime | `Optional` When did the incident end in UTC seconds | +| title | `Required` Title of the incident | +| body | `Optional` Body of the incident | +| tags | `Required` Array of String, Monitor Tags of the incident | +| impact | `Optional` Can be only DOWN/DEGRADED | +| isMaintenance | `Optional` Boolean if incident is a maintenance | +| isIdentified | `Optional` Incident identified | +| isResolved | `Optional` Incident resolved | + +```shell +curl --request PATCH \ + --url http://your-kener.host/api/incident/{incidentNumber} \ + --header 'Authorization: Bearer some-token-set-by-you' \ + --header 'Content-Type: application/json' \ + --data '{ + "startDatetime": 1702405740, + "endDatetime": 1702405920, + "title": "Outage in Mumbai", + "body": "Login cluster is down in mumbai region", + "tags": ["google-search"], + "impact": "DOWN", + "isMaintenance": false, + "isIdentified": true, + "isResolved": false +}' +``` + +### Response + +```json +{ + "createdAt": 1703940450, + "closedAt": null, + "title": "Outage in Mumbai", + "tags": ["google-search"], + "incidentNumber": 12, + "startDatetime": 1702405740, + "endDatetime": 1702405920, + "body": "Login cluster is down in mumbai region", + "impact": "DOWN", + "isMaintenance": false, + "isIdentified": true, + "isResolved": false +} +``` + +--- + +## Get an Incident - API + +![Static Badge](https://img.shields.io/badge/METHOD-GET-green?style=flat-square) + +Use `incidentNumber` to fetch an incident + +### Request Body + +```shell +curl --request GET \ + --url http://your-kener.host/api/incident/{incidentNumber} \ + --header 'Authorization: Bearer some-token-set-by-you' \ +``` + +### Response + +```json +{ + "createdAt": 1703940450, + "closedAt": null, + "title": "Outage in Mumbai", + "tags": ["google-search"], + "incidentNumber": 12, + "startDatetime": 1702405740, + "endDatetime": 1702405920, + "body": "Login cluster is down in mumbai region", + "impact": "DOWN", + "isMaintenance": false, + "isIdentified": true, + "isResolved": false +} +``` + +--- + +## Add Comment - API + +![Static Badge](https://img.shields.io/badge/METHOD-POST-blue?style=flat-square) + +Add comments for incident using `incidentNumber` + +### Request + +```shell +curl --request POST \ + --url http://your-kener.host/api/incident/{incidentNumber}/comment \ + --header 'Authorization: Bearer some-token-set-by-you' \ + --header 'Content-Type: application/json' \ + --data '{ + "body": "comment 1" +}' +``` + +### Response + +```json +{ + "commentID": 1873376745, + "body": "comment 1", + "createdAt": 1704123938 +} +``` + +--- + +## Get Comments - API + +![Static Badge](https://img.shields.io/badge/METHOD-GET-green?style=flat-square) + +Use this API to fetch all the comments for an incident + +### Request + +```shell +curl --request GET \ + --url http://your-kener.host/api/incident/{incidentNumber}/comment \ + --header 'Authorization: Bearer some-token-set-by-you' \ +``` + +### Response + +```json +[ + { + "commentID": 1873372042, + "body": "comment 1", + "createdAt": 1704123116 + }, + { + "commentID": 1873372169, + "body": "comment 2", + "createdAt": 1704123139 + } +] +``` + +--- + +## Update Incident Status - API + +![Static Badge](https://img.shields.io/badge/METHOD-POST-blue?style=flat-square) + +Use this to API to update the status of an ongoing incident. + +### Request Body + +| Parameter | Description | +| ------------ | ------------------------------------------------------------ | +| isIdentified | `Optional` Boolean, set it when incident has been identified | +| isResolved | `Optional` Boolean, set it when incident has been resolved | +| endDatetime | `Optional` When did the incident end in UTC seconds | + +### Request + +```shell +curl --request POST \ + --url http://your-kener.host/api/incident/{incidentNumber}/status \ + --header 'Authorization: Bearer some-token-set-by-you' \ + --header 'Content-Type: application/json' \ + --data '{ + "isIdentified": true, + "isResolved": false + "endDatetime": 1702405920 +}' +``` + +### Response + +```json +{ + "createdAt": 1703940450, + "closedAt": null, + "title": "Outage in Mumbai", + "tags": ["google-search"], + "incidentNumber": 12, + "startDatetime": 1702405740, + "endDatetime": 1702405920, + "body": "Login cluster is down in mumbai region", + "impact": "DOWN", + "isMaintenance": false, + "isIdentified": true, + "isResolved": false +} +``` + +--- + +## Search Incidents - API + +![Static Badge](https://img.shields.io/badge/METHOD-POST-blue?style=flat-square) + +Use this to API to search incidents. + +### Request Body + +| Parameter | Description | +| ------------------ | ---------------------------------------------------------------------------------------------- | +| state | `Optional` open or closed. Default is open | +| tags | `Optional` Comma separated monitor tags, example: earth,google-seach | +| page | `Optional` Page number, starts with 1, defaults to 1 | +| per_page | `Optional` Page size, defaults to 10, max is 100 | +| created_after_utc | `Optional` timestamp in UTC seconds when the incident was created after. Example: 1702405920 | +| created_before_utc | `Optional` timestamp in UTC seconds when the incident was created before . Example: 1702405920 | +| title_like | `Optional` search incidents with title | + +### Request + +Search incidents that are closed and title contains `hello incident` + +```shell +curl --request POST \ + --url http://your-kener.host/api/incident?state=closed&title_like=Hello%20Incident \ + --header 'Authorization: Bearer some-token-set-by-you' \ + --header 'Content-Type: application/json' \ + --data '{ + "isIdentified": true, + "isResolved": false + "endDatetime": 1702405920 +}' +``` + +### Response + +```json +[ + { + "createdAt": 1703940450, + "closedAt": null, + "title": "Outage in Mumbai - Hello Incident", + "tags": ["google-search"], + "incidentNumber": 12, + "startDatetime": 1702405740, + "endDatetime": 1702405920, + "body": "Login cluster is down in mumbai region", + "impact": "DOWN", + "isMaintenance": false, + "isIdentified": true, + "isResolved": false + } +] +``` diff --git a/docs/monitor-examples.md b/docs/monitor-examples.md new file mode 100644 index 000000000..d3eeed500 --- /dev/null +++ b/docs/monitor-examples.md @@ -0,0 +1,207 @@ +--- +title: Monitor Examples | Kener +description: Here are some exhaustive examples for monitors +--- + +# Monitor Examples + +Here are some exhaustive examples for monitors + +## Simple GET Monitor + +Below example will call https://www.google.com/webhp. If the status code is 200 then it will be UP else DOWN. + +```yaml +- name: Google Search + tag: "google-search" + api: + method: GET + url: https://www.google.com/webhp +``` + +## Simple GET Monitor Without Hyperlink + +Below example will call https://www.google.com/webhp. If the status code is 200 then it will be UP else DOWN. It will not show the GET hyperlink in the monitor description. + +```yaml +- name: Google Search + tag: "google-search" + api: + method: GET + url: https://www.google.com/webhp + hideURLForGet: true +``` + +## Monitor with HTML description + +Below example will call https://www.google.com/webhp. If the status code is 200 then it will be UP else DOWN. It will show the description in HTML format. + +```yaml +- name: Google Search + tag: "google-search" + description: "Hello world" + api: + method: GET + url: https://www.google.com/webhp +``` + +## Monitor with image + +google.png is in the static folder + +```yaml +- name: Google Search + tag: "google-search" + image: "/google.png" + api: + method: GET + url: https://www.google.com/webhp +``` + +## Get Monitor 15 Minute + +Below example will call https://www.google.com/webhp every 15 minutes. If the status code is 200 then it will be UP else DOWN. + +```yaml +- name: Google Search + description: Search the world's information, including webpages, images, videos and more. + tag: "google-search" + cron: "*/15 * * * *" + api: + method: GET + url: https://www.google.com/webhp +``` + +## POST Monitor With Body + +Below example will call https://www.google.com/webhp with body. If the status code is 200 then it will be UP else DOWN. + +```yaml +- name: Google Search + description: Google Search + tag: "google-search-post" + api: + method: POST + url: https://www.google.com/webhp + headers: + Content-Type: application/json + body: '{"order_amount":22222.1,"order_currency":"INR"}' +``` + +## Secrets in Header + +You can set ENV variables in your machine and use them in your monitors. Example below has `GH_TOKEN` as an environment variable. It uses process.env.GH_TOKEN. + +``` +export GH_TOKEN=some.token.for.github +``` + +> **_NOTE:_** DO NOT forget the `$` sign in your monitor secret, otherwise it will not be picked up. + +```yaml +- name: Github Issues + description: Github Issues Fetch + tag: "gh-search-issue" + api: + method: GET + url: https://api.github.com/repos/rajnandan1/kener/issues + headers: + Authorization: Bearer $GH_TOKEN +``` + +## Secrets in Body + +Assuming `ORDER_ID` is present in env + +```yaml +- name: Github Issues + description: Github Issues Fetch + tag: "gh-search-issue" + api: + method: POST + url: https://api.github.com/repos/rajnandan1/kener/issues + headers: + Content-Type: application/json + body: '{"order_amount":22222.1,"order_currency":"INR", "order_id": "$ORDER_ID"}' +``` + +## Eval Body + +Read more about [eval](https://kener.ing/docs/monitors#eval) + +Below example will call https://api.github.com/repos/rajnandan1/kener/issues. If the status code is 200 then it will be UP else DOWN. It will also check if the response time is greater than 2000ms then it will be DEGRADED. + +```yaml +- name: Github Issues + description: Github Issues Fetch + tag: "gh-search-issue" + api: + method: GET + url: https://api.github.com/repos/rajnandan1/kener/issues + eval: | + (function(statusCode, responseTime, responseDataBase64){ + const resp = JSON.parse(atob(responseDataBase64)); + let status = 'DOWN' + if(statusCode == 200) status = 'UP'; + if(Object.keys(resp).length == 0) status = 'DOWN'; + if(statusCode == 200 && responseTime > 2000) status = 'DEGRADED'; + return { + status: status, + latency: responseTime, + } + }) +``` + +## With defaultStatus UP + +Each minute it will set the status as UP + +```yaml +- name: Earth + description: Our Planet + tag: "earth" + defaultStatus: UP +``` + +## With Category + +Add this monitor to the API category instead of the default home category + +```yaml +- name: Earth + description: Our Planent + tag: "earth" + category: API +``` + +## Ping Monitor + +This will ping the hosts. It will be up if the ping is successful for all the hosts present in the list of ip4 and ip6. + +```yaml +- name: Earth + description: Our Planent + tag: "earth" + ping: + hostsV4: + - www.frogment.com + - 52.84.205.24 + hostsV6: + - ipv6.google.com +``` + +If both ping and api monitors are present then API data will overwrite ping data + +## Custom Thresholds + +The below monitor will show DEGRADED if 3 or more degraded status in a day and DOWN if 2 or more down status in a day. It will also include degraded in downtime calculation. + +```yaml +- name: Earth + description: Our blue planet + tag: "earth" + defaultStatus: "UP" + dayDegradedMinimumCount: 3 + dayDownMinimumCount: 2 + includeDegradedInDowntime: true +``` diff --git a/docs/monitors.md b/docs/monitors.md new file mode 100644 index 000000000..bc530ba6b --- /dev/null +++ b/docs/monitors.md @@ -0,0 +1,96 @@ +--- +title: Monitors | monitors.yaml | Kener +description: Monitors are the heart of Kener. This is where you define the monitors you want to show on your site. +--- + +# Monitors + +Inside `config/` folder there is a file called `monitors.yaml`. We will be adding our monitors here. Please note that your yaml must be valid. It is an array. + +## Understanding monitors + +Each monitor runs at 1 minute interval by default. Monitor runs in below priorty order. + +- defaultStatus Data +- API call Data overrides above data(if specified) +- Pushed Status Data overrides API Data using [Kener Update Statue API](https://rajnandan1.github.io/kener-docs/docs/kener-apis#update-status) +- Manual Incident Data overrides Pushed Status Data + +Sample + +```yaml +- name: Google Search + description: Search the world's information, including webpages, images, videos and more. + tag: "google-search" + image: "/google.png" + cron: "* * * * *" + defaultStatus: "UP" + api: + timeout: 4000 + method: POST + url: https://www.google.com/webhp + headers: + Content-Type: application/json + body: '{"order_amount":1,"order_currency":"INR"}' + eval: | + (function(statusCode, responseTime, responseDataBase64){ + const resp = JSON.parse(atob(responseDataBase64)); + return { + status: statusCode == 200 ? 'UP':'DOWN', + latency: responseTime, + } + }) +``` + +| name | Required | This will be shown in the UI to your users. Keep it short and unique | +| ------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| name | Required + Unique | This will be shown in the UI to your users. Keep it short and unique | +| description | Optional | This will be show below your name | +| tag | Required + Unique | This is used to tag incidents created in Github using comments | +| image | Optional | To show a logo before the name | +| cron | Optional | Use cron expression to specify the interval to run the monitors. Defaults to `* * * * *` i.e every minute | +| api.timeout | Optional | timeout for the api in milliseconds. Default is 10000(10 secs) | +| api.method | Optional | HTTP Method | +| api.url | Optional | HTTP URL | +| api.headers | Optional | HTTP headers | +| api.body | Optional | HTTP Body as string | +| api.hideURLForGet | Optional | if the monitor is a GET URL and no headers are specified and the response body content-type is a text/html then kener shows a GET hyperlink in monitor description. To hide that set this as false. Default is true | +| api.eval | Optional | Evaluator written in JS, to parse HTTP response and calculate uptime and latency | +| defaultStatus | Optional | If no API is given this will be the default status. can be UP/DOWN/DEGRADED | +| hidden | Optional | If set to `true` will not show the monitor in the UI | +| category | Optional | Use this to group your monitors. Make sure you have defined category in `site.yaml` and use the `name` attribute. More about it [here](/docs/customize-site#categories). | +| dayDegradedMinimumCount | Optional | Default is 1. It means minimum this number of count for the day to be classified as DEGRADED(Yellow Bar) in 90 day view. Has to be `number` greater than 0 | +| dayDownMinimumCount | Optional | Default is 1. It means minimum this number of count for the day to be classified as DOWN(Red Bar) in 90 day view. Has to be `number` greater than 0 | +| includeDegradedInDowntime | Optional | By deafault uptime percentage is calculated as (UP+DEGRADED/UP+DEGRADED+DOWN). Setting it as `true` will change the calculation to (UP/UP+DEGRADED+DOWN) | +| ping.hostsV4 | Optional | Array of hosts / IP to monitor ping response. Either domain name or IP4 | +| ping.hostsV6 | Optional | Array of hosts / IP to monitor ping response. Either domain name or IP6 | + +## eval + +This is a anonymous JS function, by default it looks like this. + +> **_NOTE:_** The eval function should always return a json object. The json object can have only status(UP/DOWN/DEGRADED) and lantecy(number) +> `{status:"DEGRADED", latency: 200}`. + +```javascript +(function (statusCode, responseTime, responseDataBase64) { + let statusCodeShort = Math.floor(statusCode/100); + let status = 'DOWN' + if(statusCodeShort >=2 && statusCodeShort <= 3) { + status = 'UP', + } + return { + status: 'DOWN', + latency: responseTime, + } +}) +``` + +- `statusCode` **REQUIRED** is a number. It is the HTTP status code +- `responseTime` **REQUIRED**is a number. It is the latency in milliseconds +- `responseDataBase64` **REQUIRED** is a string. It is the base64 encoded response data. To use it you will have to decode it + +```js +let decodedResp = atob(responseDataBase64); +//let jsonResp = JSON.parse(decodedResp) +``` diff --git a/docs/quick-start.md b/docs/quick-start.md new file mode 100644 index 000000000..ec7bfb808 --- /dev/null +++ b/docs/quick-start.md @@ -0,0 +1,39 @@ +--- +title: Quick Start | Kener +description: Get started with Kener +--- + +# Quick Start + +Please make sure you have [Node](https://nodejs.org/en) installed in your system. Minimum version required is `v16.17.0`. + +## Clone the repository + +```shell +git clone https://github.com/rajnandan1/kener.git +cd kener +``` + +## Install Dependencies + +```shell +npm install +``` + +## Configs + +- Rename `config/site.example.yaml` -> `config/site.yaml` +- Rename `config/monitors.example.yaml` -> `config/monitors.yaml` + +```shell +mv config/site.example.yaml config/site.yaml +mv config/monitors.example.yaml config/monitors.yaml +``` + +## Start Kener Development Server + +```bash +npm run dev +``` + +Kener Development Server would be running at PORT 3000. Go to [http://localhost:3000](http://localhost:3000) diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 000000000..00823dea6 --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,19 @@ +--- +title: Roadmap | Kener +description: Roadmap for Kener +--- + +# Roadmap + + + + 🌱 + + +- Move from file system to sqlite3 +- Add support for webhooks +- Support DNS probe +- App support for fly.io deployment +- Add Rate limiting to APIs + +Request a feature or start a discussion [here](https://github.com/rajnandan1/kener/discussions/119) diff --git a/docs/showcase.md b/docs/showcase.md new file mode 100644 index 000000000..72919bbd0 --- /dev/null +++ b/docs/showcase.md @@ -0,0 +1,22 @@ +# Kener Showcase + +This page is a showcase of how kener is getting used in the wild. If you want to add your site here, please raise a PR and modify this [file](https://github.com/rajnandan1/kener-docs/blob/main/docs/md/docs/showcase.md) + +#### [Kener](https://kener.ing) +#### [Cashfree Payments India](https://statuspage.cashfree.com/) +#### [status.orhun.dev](https://status.orhun.dev/) +#### [status.ordinalsbot.com](https://status.ordinalsbot.com/) +#### [status.britsov.com](https://status.britsov.net/) +#### [status.gosu.bar](https://status.gosu.bar/) +#### [stat.imsun.org](https://stat.imsun.org/) +#### [Goomer](https://status.goomer.com.br/) +#### [kennek.io](https://status.kennek.io/) +#### [evelan.io](https://status.evelan.io/) +#### [evelan.io](https://status.evelan.io/) +#### [sveir.xyz](https://status.sveir.xyz/) +#### [cellcast.com](https://status.cellcast.com/) +#### [flytbase.com](https://status.flytbase.com/) +#### [scriptor-artis.fr](https://status.scriptor-artis.fr/) +#### [jiance.f.ozizio.com](http://jiance.f.ozizio.com/) +#### [sshaw.cn](https://s.sshaw.cn/) +#### [donotes.app](https://status.donotes.app) diff --git a/docs/site-analytics.md b/docs/site-analytics.md new file mode 100644 index 000000000..bb3ff0271 --- /dev/null +++ b/docs/site-analytics.md @@ -0,0 +1,54 @@ +--- +title: Site Analytics | Kener +description: Add Google Analytics, Amplitude, Mixpanel etc to your Kener site +--- + +# Site Analytics + +You can add Google Analytics, Amplitude, Mixpanel etc to your Kener site. In order to do this, you need to add the following configuration to your `site.yaml` file. + +```yaml +analytics: + - id: "G-QsFT" + type: "GA" + - id: "deasf0d350" + type: "AMPLITUDE" + - id: "FKOdsKener" + type: "MIXPANEL" +``` + +## Google Analytics + +To add Google Analytics to your site, you need to add the following configuration to your `site.yaml` file. + +```yaml +analytics: + - id: "G-QsFT" + type: "GA" +``` + +`id` is the tracking ID of your Google Analytics account. You can find this in your Google Analytics account. + +## Amplitude + +To add Amplitude to your site, you need to add the following configuration to your `site.yaml` file. + +```yaml +analytics: + - id: "deasf0d350" + type: "AMPLITUDE" +``` + +`id` is the API key of your Amplitude account. You can find this in your Amplitude account. + +## Mixpanel + +To add Mixpanel to your site, you need to add the following configuration to your `site.yaml` file. + +```yaml +analytics: + - id: "FKOdsKener" + type: "MIXPANEL" +``` + +`id` is the token of your Mixpanel account. You can find this in your Mixpanel account. diff --git a/docs/status-badges.md b/docs/status-badges.md new file mode 100644 index 000000000..d97cef672 --- /dev/null +++ b/docs/status-badges.md @@ -0,0 +1,174 @@ +--- +title: Status Badges | Kener +description: Status badges for your monitors +--- + +# Status Badges + +There are three types of badges + +Syntax + +```md +http://[hostname]/badge/[tag]/status +http://[hostname]/badge/[tag]/dot +http://[hostname]/badge/[tag]/uptime +``` + +--- + +## Status + +Shows the last health check was UP/DOWN/DEGRADED + +![Earth Status](https://kener.ing/badge/earth/status) + +Example in HTML + +```html + +``` + +Example in MarkDown + +```md +![Status Badge](https://kener.ing/badge/[monitor.tag]/status) +``` + +--- + +## Live + +Shows the last health check was UP/DOWN/DEGRADED as SVG dot + +```shell +http://[hostname]/badge/[tag]/dot +#or +http://[hostname]/badge/[tag]/dot?animate=ping +``` + +### Standard + +![Earth Status](/badge/earth/dot) + +```html + +``` + +### Animated + +![Earth Status](/badge/earth/dot?animate=ping) + +```html + +``` + +--- + +## Uptime + +Shows the 90 Day uptime by default. You can `sinceLast` as query param to get uptime since last x seconds. + +![Earth Uptime](https://kener.ing/badge/earth/uptime) + +### 90 Day Uptime + +Example in HTML + +```html + +``` + +Example in MarkDown + +```md +![Uptime Badge](https://kener.ing/badge/[monitor.tag]/uptime) +``` + +### 15 Minute Uptime + +Example in HTML + +```html + +``` + +Example in MarkDown + +```md +![Uptime Badge](https://kener.ing/badge/[monitor.tag]/uptime?sinceLast=900) +``` + +--- + +## Customize Badges + +You can set different colors for badges and style. + +### With Custom Label Color + +![Earth Status](https://kener.ing/badge/earth/status?labelColor=F2BED1) + +```md +![Earth Status](https://kener.ing/badge/earth/status?labelColor=F2BED1) +``` + +### With Custom Value Color + +![Earth Status](https://kener.ing/badge/earth/status?color=FFC0D9) + +```md +![Earth Status](https://kener.ing/badge/earth/status?color=FFC0D9) +``` + +### With Both Different Colors + +![Earth Status](https://kener.ing/badge/earth/uptime?color=D0BFFF&labelColor=FFF3DA) + +```md +![Earth Status](https://kener.ing/badge/earth/uptime?color=D0BFFF&labelColor=FFF3DA) +``` + +### Style Of the Badge + +You can change the style of the badge. Supported Styles are `plastic`, `flat`, `flat-square`, `for-the-badge` or `social`. Default is `flat` + +#### plastic + +![Earth Uptime](https://kener.ing/badge/earth/uptime?style=plastic) + +```md +![Earth Uptime](https://kener.ing/badge/earth/uptime?style=plastic) +``` + +#### flat + +![Earth Uptime](https://kener.ing/badge/earth/uptime?style=flat) + +```md +![Earth Uptime](https://kener.ing/badge/earth/uptime?style=flat) +``` + +#### flat-square + +![Earth Uptime](https://kener.ing/badge/earth/uptime?style=flat-square) + +```md +![Earth Uptime](https://kener.ing/badge/earth/uptime?style=flat-square) +``` + +#### for-the-badge + +![Earth Uptime](https://kener.ing/badge/earth/uptime?style=for-the-badge) + +```md +![Earth Uptime](https://kener.ing/badge/earth/uptime?style=for-the-badge) +``` + +#### social + +![Earth Uptime](https://kener.ing/badge/earth/uptime?style=social) + +```md +![Earth Uptime](https://kener.ing/badge/earth/uptime?style=social) +``` diff --git a/docs/structure.json b/docs/structure.json new file mode 100644 index 000000000..f9c70a946 --- /dev/null +++ b/docs/structure.json @@ -0,0 +1,124 @@ +{ + "sidebar": [ + { + "sectionTitle": "Getting Started", + "children": [ + { + "title": "Introduction", + "link": "/docs/home", + "file": "/home.md" + }, + { + "title": "Quick Start", + "link": "/docs/quick-start", + "file": "/docs/quick-start.md" + }, + { + "title": "How it works", + "link": "/docs/how-it-works", + "file": "/how-it-works.md" + }, + { + "title": "Changelogs", + "link": "/docs/changelogs", + "file": "/changelogs.md" + }, + { + "title": "Roadmap", + "link": "/docs/roadmap", + "file": "/roadmap.md" + } + ] + }, + { + "sectionTitle": "Core Concepts", + "children": [ + { + "title": "Site Configuration", + "link": "/docs/customize-site", + "file": "/customize-site.md" + }, + { + "title": "Monitors", + "link": "/docs/monitors", + "file": "/monitors.md" + }, + { + "title": "Monitors Examples", + "link": "/docs/monitor-examples", + "file": "/monitor-examples.md" + }, + { + "title": "Incident Management", + "link": "/docs/incident-management", + "file": "/incident-management.md" + }, + { + "title": "Localization", + "link": "/docs/i18n", + "file": "/i18n.md" + }, + { + "title": "Badges", + "link": "/docs/status-badges", + "file": "/status-badges.md" + }, + { + "title": "Embed", + "link": "/docs/embed", + "file": "/embed.md" + }, + { + "title": "Analytics", + "link": "/docs/site-analytics", + "file": "/site-analytics.md" + } + ] + }, + { + "sectionTitle": "Deployment", + "children": [ + { + "title": "Environment Setup", + "link": "/docs/environment-vars", + "file": "/environment-vars.md" + }, + { + "title": "Deployment", + "link": "/docs/deployment", + "file": "/deployment.md" + }, + { + "title": "Github Setup", + "link": "/docs/gh-setup", + "file": "/gh-setup.md" + } + ] + }, + { + "sectionTitle": "API Reference", + "children": [ + { + "title": "Kener APIs", + "link": "/docs/kener-apis", + "file": "/kener-apis.md" + } + ] + }, + { + "sectionTitle": "Guides", + "children": [ + { + "title": "Categorize Monitors", + "link": "/docs/categorize-guide", + "file": "/categorize-guide.md" + }, + { + "title": "Custom JS/CSS", + "link": "/docs/custom-js-css-guide", + "file": "/custom-js-css-guide.md" + } + ] + } + ] +} diff --git a/prod.js b/main.js similarity index 68% rename from prod.js rename to main.js index 805591846..19dd89ac7 100644 --- a/prod.js +++ b/main.js @@ -1,28 +1,25 @@ import { handler } from "./build/handler.js"; +import dotenv from "dotenv"; +dotenv.config(); import express from "express"; -import { STATUS_OK } from "./scripts/check.js"; -import { Startup } from "./scripts/startup.js"; -import sitemap from "./scripts/sitemap.js"; +import sitemap from "./sitemap.js"; const PORT = process.env.PORT || 3000; -console.log("STATUS_OK", STATUS_OK); -Startup(); const app = express(); app.use((req, res, next) => { if (req.path.startsWith("/embed")) { - res.setHeader("X-Frame-Options", "None"); + res.setHeader("Content-Security-Policy", "frame-ancestors *"); } + res.setHeader("X-Powered-By", "Kener"); next(); }); app.get("/healthcheck", (req, res) => { res.end("ok"); }); - app.get("/sitemap.xml", (req, res) => { res.setHeader("Content-Type", "application/xml"); res.end(sitemap); }); - app.use(handler); app.listen(PORT, () => { diff --git a/package-lock.json b/package-lock.json index 9820b50e2..7d3ff5703 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "kener", - "version": "0.0.14", + "version": "0.0.16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kener", - "version": "0.0.14", + "version": "0.0.16", "license": "MIT", "dependencies": { + "analytics": "^0.8.14", "axios": "^1.6.2", "badge-maker": "^3.3.1", "bits-ui": "^0.9.9", @@ -20,12 +21,16 @@ "js-yaml": "^4.1.0", "lucide-svelte": "^0.292.0", "marked": "^11.1.1", + "mode-watcher": "^0.4.1", "moment": "^2.29.4", "moment-timezone": "^0.5.43", "node-cache": "^5.1.2", + "npm-run-all": "^4.1.5", "ping": "^0.4.4", + "prismjs": "^1.29.0", "queue": "^7.0.0", "randomstring": "^1.3.0", + "svelte-legos": "^0.2.5", "tailwind-merge": "^2.0.0", "tailwind-variants": "^0.1.18" }, @@ -72,6 +77,78 @@ "node": ">=6.0.0" } }, + "node_modules/@analytics/cookie-utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@analytics/cookie-utils/-/cookie-utils-0.2.12.tgz", + "integrity": "sha512-2h/yuIu3kmu+ZJlKmlT6GoRvUEY2k1BbQBezEv5kGhnn9KpmzPz715Y3GmM2i+m7Y0QmBdVUoA260dQZkofs2A==", + "license": "MIT", + "dependencies": { + "@analytics/global-storage-utils": "^0.1.7" + } + }, + "node_modules/@analytics/core": { + "version": "0.12.15", + "resolved": "https://registry.npmjs.org/@analytics/core/-/core-0.12.15.tgz", + "integrity": "sha512-Y+zxTNIbONXKxeEUOtcXs4b3uuiGjF5sy1zHl8ZNkIBwrOpTM8ZGNhi0xGL8ZhaQLGbi03BrT6DaoNNG3sBQOg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/davidwells" + } + ], + "license": "MIT", + "dependencies": { + "@analytics/global-storage-utils": "^0.1.7", + "@analytics/type-utils": "^0.6.2", + "analytics-utils": "^1.0.12" + } + }, + "node_modules/@analytics/global-storage-utils": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@analytics/global-storage-utils/-/global-storage-utils-0.1.7.tgz", + "integrity": "sha512-V+spzGLZYm4biZT4uefaylm80SrLXf8WOTv9hCgA46cLcyxx3LD4GCpssp1lj+RcWLl/uXJQBRO4Mnn/o1x6Gw==", + "license": "MIT", + "dependencies": { + "@analytics/type-utils": "^0.6.2" + } + }, + "node_modules/@analytics/localstorage-utils": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@analytics/localstorage-utils/-/localstorage-utils-0.1.10.tgz", + "integrity": "sha512-uJS+Jp1yLG5VFCgA5T82ZODYBS0xuDQx0NtAZrgbqt9j51BX3TcgmOez5LVkrUNu/lpbxjCLq35I4TKj78VmOQ==", + "license": "MIT", + "dependencies": { + "@analytics/global-storage-utils": "^0.1.7" + } + }, + "node_modules/@analytics/session-storage-utils": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@analytics/session-storage-utils/-/session-storage-utils-0.0.7.tgz", + "integrity": "sha512-PSv40UxG96HVcjY15e3zOqU2n8IqXnH8XvTkg1X43uXNTKVSebiI2kUjA3Q7ESFbw5DPwcLbJhV7GforpuBLDw==", + "license": "MIT", + "dependencies": { + "@analytics/global-storage-utils": "^0.1.7" + } + }, + "node_modules/@analytics/storage-utils": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@analytics/storage-utils/-/storage-utils-0.4.2.tgz", + "integrity": "sha512-AXObwyVQw9h2uJh1t2hUgabtVxzYpW+7uKVbdHQK80vr3Td5rrmCxrCxarh7HUuAgSDZ0bZWqmYxVgmwKceaLg==", + "license": "MIT", + "dependencies": { + "@analytics/cookie-utils": "^0.2.12", + "@analytics/global-storage-utils": "^0.1.7", + "@analytics/localstorage-utils": "^0.1.10", + "@analytics/session-storage-utils": "^0.0.7", + "@analytics/type-utils": "^0.6.2" + } + }, + "node_modules/@analytics/type-utils": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@analytics/type-utils/-/type-utils-0.6.2.tgz", + "integrity": "sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==", + "license": "MIT" + }, "node_modules/@babel/runtime": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", @@ -820,10 +897,18 @@ "integrity": "sha512-7z/eR6O859gyWIAjuvBWFzNURmf2oPBmJlfVWkwehU5nzIyjwBsTh7WMmEEV4JFnHuQ3ex4oyTvfKzcyJVDBNA==", "dev": true }, + "node_modules/@types/dlv": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@types/dlv/-/dlv-1.1.5.tgz", + "integrity": "sha512-JHOWNfiWepAhfwlSw17kiWrWrk6od2dEQgHltJw9AS0JPFoLZJBge5+Dnil2NfdjAvJ/+vGSX60/BRW20PpUXw==", + "license": "MIT", + "peer": true + }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" }, "node_modules/@types/pug": { "version": "2.0.10", @@ -868,6 +953,35 @@ "char-width-table-consumer": "^1.0.0" } }, + "node_modules/analytics": { + "version": "0.8.14", + "resolved": "https://registry.npmjs.org/analytics/-/analytics-0.8.14.tgz", + "integrity": "sha512-ZKpqWHEHBrN0lvIsrUKmt0fcXNyQuKa0JUWDRAz7LgJ+Sf4ZX+a66/ai28W4H8kJJlLeItCrhIi/xvdbV08RlA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/davidwells" + } + ], + "license": "MIT", + "dependencies": { + "@analytics/core": "^0.12.15", + "@analytics/storage-utils": "^0.4.2" + } + }, + "node_modules/analytics-utils": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/analytics-utils/-/analytics-utils-1.0.12.tgz", + "integrity": "sha512-WvV2YWgsnXLxaY0QYux0crpBAg/0JA763NmbMVz22jKhMPo7dpTBet8G2IlF7ixTjLDzGlkHk1ZaKqqQmjJ+4w==", + "license": "MIT", + "dependencies": { + "@analytics/type-utils": "^0.6.2", + "dlv": "^1.1.3" + }, + "peerDependencies": { + "@types/dlv": "^1.0.0" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -927,11 +1041,49 @@ "dequal": "^2.0.3" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -974,22 +1126,39 @@ "postcss": "^8.1.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "node_modules/axobject-query": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", - "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", - "dependencies": { - "dequal": "^2.0.3" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" } }, "node_modules/badge-maker": { @@ -1039,9 +1208,10 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -1051,7 +1221,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -1065,6 +1235,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -1072,7 +1243,8 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/brace-expansion": { "version": "2.0.1", @@ -1084,11 +1256,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1151,6 +1324,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1159,6 +1333,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -1211,6 +1386,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/canvas-confetti": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.3.tgz", + "integrity": "sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==", + "license": "ISC", + "funding": { + "type": "donate", + "url": "https://www.paypal.me/kirilvatev" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1412,6 +1597,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1513,6 +1699,57 @@ "node": ">=4" } }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -1530,12 +1767,13 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1559,6 +1797,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -1571,6 +1810,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1583,6 +1839,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1599,6 +1856,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -1644,7 +1902,8 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.4.601", @@ -1659,17 +1918,88 @@ "dev": true }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -1681,8 +2011,52 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/es6-promise": { @@ -1740,7 +2114,17 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, "node_modules/esm-env": { "version": "1.0.0", @@ -1758,41 +2142,43 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1804,9 +2190,10 @@ } }, "node_modules/express/node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1848,9 +2235,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1859,12 +2247,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1879,6 +2268,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -1886,7 +2276,8 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/focus-trap": { "version": "7.5.4", @@ -1915,6 +2306,15 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -1953,6 +2353,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1996,6 +2397,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2009,6 +2437,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -2023,13 +2452,30 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", @@ -2053,6 +2499,22 @@ "node": ">= 6" } }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globalyzer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", @@ -2069,6 +2531,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -2081,6 +2544,15 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2094,6 +2566,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -2105,6 +2578,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -2116,6 +2590,22 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" }, @@ -2124,9 +2614,10 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -2134,10 +2625,17 @@ "node": ">= 0.4" } }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "license": "ISC" + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -2153,6 +2651,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -2200,6 +2699,20 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2208,6 +2721,40 @@ "node": ">= 0.10" } }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2219,6 +2766,22 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-builtin-module": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", @@ -2234,6 +2797,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-core-module": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", @@ -2245,6 +2820,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "license": "MIT", + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2279,14 +2884,42 @@ "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "dev": true }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-reference": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", @@ -2296,11 +2929,104 @@ "@types/estree": "*" } }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/jiti": { "version": "1.21.0", @@ -2321,6 +3047,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "license": "MIT" + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -2354,6 +3086,30 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", @@ -2422,14 +3178,27 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge2": { "version": "1.4.1", @@ -2448,11 +3217,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -2463,6 +3233,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -2531,6 +3302,15 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mode-watcher": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mode-watcher/-/mode-watcher-0.4.1.tgz", + "integrity": "sha512-bNC+1NXmwEFZtziCdZSgP7HFQTpqJPcQn9GwwJQGSf6SBF3neEPYV1uRwkYuAQwbsvsXIYtzaqgedDzJ7D1mhg==", + "license": "MIT", + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.1" + } + }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -2569,10 +3349,10 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/mz": { "version": "2.7.0", @@ -2609,6 +3389,12 @@ "node": ">= 0.6" } }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "license": "MIT" + }, "node_modules/node-cache": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", @@ -2626,6 +3412,18 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -2643,6 +3441,173 @@ "node": ">=0.10.0" } }, + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm-run-all/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npm-run-all/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/npm-run-all/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/npm-run-all/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/npm-run-all/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm-run-all/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2660,9 +3625,40 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2671,6 +3667,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -2698,10 +3695,24 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2729,9 +3740,31 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "license": "MIT", + "engines": { + "node": ">=4" + } }, "node_modules/periscopic": { "version": "3.1.0", @@ -2760,9 +3793,10 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -2775,6 +3809,18 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -2799,10 +3845,19 @@ "node": ">= 6" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.4.48", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.48.tgz", + "integrity": "sha512-GCRK8F6+Dl7xYniR5a4FYbpBzU8XnZVeowqsQFYdcXuSbChgiks7qybSkbvnaeqv0G0B+dd9/jJgH8kkLDQeEA==", "funding": [ { "type": "opencollective", @@ -2817,10 +3872,11 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -3045,6 +4101,21 @@ } } }, + "node_modules/prism-svelte": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.5.0.tgz", + "integrity": "sha512-db91Bf3pRGKDPz1lAqLFSJXeW13mulUJxhycysFpfXV5MIK7RgWWK2E5aPAa71s8TCzQUXxF5JOV42/iOs6QkA==", + "license": "MIT" + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -3063,11 +4134,12 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -3123,6 +4195,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3131,6 +4204,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -3149,6 +4223,20 @@ "pify": "^2.3.0" } }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "license": "MIT", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -3165,6 +4253,24 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -3263,10 +4369,11 @@ } }, "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", "dev": true, + "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -3321,6 +4428,24 @@ "node": ">=6" } }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -3340,10 +4465,28 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/sander": { "version": "0.5.1", @@ -3357,10 +4500,20 @@ "rimraf": "^2.5.2" } }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -3384,6 +4537,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -3391,22 +4545,28 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -3422,6 +4582,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -3434,10 +4595,26 @@ "node": ">= 0.4" } }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", @@ -3464,7 +4641,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3473,6 +4649,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -3516,9 +4693,10 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -3529,10 +4707,43 @@ "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", "dev": true }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "license": "CC0-1.0" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3551,6 +4762,73 @@ "node": ">=8" } }, + "node_modules/string.prototype.padend": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", + "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3563,6 +4841,15 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -3662,16 +4949,18 @@ } }, "node_modules/svelte": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.8.tgz", - "integrity": "sha512-hU6dh1MPl8gh6klQZwK/n73GiAHiR95IkFsesLPbMeEZi36ydaXL/ZAb4g9sayT0MXzpxyZjR28yderJHxcmYA==", + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", + "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.1", "@jridgewell/sourcemap-codec": "^1.4.15", "@jridgewell/trace-mapping": "^0.3.18", + "@types/estree": "^1.0.1", "acorn": "^8.9.0", "aria-query": "^5.3.0", - "axobject-query": "^3.2.1", + "axobject-query": "^4.0.0", "code-red": "^1.0.3", "css-tree": "^2.3.1", "estree-walker": "^3.0.3", @@ -3718,6 +5007,20 @@ "svelte": "^3.19.0 || ^4.0.0" } }, + "node_modules/svelte-legos": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/svelte-legos/-/svelte-legos-0.2.5.tgz", + "integrity": "sha512-r4HbLYripCLECgraqJMvsykW/8FaPBd1hLkt3ejJzJRfhhOnCgGTo6lJT27qrestDFbiIASQV3xOnjRr/D6cGw==", + "license": "MIT", + "dependencies": { + "canvas-confetti": "^1.6.0", + "prism-svelte": "^0.5.0", + "prismjs": "^1.29.0" + }, + "peerDependencies": { + "svelte": "^4.0.0" + } + }, "node_modules/svelte-preprocess": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.1.tgz", @@ -3937,6 +5240,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -3948,6 +5252,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } @@ -3984,6 +5289,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -3992,6 +5298,79 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typescript": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", @@ -4005,6 +5384,21 @@ "node": ">=14.17" } }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undici": { "version": "5.28.4", "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", @@ -4029,6 +5423,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -4076,6 +5471,16 @@ "node": ">= 0.4.0" } }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -4085,10 +5490,11 @@ } }, "node_modules/vite": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", - "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.5.tgz", + "integrity": "sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", @@ -4168,6 +5574,41 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 85d553cfa..ed1aba94b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kener", - "version": "0.0.15", + "version": "0.0.16", "private": false, "license": "MIT", "description": "Kener: An open-source Node.js status page application for real-time service monitoring, incident management, and customizable reporting. Simplify service outage tracking, enhance incident communication, and ensure a seamless user experience.", @@ -27,13 +27,15 @@ "url": "https://github.com/rajnandan1/kener.git" }, "scripts": { - "build": "node scripts/check.js && vite build", - "serve": "node prod.js", - "kener:dev": "cross-env NODE_ENV=development PUBLIC_KENER_FOLDER=./static/kener node scripts/check.js && concurrently \"cross-env NODE_ENV=development PUBLIC_KENER_FOLDER=./static/kener node dev.js\" \"cross-env NODE_ENV=development PUBLIC_KENER_FOLDER=./static/kener vite dev\"", - "kener:dev-monitor": "cross-env NODE_ENV=development PUBLIC_KENER_FOLDER=./static/kener node dev.js", - "kener:build": "cross-env NODE_ENV=production node scripts/check.js && cross-env NODE_ENV=production vite build", - "kener": "cross-env NODE_ENV=production node prod.js", - "prettify": "prettier --write ." + "build": "vite build", + "preview": "vite preview", + "preschedule": "node build.js", + "schedule": "node src/lib/server/startup.js", + "development": "vite dev", + "dev": "npm-run-all --parallel schedule development", + "prettify": "prettier --write .", + "start": "node main.js", + "prod": "npm-run-all --parallel schedule start" }, "devDependencies": { "@sveltejs/adapter-auto": "^2.0.0", @@ -56,6 +58,7 @@ }, "type": "module", "dependencies": { + "analytics": "^0.8.14", "axios": "^1.6.2", "badge-maker": "^3.3.1", "bits-ui": "^0.9.9", @@ -67,12 +70,16 @@ "js-yaml": "^4.1.0", "lucide-svelte": "^0.292.0", "marked": "^11.1.1", + "mode-watcher": "^0.4.1", "moment": "^2.29.4", "moment-timezone": "^0.5.43", "node-cache": "^5.1.2", + "npm-run-all": "^4.1.5", "ping": "^0.4.4", + "prismjs": "^1.29.0", "queue": "^7.0.0", "randomstring": "^1.3.0", + "svelte-legos": "^0.2.5", "tailwind-merge": "^2.0.0", "tailwind-variants": "^0.1.18" } diff --git a/scripts/constants.js b/scripts/constants.js deleted file mode 100644 index 83a11c1eb..000000000 --- a/scripts/constants.js +++ /dev/null @@ -1,15 +0,0 @@ -// Define your constants -import dotenv from "dotenv"; -dotenv.config(); -const FOLDER = process.env.PUBLIC_KENER_FOLDER; -const ENV = process.env.NODE_ENV; -const MONITOR = "./config/monitors.yaml"; -const SITE = "./config/site.yaml"; -const FOLDER_MONITOR = FOLDER + "/monitors.json"; -const FOLDER_SITE = FOLDER + "/site.json"; -const UP = "UP"; -const DOWN = "DOWN"; -const DEGRADED = "DEGRADED"; -const API_TIMEOUT = 10 * 1000; // 10 seconds -// Export the constants -export { FOLDER, FOLDER_MONITOR, FOLDER_SITE, MONITOR, UP, DOWN, SITE, DEGRADED, API_TIMEOUT, ENV }; diff --git a/scripts/testts.js b/scripts/testts.js deleted file mode 100644 index 8746c7143..000000000 --- a/scripts/testts.js +++ /dev/null @@ -1,12 +0,0 @@ -import { GetMinuteStartNowTimestampUTC, GetDayStartWithOffset, BeginningOfDay } from "./tool.js"; -let tzOffset = -330; -let ts = GetMinuteStartNowTimestampUTC(); -console.log("GetMinuteStartNowTimestampUTC India 12AM: " + ts); -let tm = GetDayStartWithOffset(GetMinuteStartNowTimestampUTC(), tzOffset); -console.log("GetMinuteStartTimestampUTC India 12AM: should be 18:30PM " + tm); -console.log( - `getUTCTimestampAtStartOfDayForOffset(${GetMinuteStartNowTimestampUTC()}, ${tzOffset})` -); - -console.log(BeginningOfDay({ timeZone: "GMT" })); -console.log(BeginningOfDay({ timeZone: "Asia/Kolkata", date: new Date(1703223388000) })); diff --git a/scripts/sitemap.js b/sitemap.js similarity index 83% rename from scripts/sitemap.js rename to sitemap.js index 392eed757..74c30707e 100644 --- a/scripts/sitemap.js +++ b/sitemap.js @@ -5,10 +5,8 @@ import fs from "fs-extra"; let siteMap = ""; import dotenv from "dotenv"; dotenv.config(); -const site = JSON.parse(fs.readFileSync(process.env.PUBLIC_KENER_FOLDER + "/site.json", "utf8")); -const monitors = JSON.parse( - fs.readFileSync(process.env.PUBLIC_KENER_FOLDER + "/monitors.json", "utf8") -); +const site = fs.readJSONSync("./database/site.json", "utf8"); +const monitors = fs.readJSONSync("./database/monitors.json", "utf8"); if (site.siteURL !== undefined && site.siteURL !== null && site.siteURL !== "") { if (monitors.length > 0) { siteMap = ` @@ -19,7 +17,8 @@ if (site.siteURL !== undefined && site.siteURL !== null && site.siteURL !== "") https://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"> ${monitors .map((monitor) => { - return ` + return ` + ${site.siteURL}/incident/${monitor.folderName} ${new Date().toISOString()} daily @@ -29,7 +28,8 @@ if (site.siteURL !== undefined && site.siteURL !== null && site.siteURL !== "") .join("\n")} ${monitors .map((monitor) => { - return ` + return ` + ${site.siteURL}/monitor-${encodeURIComponent(monitor.tag)} ${new Date().toISOString()} daily diff --git a/src/app.html b/src/app.html index 5e9022a65..65e635887 100644 --- a/src/app.html +++ b/src/app.html @@ -3,22 +3,12 @@ + + %sveltekit.head%
%sveltekit.body%
- - - - diff --git a/src/docs.css b/src/docs.css new file mode 100644 index 000000000..48b9faf2b --- /dev/null +++ b/src/docs.css @@ -0,0 +1,16 @@ +code:not([class^="language-"]) { + @apply rounded bg-gray-100 px-1.5 py-0.5 font-mono text-xs dark:bg-gray-800; +} + +.sidebar-item.active, +.sidebar-item:hover { + color: #ed702d; +} + +.w-585px { + width: 585px; +} + +main { + scroll-behavior: smooth; +} diff --git a/src/hooks.server.js b/src/hooks.server.js new file mode 100644 index 000000000..a45a1e273 --- /dev/null +++ b/src/hooks.server.js @@ -0,0 +1,7 @@ +// // @ts-nocheck +// // src/routes/+server.js +// import { Startup } from "$lib/server/startup.js"; +// import { STATUS_OK } from "$lib/server/check.js"; +// import { building } from "$app/environment"; + +// await Startup(); diff --git a/src/kener.css b/src/kener.css index 984e3ebda..fa7f27bb6 100644 --- a/src/kener.css +++ b/src/kener.css @@ -1,5 +1,6 @@ /*one is the class for dotted background*/ -.one { + +.dots-pattern { position: absolute; top: 0px; left: 0; @@ -12,7 +13,7 @@ clip-path: polygon(0 0, 100% 0, 100% 54%, 0% 100%); } -.one::after { +.dots-pattern::after { content: ""; position: absolute; background-image: radial-gradient(rgba(0, 0, 0, 0) 1.5px, var(--background-kener) 1px); @@ -24,6 +25,55 @@ left: 0; } +.squares-pattern { + position: absolute; + top: 0; + left: 0; + width: 100%; + z-index: 0; + background-repeat: no-repeat; + background-size: 100%; + height: 100svh; + + clip-path: polygon(0 0, 100% 0, 100% 54%, 0% 100%); + transform: blur(3px); +} + +.squares-pattern::after { + content: ""; + position: absolute; + background-image: linear-gradient(#444cf7 1px, transparent 1px), + linear-gradient(to right, #444cf7 1px, var(--background-kener) 1px); + -webkit-mask-image: linear-gradient( + to bottom, + rgba(0, 0, 0, 1) 0%, + rgba(0, 0, 0, 0.8) 20%, + rgba(0, 0, 0, 0.6) 40%, + rgba(0, 0, 0, 0.4) 60%, + rgba(0, 0, 0, 0.2) 80%, + rgba(0, 0, 0, 0) 100% + ); + mask-image: linear-gradient( + 180deg, + rgba(0, 0, 0, 0.2) 0%, + rgba(0, 0, 0, 0.1) 20%, + rgba(0, 0, 0, 0.05) 40%, + rgba(0, 0, 0, 0.025) 60%, + rgba(0, 0, 0, 0.0125) 80%, + rgba(0, 0, 0, 0) 100% + ); + background-size: 32px 32px; + width: 100%; + height: 100vh; + top: 0; + + left: 0; +} +.dark .squares-pattern::after { + background-image: linear-gradient(#677489 1px, transparent 1px), + linear-gradient(to right, #677489 1px, var(--background-kener) 1px); +} + /*Needed to overlay content on top of dotted bg*/ section { position: relative; @@ -78,13 +128,17 @@ section { /*Needed to show monitor stacked properly*/ .monitors-card .monitor { - padding: 1.3em 1em; + padding: 1.2em 3.4em 0.875em 3.4em; border-bottom: 1px solid; border-color: hsl(var(--border) / var(--tw-border-opacity)); } .monitors-card .monitor:last-child { border-bottom: none; } +.monitors-card.embed .monitor { + padding: 0em 0.87em 0.875em 0.87em; + border-bottom: none; +} /*Tag Color*/ .tag-maintenance { diff --git a/src/lib/analytics.js b/src/lib/analytics.js new file mode 100644 index 000000000..28e58e1ce --- /dev/null +++ b/src/lib/analytics.js @@ -0,0 +1,13 @@ +// @ts-ignore +export const analyticsEvent = (event, data) => { + // Do something with the event and data + document.dispatchEvent( + new CustomEvent("analyticsEvent", { + bubbles: true, + detail: { + event, + data + } + }) + ); +}; diff --git a/src/lib/components/incident.svelte b/src/lib/components/incident.svelte index 229f0b8b5..67d92f049 100644 --- a/src/lib/components/incident.svelte +++ b/src/lib/components/incident.svelte @@ -52,7 +52,6 @@ let commentsLoading = true; function getComments() { - state = state == "open" ? "close" : "open"; if (incident.comments.length > 0) return; if (commentsLoading === false) return; axios @@ -65,17 +64,22 @@ // console.log(error); }); } + $: { + if (state == "open") { + getComments(); + } + } -
+
- - + + {#if incidentPriority != "" && incidentDuration > 0} -

+

@@ -86,24 +90,28 @@

{/if} - {#if variant.includes("monitor")} -
-
- {#if monitor.image} - - {/if} - {monitor.name} -
-
- {/if} - {#if variant.includes("title")} - {incident.title} + {#if monitor.image} + {/if} + +
+
+ {#if variant.includes("monitor")} + {monitor.name} - + {/if} + {#if variant.includes("title")} + {incident.title} + {/if} +
+
+ {#if incidentState == "open"}
{/if} - + {moment(incidentCreatedAt * 1000).format("MMMM Do YYYY, h:mm:ss a")}

@@ -151,7 +161,7 @@ {#if (variant.includes("body") || variant.includes("comments")) && state == "open"} - + {#if variant.includes("body")}

{/if} {#if variant.includes("comments") && incident.comments?.length > 0} -
+
    {#each incident.comments as comment}
  1. @@ -168,7 +178,7 @@ class="absolute -start-1.5 mt-1.5 h-3 w-3 rounded-full border border-secondary bg-secondary" >