From 720ee9f4f0d4aea52ecd1564a6c73a9e6de4a053 Mon Sep 17 00:00:00 2001 From: Sylvain Zimmer Date: Wed, 19 Nov 2025 15:18:21 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(widgets)=20import=20widgets=20code=20?= =?UTF-8?q?from=20Messages=20and=20setup=20Docker=20workflow=20(#33)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds Gaufre v2 with source, documentation, examples and built artefacts. Also includes the feedback widget from Messages. --- .gitignore | 2 + Makefile | 240 ++ README.md | 53 + compose.yaml | 34 + .../.env.example => ops/env/website.defaults | 1 + ops/env/website.local | 4 + ops/env/widgets.defaults | 1 + ops/env/widgets.local | 4 + packages/integration/README.md | 2 +- packages/widgets/Dockerfile | 10 + packages/widgets/build.js | 31 + packages/widgets/eslint.config.mjs | 10 + packages/widgets/index.html | 16 + packages/widgets/package-lock.json | 2732 +++++++++++++++++ packages/widgets/package.json | 19 + packages/widgets/src/shared/events.ts | 31 + packages/widgets/src/shared/focus.ts | 43 + packages/widgets/src/shared/script.ts | 70 + packages/widgets/src/shared/shadow-dom.ts | 30 + packages/widgets/src/vite-env.d.ts | 1 + packages/widgets/src/widgets/feedback/main.ts | 204 ++ .../widgets/src/widgets/feedback/styles.css | 158 + packages/widgets/src/widgets/lagaufre/main.ts | 367 +++ .../widgets/src/widgets/lagaufre/styles.css | 271 ++ packages/widgets/src/widgets/loader/icon.svg | 1 + packages/widgets/src/widgets/loader/main.ts | 86 + .../widgets/src/widgets/loader/styles.css | 105 + packages/widgets/tsconfig.json | 25 + packages/widgets/vite.config.ts | 19 + website/Dockerfile | 10 + website/README.md | 1 - website/package.json | 4 +- .../widgets/demo/feedback-api-error.json | 1 + website/public/widgets/demo/feedback-api.json | 1 + .../public/widgets/demo/lagaufre-data.json | 57 + .../public/widgets/demo/logos/analytics.svg | 5 + website/public/widgets/demo/logos/auth.svg | 5 + website/public/widgets/demo/logos/docs.svg | 4 + .../widgets/demo/logos/notifications.svg | 5 + website/public/widgets/demo/logos/payment.svg | 5 + website/public/widgets/demo/logos/storage.svg | 4 + website/public/widgets/dist/feedback.js | 1 + website/public/widgets/dist/lagaufre.js | 1 + website/public/widgets/dist/loader.js | 1 + website/src/content/docs/guides/feedback.mdx | 64 + website/src/content/docs/guides/feedback.png | Bin 0 -> 24555 bytes .../content/docs/guides/gaufre-v2-anct.png | Bin 0 -> 45661 bytes .../content/docs/guides/gaufre-v2-dinum.png | Bin 0 -> 55662 bytes website/src/content/docs/guides/gaufre-v2.mdx | 87 + website/src/pages/widgets-demo/feedback.html | 98 + .../pages/widgets-demo/lagaufre-single.html | 89 + website/src/pages/widgets-demo/lagaufre.html | 297 ++ website/src/pages/widgets-demo/loader.html | 69 + 53 files changed, 5375 insertions(+), 4 deletions(-) create mode 100644 Makefile create mode 100644 compose.yaml rename website/.env.example => ops/env/website.defaults (79%) create mode 100644 ops/env/website.local create mode 100644 ops/env/widgets.defaults create mode 100644 ops/env/widgets.local create mode 100644 packages/widgets/Dockerfile create mode 100644 packages/widgets/build.js create mode 100644 packages/widgets/eslint.config.mjs create mode 100644 packages/widgets/index.html create mode 100644 packages/widgets/package-lock.json create mode 100644 packages/widgets/package.json create mode 100644 packages/widgets/src/shared/events.ts create mode 100644 packages/widgets/src/shared/focus.ts create mode 100644 packages/widgets/src/shared/script.ts create mode 100644 packages/widgets/src/shared/shadow-dom.ts create mode 100644 packages/widgets/src/vite-env.d.ts create mode 100644 packages/widgets/src/widgets/feedback/main.ts create mode 100644 packages/widgets/src/widgets/feedback/styles.css create mode 100644 packages/widgets/src/widgets/lagaufre/main.ts create mode 100644 packages/widgets/src/widgets/lagaufre/styles.css create mode 100644 packages/widgets/src/widgets/loader/icon.svg create mode 100644 packages/widgets/src/widgets/loader/main.ts create mode 100644 packages/widgets/src/widgets/loader/styles.css create mode 100644 packages/widgets/tsconfig.json create mode 100644 packages/widgets/vite.config.ts create mode 100644 website/Dockerfile create mode 100644 website/public/widgets/demo/feedback-api-error.json create mode 100644 website/public/widgets/demo/feedback-api.json create mode 100644 website/public/widgets/demo/lagaufre-data.json create mode 100644 website/public/widgets/demo/logos/analytics.svg create mode 100644 website/public/widgets/demo/logos/auth.svg create mode 100644 website/public/widgets/demo/logos/docs.svg create mode 100644 website/public/widgets/demo/logos/notifications.svg create mode 100644 website/public/widgets/demo/logos/payment.svg create mode 100644 website/public/widgets/demo/logos/storage.svg create mode 100644 website/public/widgets/dist/feedback.js create mode 100644 website/public/widgets/dist/lagaufre.js create mode 100644 website/public/widgets/dist/loader.js create mode 100644 website/src/content/docs/guides/feedback.mdx create mode 100644 website/src/content/docs/guides/feedback.png create mode 100644 website/src/content/docs/guides/gaufre-v2-anct.png create mode 100644 website/src/content/docs/guides/gaufre-v2-dinum.png create mode 100644 website/src/content/docs/guides/gaufre-v2.mdx create mode 100644 website/src/pages/widgets-demo/feedback.html create mode 100644 website/src/pages/widgets-demo/lagaufre-single.html create mode 100644 website/src/pages/widgets-demo/lagaufre.html create mode 100644 website/src/pages/widgets-demo/loader.html diff --git a/.gitignore b/.gitignore index 84e6e46..f8904d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # build output dist/ +!website/public/widgets/dist # content generated by build scripts website/public/api/backgrounds/v1/* @@ -24,6 +25,7 @@ pnpm-debug.log* # environment variables .env .env.production +.aws # macOS-specific files .DS_Store diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..342f83d --- /dev/null +++ b/Makefile @@ -0,0 +1,240 @@ +# /!\ /!\ /!\ /!\ /!\ /!\ /!\ DISCLAIMER /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ +# +# This Makefile is only meant to be used for DEVELOPMENT purpose as we are +# changing the user id that will run in the container. +# +# PLEASE DO NOT USE IT FOR YOUR CI/PRODUCTION/WHATEVER... +# +# /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ +# +# Note to developers: +# +# While editing this file, please respect the following statements: +# +# 1. Every variable should be defined in the ad hoc VARIABLES section with a +# relevant subsection +# 2. Every new rule should be defined in the ad hoc RULES section with a +# relevant subsection depending on the targeted service +# 3. Rules should be sorted alphabetically within their section +# 4. When a rule has multiple dependencies, you should: +# - duplicate the rule name to add the help string (if required) +# - write one dependency per line to increase readability and diffs +# 5. .PHONY rule statement should be written after the corresponding rule +# ============================================================================== +# VARIABLES + +BOLD := \033[1m +RESET := \033[0m +GREEN := \033[1;32m + +# -- Docker +# Get the current user ID to use for docker run and docker exec commands +DOCKER_UID = $(shell id -u) +DOCKER_GID = $(shell id -g) +DOCKER_USER = $(DOCKER_UID):$(DOCKER_GID) +COMPOSE = DOCKER_USER=$(DOCKER_USER) docker compose +COMPOSE_EXEC = $(COMPOSE) exec +COMPOSE_RUN = $(COMPOSE) run --rm --build + + +# ============================================================================== +# RULES + +default: help + +# -- Project + +create-env-files: ## Create empty .local env files for local development +create-env-files: \ + ops/env/widgets.local \ + ops/env/website.local +.PHONY: create-env-files + +bootstrap: ## Prepare the project for local development and start the services + @echo "$(BOLD)" + @echo "╔══════════════════════════════════════════════════════════════════════════════╗" + @echo "║ ║" + @echo "║ 🚀 Welcome to Integration - Shared frontend packages from La Suite! 🚀 ║" + @echo "║ ║" + @echo "║ This will set up your development environment with : ║" + @echo "║ • Docker containers for all services ║" + @echo "║ • Frontend dependencies and build ║" + @echo "║ • Environment configuration files ║" + @echo "║ ║" + @echo "║ Services will be available at: ║" + @echo "║ • Website: http://localhost:8930 ║" + @echo "║ • Widgets: http://localhost:8931 ║" + @echo "║ ║" + @echo "╚══════════════════════════════════════════════════════════════════════════════╝" + @echo "$(RESET)" + @echo "$(GREEN)Starting bootstrap process...$(RESET)" + @echo "" + @$(MAKE) update + @$(MAKE) start + @echo "" + @echo "$(GREEN)🎉 Bootstrap completed successfully!$(RESET)" + @echo "" + @echo "$(BOLD)Next steps:$(RESET)" + @echo " • Visit http://localhost:8930 to access the website" + @echo " • Visit http://localhost:8931 to access the widgets" + @echo " • Run 'make help' to see all available commands" + @echo "" +.PHONY: bootstrap + +update: ## Update the project with latest changes + @$(MAKE) create-env-files + @$(MAKE) build + @$(MAKE) widgets-install + @$(MAKE) website-install +.PHONY: update + +# -- Docker/compose +build: ## build the project containers + @$(COMPOSE) build +.PHONY: build + +down: ## stop and remove containers, networks, images, and volumes + @$(COMPOSE) down +.PHONY: down + +logs: ## display all services logs (follow mode) + @$(COMPOSE) logs -f +.PHONY: logs + +start: ## start all development services + @$(COMPOSE) up --force-recreate --build -d website-dev widgets-dev --wait +.PHONY: start + +status: ## an alias for "docker compose ps" + @$(COMPOSE) ps +.PHONY: status + +stop: ## stop all development services + @$(COMPOSE) --profile "*" stop +.PHONY: stop + +restart: ## restart all development services +restart: \ + stop \ + start +.PHONY: restart + +# -- Misc +clean: ## restore repository state as it was freshly cloned + git clean -idx +.PHONY: clean + +help: + @echo "$(BOLD)messages Makefile" + @echo "Please use 'make $(BOLD)target$(RESET)' where $(BOLD)target$(RESET) is one of:" + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(firstword $(MAKEFILE_LIST)) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(GREEN)%-30s$(RESET) %s\n", $$1, $$2}' +.PHONY: help + +ops/env/%.local: + @echo "# Local development overrides for $(notdir $*)" > $@ + @echo "# Add your local-specific environment variables below:" >> $@ + @echo "# Example: DJANGO_DEBUG=True" >> $@ + @echo "" >> $@ + +lint: ## run all linters +lint: \ + widgets-lint +.PHONY: lint + + +# Website +website-install: ## install the website locally + @args="$(filter-out $@,$(MAKECMDGOALS))" && \ + $(COMPOSE) run --build --rm website-dev npm install $${args:-${1}} +.PHONY: website-install + +website-freeze-deps: ## freeze the website dependencies + rm -rf website/package-lock.json + @$(MAKE) website-install +.PHONY: website-freeze-deps + +website-shell: ## open a shell in the website container + $(COMPOSE) run --build --rm -p 8930:8930 website-dev /bin/sh +.PHONY: website-shell + +website-start: ## start the website container + $(COMPOSE) up --force-recreate --build -d website-dev --wait + @sleep 2 + @echo "$(BOLD)" + @echo "╔══════════════════════════════════════════════════════════════════════════════╗" + @echo "║ ║" + @echo "║ 🚀 Website development server with Live Reload is started! 🚀 ║" + @echo "║ ║" + @echo "║ Open your browser at http://localhost:8930 ║" + @echo "║ ║" + @echo "╚══════════════════════════════════════════════════════════════════════════════╝" + @echo "$(RESET)" +.PHONY: website-start + +website-stop: ## stop the website container + $(COMPOSE) stop website-dev +.PHONY: website-stop + + +website-restart: ## restart the website container and rebuild +website-restart: \ + website-stop \ + website-start +.PHONY: website-restart + + +# Widgets +widgets-install: ## install the widgets locally + @args="$(filter-out $@,$(MAKECMDGOALS))" && \ + $(COMPOSE) run --build --rm widgets-dev npm install $${args:-${1}} +.PHONY: widgets-install + +widgets-freeze-deps: ## freeze the widgets dependencies + rm -rf src/widgets/package-lock.json + @$(MAKE) widgets-install +.PHONY: widgets-freeze-deps + +widgets-build: ## build the widgets + $(COMPOSE) run --build --rm widgets-dev npm run build +.PHONY: widgets-build + +widgets-lint: ## lint the widgets + $(COMPOSE) run --build --rm widgets-dev npm run lint +.PHONY: widgets-lint + +widgets-shell: ## open a shell in the widgets container + $(COMPOSE) run --build --rm widgets-dev /bin/sh +.PHONY: widgets-shell + +widgets-start: ## start the widgets container + $(COMPOSE) up --force-recreate --build -d widgets-dev --wait + @echo "$(BOLD)" + @echo "╔══════════════════════════════════════════════════════════════════════════════╗" + @echo "║ ║" + @echo "║ 🚀 Widgets development server with Live Reload is started! 🚀 ║" + @echo "║ ║" + @echo "║ Open your browser at http://localhost:8931 ║" + @echo "║ ║" + @echo "╚══════════════════════════════════════════════════════════════════════════════╝" + @echo "$(RESET)" +.PHONY: widgets-start + +widgets-stop: ## stop the widgets container + $(COMPOSE) stop widgets-dev +.PHONY: widgets-stop + +widgets-restart: ## restart the widgets container and rebuild +widgets-restart: \ + widgets-stop \ + widgets-build \ + widgets-start +.PHONY: widgets-restart + +widgets-deploy: ## deploy the widgets to an S3 bucket + @## Error if the env vars WIDGETS_S3_PATH is not set + @if [ -z "$$WIDGETS_S3_PATH" ]; then \ + echo "Error: WIDGETS_S3_PATH is not set"; \ + exit 1; \ + fi; \ + docker run --rm -ti -v .aws:/root/.aws -v `pwd`/website/public/widgets/dist:/aws amazon/aws-cli s3 cp --acl public-read --recursive . s3://$(WIDGETS_S3_PATH) +.PHONY: widgets-deploy diff --git a/README.md b/README.md index 7584e9e..f36014c 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,61 @@ Repo containing code of: - [@gouvfr-lasuite/integration npm package](https://www.npmjs.com/package/@gouvfr-lasuite/integration) in [`packages/integration`](./packages/integration/) +- Frontend widgets in [`packages/widgets`](./packages/widgets/) - [La Suite: integration docs and API](https://integration.lasuite.numerique.gouv.fr/) in [`website`](./website/) + +## Local development + +After checking out the repository, run: +``` +$ make bootstrap +``` + +For both the website and the widgets projects, it will install dependencies, build, and start the development server, respectively at http://localhost:8930 and http://localhost:8931. + +To see dev server outputs, run: +``` +$ make logs +``` + +You can view all available commands with: +``` +$ make help +``` + +### Developing the website + +If you want a faster startup than `make bootstrap`, you can run more focused commands. For the website: + +``` +$ make website-start +``` + +This will start the development server at [http://localhost:8930](http://localhost:8930). + +### Developing Widgets + +We currently develop some embeddable widgets in the `packages/widgets` directory in this repository. + +``` +$ make widgets-start +``` + +This will start the development server at [http://localhost:8931](http://localhost:8931). + +You can then build them with: + +``` +$ make widgets-build +``` + +And deploy them to an S3 bucket, with `.aws/{config|credentials}` files in the root of the repository. +``` +$ WIDGETS_S3_PATH=xxx make widgets-deploy +``` + + ## Licenses Source code is released under the [MIT](LICENSES/MIT.txt) and other diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..2db4039 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,34 @@ +name: integration + +services: + + website-dev: + user: "${DOCKER_USER:-1000}" + build: + context: ./website + dockerfile: Dockerfile + env_file: + - ops/env/website.defaults + - ops/env/website.local + command: ["npm", "run", "dev"] + volumes: + - ./website/:/home/website/ + ports: + - "8930:8930" + + widgets-dev: + user: "${DOCKER_USER:-1000}" + build: + context: ./packages/widgets + dockerfile: Dockerfile + env_file: + - ops/env/widgets.defaults + - ops/env/widgets.local + command: ["npm", "run", "dev"] + volumes: + - ./packages/widgets/:/home/widgets/ + - ./website/:/home/website/ + - ./website/src/pages/widgets-demo/:/home/widgets/widgets-demo/ + - ./website/public/widgets/:/home/widgets/widgets/ + ports: + - "8931:8931" diff --git a/website/.env.example b/ops/env/website.defaults similarity index 79% rename from website/.env.example rename to ops/env/website.defaults index 359cb4c..4829da6 100644 --- a/website/.env.example +++ b/ops/env/website.defaults @@ -1,2 +1,3 @@ PUBLIC_LASUITE_API_URL=https://integration.lasuite.numerique.gouv.fr PUBLIC_USE_GAUFRE_SUBSETTED_FONT=1 +ASTRO_TELEMETRY_DISABLED=1 diff --git a/ops/env/website.local b/ops/env/website.local new file mode 100644 index 0000000..a775563 --- /dev/null +++ b/ops/env/website.local @@ -0,0 +1,4 @@ +# Local development overrides for website +# Add your local-specific environment variables below: +# Example: DJANGO_DEBUG=True + diff --git a/ops/env/widgets.defaults b/ops/env/widgets.defaults new file mode 100644 index 0000000..cf47dd2 --- /dev/null +++ b/ops/env/widgets.defaults @@ -0,0 +1 @@ +WIDGETS_OUTPUT_DIR=/home/website/public/widgets/ \ No newline at end of file diff --git a/ops/env/widgets.local b/ops/env/widgets.local new file mode 100644 index 0000000..2317523 --- /dev/null +++ b/ops/env/widgets.local @@ -0,0 +1,4 @@ +# Local development overrides for widgets +# Add your local-specific environment variables below: +# Example: DJANGO_DEBUG=True + diff --git a/packages/integration/README.md b/packages/integration/README.md index 400d3d2..27cb94c 100644 --- a/packages/integration/README.md +++ b/packages/integration/README.md @@ -27,7 +27,7 @@ This folder is meant to generate the `@gouvfr-lasuite/integration` npm package. It's a vite app. -To start, `npm install` a first time and copy the example env file: `cp .env.example .env`. Make sure the API env var targets a running API. If you don't want to use the production one, you can run one locally easily: the API is exposed via the `/website` server, go check the README there. +To start, `npm install` a first time. Make sure the API env var targets a running API. If you don't want to use the production one, you can run one locally easily: the API is exposed via the `/website` server, go check the README there. Then, run the local dev server with `npm run dev`. diff --git a/packages/widgets/Dockerfile b/packages/widgets/Dockerfile new file mode 100644 index 0000000..24a7a24 --- /dev/null +++ b/packages/widgets/Dockerfile @@ -0,0 +1,10 @@ +FROM node:22-slim AS widgets-deps + +WORKDIR /home/widgets/ + +RUN npm install -g npm@11.3.0 && npm cache clean -f + +ARG DOCKER_USER +USER ${DOCKER_USER} + +ENV npm_config_cache=/tmp/npm-cache diff --git a/packages/widgets/build.js b/packages/widgets/build.js new file mode 100644 index 0000000..0976217 --- /dev/null +++ b/packages/widgets/build.js @@ -0,0 +1,31 @@ +import { build } from 'vite' +import { readdirSync } from 'node:fs' +import { join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const __dirname = fileURLToPath(new URL('.', import.meta.url)) + +const widgetsDir = join(__dirname, 'src', 'widgets') + +function discoverWidgets() { + return readdirSync(widgetsDir, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .map(dirent => dirent.name) +} + +// Run an independent build for each widget +for (const widget of discoverWidgets()) { + await build({ + build: { + emptyOutDir: false, + outDir: join(process.env.WIDGETS_OUTPUT_DIR || "", "dist"), + rollupOptions: { + input: join(widgetsDir, widget, 'main.ts'), + output: { + entryFileNames: widget + '.js', + format: 'iife' + } + } + }, + }) +} diff --git a/packages/widgets/eslint.config.mjs b/packages/widgets/eslint.config.mjs new file mode 100644 index 0000000..7cd04f4 --- /dev/null +++ b/packages/widgets/eslint.config.mjs @@ -0,0 +1,10 @@ +// @ts-check + +import eslint from '@eslint/js'; +import { defineConfig } from 'eslint/config'; +import tseslint from 'typescript-eslint'; + +export default defineConfig( + eslint.configs.recommended, + tseslint.configs.recommended, +); \ No newline at end of file diff --git a/packages/widgets/index.html b/packages/widgets/index.html new file mode 100644 index 0000000..81eee2f --- /dev/null +++ b/packages/widgets/index.html @@ -0,0 +1,16 @@ + + + + + + Widgets demo + + +

Widgets demo

+ + + diff --git a/packages/widgets/package-lock.json b/packages/widgets/package-lock.json new file mode 100644 index 0000000..fa16f67 --- /dev/null +++ b/packages/widgets/package-lock.json @@ -0,0 +1,2732 @@ +{ + "name": "@gouvfr-lasuite/widgets", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@gouvfr-lasuite/widgets", + "version": "0.0.0", + "devDependencies": { + "eslint": "9.36.0", + "prettier": "3.6.2", + "typescript": "5.9.2", + "typescript-eslint": "8.45.0", + "vite": "7.1.7" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", + "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz", + "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz", + "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz", + "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", + "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz", + "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz", + "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz", + "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz", + "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz", + "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz", + "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz", + "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz", + "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz", + "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz", + "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz", + "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", + "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz", + "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz", + "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz", + "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz", + "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz", + "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz", + "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz", + "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz", + "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz", + "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", + "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz", + "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz", + "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz", + "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz", + "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz", + "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz", + "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz", + "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz", + "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz", + "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz", + "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz", + "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz", + "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz", + "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz", + "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz", + "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz", + "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz", + "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", + "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", + "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", + "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.45.0.tgz", + "integrity": "sha512-HC3y9CVuevvWCl/oyZuI47dOeDF9ztdMEfMH8/DW/Mhwa9cCLnK1oD7JoTVGW/u7kFzNZUKUoyJEqkaJh5y3Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.45.0", + "@typescript-eslint/type-utils": "8.45.0", + "@typescript-eslint/utils": "8.45.0", + "@typescript-eslint/visitor-keys": "8.45.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.45.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.45.0.tgz", + "integrity": "sha512-TGf22kon8KW+DeKaUmOibKWktRY8b2NSAZNdtWh798COm1NWx8+xJ6iFBtk3IvLdv6+LGLJLRlyhrhEDZWargQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.45.0", + "@typescript-eslint/types": "8.45.0", + "@typescript-eslint/typescript-estree": "8.45.0", + "@typescript-eslint/visitor-keys": "8.45.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.45.0.tgz", + "integrity": "sha512-3pcVHwMG/iA8afdGLMuTibGR7pDsn9RjDev6CCB+naRsSYs2pns5QbinF4Xqw6YC/Sj3lMrm/Im0eMfaa61WUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.45.0", + "@typescript-eslint/types": "^8.45.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.45.0.tgz", + "integrity": "sha512-clmm8XSNj/1dGvJeO6VGH7EUSeA0FMs+5au/u3lrA3KfG8iJ4u8ym9/j2tTEoacAffdW1TVUzXO30W1JTJS7dA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.45.0", + "@typescript-eslint/visitor-keys": "8.45.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.45.0.tgz", + "integrity": "sha512-aFdr+c37sc+jqNMGhH+ajxPXwjv9UtFZk79k8pLoJ6p4y0snmYpPA52GuWHgt2ZF4gRRW6odsEj41uZLojDt5w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.45.0.tgz", + "integrity": "sha512-bpjepLlHceKgyMEPglAeULX1vixJDgaKocp0RVJ5u4wLJIMNuKtUXIczpJCPcn2waII0yuvks/5m5/h3ZQKs0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.45.0", + "@typescript-eslint/typescript-estree": "8.45.0", + "@typescript-eslint/utils": "8.45.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.45.0.tgz", + "integrity": "sha512-WugXLuOIq67BMgQInIxxnsSyRLFxdkJEJu8r4ngLR56q/4Q5LrbfkFRH27vMTjxEK8Pyz7QfzuZe/G15qQnVRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.45.0.tgz", + "integrity": "sha512-GfE1NfVbLam6XQ0LcERKwdTTPlLvHvXXhOeUGC1OXi4eQBoyy1iVsW+uzJ/J9jtCz6/7GCQ9MtrQ0fml/jWCnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.45.0", + "@typescript-eslint/tsconfig-utils": "8.45.0", + "@typescript-eslint/types": "8.45.0", + "@typescript-eslint/visitor-keys": "8.45.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.45.0.tgz", + "integrity": "sha512-bxi1ht+tLYg4+XV2knz/F7RVhU0k6VrSMc9sb8DQ6fyCTrGQLHfo7lDtN0QJjZjKkLA2ThrKuCdHEvLReqtIGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.45.0", + "@typescript-eslint/types": "8.45.0", + "@typescript-eslint/typescript-estree": "8.45.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.45.0.tgz", + "integrity": "sha512-qsaFBA3e09MIDAGFUrTk+dzqtfv1XPVz8t8d1f0ybTzrCY7BKiMC5cjrl1O/P7UmHsNyW90EYSkU/ZWpmXelag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.45.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", + "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.8", + "@esbuild/android-arm": "0.25.8", + "@esbuild/android-arm64": "0.25.8", + "@esbuild/android-x64": "0.25.8", + "@esbuild/darwin-arm64": "0.25.8", + "@esbuild/darwin-x64": "0.25.8", + "@esbuild/freebsd-arm64": "0.25.8", + "@esbuild/freebsd-x64": "0.25.8", + "@esbuild/linux-arm": "0.25.8", + "@esbuild/linux-arm64": "0.25.8", + "@esbuild/linux-ia32": "0.25.8", + "@esbuild/linux-loong64": "0.25.8", + "@esbuild/linux-mips64el": "0.25.8", + "@esbuild/linux-ppc64": "0.25.8", + "@esbuild/linux-riscv64": "0.25.8", + "@esbuild/linux-s390x": "0.25.8", + "@esbuild/linux-x64": "0.25.8", + "@esbuild/netbsd-arm64": "0.25.8", + "@esbuild/netbsd-x64": "0.25.8", + "@esbuild/openbsd-arm64": "0.25.8", + "@esbuild/openbsd-x64": "0.25.8", + "@esbuild/openharmony-arm64": "0.25.8", + "@esbuild/sunos-x64": "0.25.8", + "@esbuild/win32-arm64": "0.25.8", + "@esbuild/win32-ia32": "0.25.8", + "@esbuild/win32-x64": "0.25.8" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", + "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.36.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", + "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.46.2", + "@rollup/rollup-android-arm64": "4.46.2", + "@rollup/rollup-darwin-arm64": "4.46.2", + "@rollup/rollup-darwin-x64": "4.46.2", + "@rollup/rollup-freebsd-arm64": "4.46.2", + "@rollup/rollup-freebsd-x64": "4.46.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", + "@rollup/rollup-linux-arm-musleabihf": "4.46.2", + "@rollup/rollup-linux-arm64-gnu": "4.46.2", + "@rollup/rollup-linux-arm64-musl": "4.46.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", + "@rollup/rollup-linux-ppc64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-musl": "4.46.2", + "@rollup/rollup-linux-s390x-gnu": "4.46.2", + "@rollup/rollup-linux-x64-gnu": "4.46.2", + "@rollup/rollup-linux-x64-musl": "4.46.2", + "@rollup/rollup-win32-arm64-msvc": "4.46.2", + "@rollup/rollup-win32-ia32-msvc": "4.46.2", + "@rollup/rollup-win32-x64-msvc": "4.46.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "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==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.45.0.tgz", + "integrity": "sha512-qzDmZw/Z5beNLUrXfd0HIW6MzIaAV5WNDxmMs9/3ojGOpYavofgNAAD/nC6tGV2PczIi0iw8vot2eAe/sBn7zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.45.0", + "@typescript-eslint/parser": "8.45.0", + "@typescript-eslint/typescript-estree": "8.45.0", + "@typescript-eslint/utils": "8.45.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz", + "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/packages/widgets/package.json b/packages/widgets/package.json new file mode 100644 index 0000000..6adeebb --- /dev/null +++ b/packages/widgets/package.json @@ -0,0 +1,19 @@ +{ + "name": "@gouvfr-lasuite/widgets", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite --host 0.0.0.0 --port 8931", + "build": "tsc && node build.js", + "preview": "vite preview --host 0.0.0.0 --port 8931", + "lint": "prettier --write --print-width=120 src && eslint src && tsc --noEmit" + }, + "devDependencies": { + "typescript": "5.9.2", + "vite": "7.1.7", + "eslint": "9.36.0", + "typescript-eslint": "8.45.0", + "prettier": "3.6.2" + } +} diff --git a/packages/widgets/src/shared/events.ts b/packages/widgets/src/shared/events.ts new file mode 100644 index 0000000..e4fe556 --- /dev/null +++ b/packages/widgets/src/shared/events.ts @@ -0,0 +1,31 @@ +/* eslint @typescript-eslint/no-explicit-any:0 */ +const NAMESPACE = `lasuite-widget`; + +export const triggerEvent = ( + widgetName: string, + eventName: string, + detail?: Record, + root?: Window | Document | HTMLElement | null, +) => { + return (root || document).dispatchEvent( + new CustomEvent(`${NAMESPACE}-${widgetName}-${eventName}`, detail ? { detail } : undefined), + ); +}; + +export const listenEvent = ( + widgetName: string, + eventName: string, + root: Window | Document | HTMLElement | null, + once: boolean, + callback: (data: any) => void, +) => { + const cb = (e: any) => callback(e.detail); + const eventFullName = widgetName ? `${NAMESPACE}-${widgetName}-${eventName}` : eventName; + (root || document).addEventListener(eventFullName, cb, once ? { once: true } : undefined); + return () => + (root || document).removeEventListener( + eventFullName, + cb, + once ? ({ once: true } as EventListenerOptions) : undefined, + ); +}; diff --git a/packages/widgets/src/shared/focus.ts b/packages/widgets/src/shared/focus.ts new file mode 100644 index 0000000..11c2d1a --- /dev/null +++ b/packages/widgets/src/shared/focus.ts @@ -0,0 +1,43 @@ +const isVisible = (element: HTMLElement) => { + return element.offsetWidth > 0 && element.offsetHeight > 0; +}; + +export const trapFocus = (shadowRoot: ShadowRoot, container: HTMLElement, selector: string) => { + const handleKeydown = (e: KeyboardEvent) => { + if (e.key !== "Tab") return; + + const focusable = Array.from(container.querySelectorAll(selector)).filter((element) => + isVisible(element as HTMLElement), + ); + if (focusable.length === 0) return; + + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + + if (e.shiftKey && shadowRoot.activeElement === first) { + e.preventDefault(); + (last as HTMLElement).focus(); + } else if (!e.shiftKey && shadowRoot.activeElement === last) { + e.preventDefault(); + (first as HTMLElement).focus(); + } + }; + + container.addEventListener("keydown", handleKeydown); + + return () => { + container.removeEventListener("keydown", handleKeydown); + }; +}; + +export const trapEscape = (cb: () => void) => { + const handleKeydown = (e: KeyboardEvent) => { + if (e.key !== "Escape") return; + e.preventDefault(); + cb(); + }; + document.addEventListener("keydown", handleKeydown); + return () => { + document.removeEventListener("keydown", handleKeydown); + }; +}; diff --git a/packages/widgets/src/shared/script.ts b/packages/widgets/src/shared/script.ts new file mode 100644 index 0000000..dc6c8ed --- /dev/null +++ b/packages/widgets/src/shared/script.ts @@ -0,0 +1,70 @@ +import { triggerEvent } from "./events"; + +type WidgetEvent = [string, string, Record | undefined]; + +type EventArray = Array & { _loaded?: Record }; + +declare global { + var _lasuite_widget: EventArray; +} + +// This could have been an enum but we want to support erasableSyntaxOnly TS settings +export const STATE_NOT_LOADED = 0; +export const STATE_LOADING = 1; +export const STATE_LOADED = 2; + +export const getLoaded = (widgetName: string) => { + return window._lasuite_widget?._loaded?.[widgetName]; +}; + +export const setLoaded = (widgetName: string, status: number) => { + if (!window._lasuite_widget?._loaded) return; + window._lasuite_widget._loaded[widgetName] = status; +}; + +// Replace the push method of the _lasuite_widget array used for communication between the widget and the page +export const installHook = (widgetName: string) => { + if (!window._lasuite_widget) { + window._lasuite_widget = [] as EventArray; + } + const W = window._lasuite_widget; + + // Keep track of the loaded state of each widget + if (!W._loaded) { + W._loaded = {} as Record; + } + + if (getLoaded(widgetName) !== STATE_LOADED) { + // Replace the push method of the _lasuite_widget array used for communication between the widget and the page + W.push = ((...elts: WidgetEvent[]): number => { + for (const elt of elts) { + // If the target widget is loaded, fire the event + if (getLoaded(elt[0]) === STATE_LOADED) { + triggerEvent(elt[0], elt[1], elt[2]); + } else { + W[W.length] = elt; + } + } + return W.length; + }) as typeof Array.prototype.push; + + setLoaded(widgetName, STATE_LOADED); + + // Empty the existing array and re-push all events that were received before the hook was installed + for (const evt of W.splice(0, W.length)) { + W.push(evt); + } + } + + // Finally, fire an event to signal that we are loaded + triggerEvent(widgetName, "loaded"); +}; + +// Loads another widget from the same directory +export const injectScript = (url: string, type: string = "") => { + const newScript = document.createElement("script"); + newScript.src = url; + newScript.type = type; + newScript.defer = true; + document.body.appendChild(newScript); +}; diff --git a/packages/widgets/src/shared/shadow-dom.ts b/packages/widgets/src/shared/shadow-dom.ts new file mode 100644 index 0000000..8ba66ff --- /dev/null +++ b/packages/widgets/src/shared/shadow-dom.ts @@ -0,0 +1,30 @@ +// Shared utility for creating shadow DOM widgets +export function createShadowWidget(widgetName: string, htmlContent: string, cssContent: string): HTMLDivElement { + const id = `lasuite-widget-${widgetName}-shadow`; + // Check if widget already exists + const existingWidget = document.getElementById(id); + if (existingWidget) { + existingWidget.remove(); + } + + // Create container element + const container = document.createElement("div"); + container.id = id; + + // Create shadow root + const shadow = container.attachShadow({ mode: "open" }); + + // Create style element for scoped CSS + const style = document.createElement("style"); + style.textContent = cssContent; + + // Create content element + const content = document.createElement("div"); + content.innerHTML = htmlContent; + + // Append style and content to shadow DOM + shadow.appendChild(style); + shadow.appendChild(content); + + return container; +} diff --git a/packages/widgets/src/vite-env.d.ts b/packages/widgets/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/packages/widgets/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages/widgets/src/widgets/feedback/main.ts b/packages/widgets/src/widgets/feedback/main.ts new file mode 100644 index 0000000..16626a6 --- /dev/null +++ b/packages/widgets/src/widgets/feedback/main.ts @@ -0,0 +1,204 @@ +import styles from "./styles.css?inline"; +import { createShadowWidget } from "../../shared/shadow-dom"; +import { installHook } from "../../shared/script"; +import { listenEvent, triggerEvent } from "../../shared/events"; +import { trapFocus, trapEscape } from "../../shared/focus"; + +const widgetName = "feedback"; + +type ConfigData = { + title?: string; + placeholder?: string; + emailPlaceholder?: string; + submitText?: string; + successText?: string; + successText2?: string; + closeLabel?: string; + submitUrl?: string; +}; + +type ConfigResponse = { + success?: boolean; + detail?: string; + captcha?: boolean; + config?: ConfigData; +}; + +type FeedbackWidgetArgs = { + title?: string; + placeholder?: string; + emailPlaceholder?: string; + submitText?: string; + successText?: string; + successText2?: string; + closeLabel?: string; + submitUrl?: string; + api: string; + channel: string; + email?: string; + bottomOffset?: number; + rightOffset?: number; +}; + +listenEvent(widgetName, "init", null, false, async (args: FeedbackWidgetArgs) => { + if (!args.api || !args.channel) { + console.error("Feedback widget requires an API URL and a channel ID"); + return; + } + + let configData: ConfigData | undefined; + try { + const config = await fetch(`${args.api}config/`, { + headers: { + "X-Channel-ID": args.channel, + }, + }); + const configResponse = (await config.json()) as ConfigResponse; + if (!configResponse.success) throw new Error(configResponse.detail || "Unknown error"); + if (configResponse.captcha) throw new Error("Captcha is not supported yet"); + configData = configResponse.config; + } catch (error) { + console.error("Error fetching config", error); + triggerEvent(widgetName, "closed"); + return; + } + + const title = args.title || configData?.title || "Feedback"; + const placeholder = args.placeholder || configData?.placeholder || "Share your feedback..."; + const emailPlaceholder = args.emailPlaceholder || configData?.emailPlaceholder || "Your email..."; + const submitText = args.submitText || configData?.submitText || "Send Feedback"; + const successText = args.successText || configData?.successText || "Thank you for your feedback!"; + const successText2 = args.successText2 || configData?.successText2 || ""; + const closeLabel = args.closeLabel || configData?.closeLabel || "Close the feedback widget"; + + /* prettier-ignore */ + const htmlContent = + `
` + + `` + + `
` + + `
` + + `` + + `` + + `` + + `
` + + `
` + + `
` + + `` + + `

` + + `

` + + `
` + + `
` + + `
`; + + // Create shadow DOM widget + const shadowContainer = createShadowWidget(widgetName, htmlContent, styles); + const shadowRoot = shadowContainer.shadowRoot!; + const $ = shadowRoot.querySelector.bind(shadowRoot); + + const wrapper = $("#wrapper")!; + const titleSpan = $("#title")!; + const submitBtn = $("#submit")!; + const feedbackText = $("#feedback-text")!; + const errorDiv = $("#error")!; + const closeBtn = $("#close")!; + const emailInput = $("#email")!; + const form = $("form")!; + const successDiv = $("#success")!; + const successTextP = $("#success-text")!; + const successText2P = $("#success-text2")!; + + wrapper.style.bottom = 20 + (args.bottomOffset || 0) + "px"; + wrapper.style.right = 20 + (args.rightOffset || 0) + "px"; + + titleSpan.textContent = title; + feedbackText.placeholder = placeholder; + emailInput.placeholder = emailPlaceholder; + submitBtn.textContent = submitText; + closeBtn.setAttribute("aria-label", closeLabel); + + if (args.email) { + emailInput.remove(); + } + + form.addEventListener("submit", async (e) => { + e.preventDefault(); + errorDiv.textContent = ""; + const message = feedbackText.value.trim(); + const email = args.email || emailInput.value.trim(); + try { + if (!message) { + feedbackText.focus(); + throw new Error("Missing value"); + } + if (!email) { + emailInput.focus(); + throw new Error("Missing value"); + } + + const ret = await fetch(configData?.submitUrl || `${args.api}deliver/`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "X-Channel-ID": args.channel, + }, + body: JSON.stringify({ textBody: message, email }), + }); + let retData; + try { + retData = await ret.json(); + } catch { + throw new Error("Invalid response from server"); + } + + if (!retData.success) throw new Error(retData.detail || "Unknown error"); + + form.remove(); + successDiv.style.display = "flex"; + requestAnimationFrame(() => { + // This RAF call allows screen readers to register the aria-live area + successTextP.textContent = successText; + successText2P.textContent = successText2; + }); + } catch (error) { + errorDiv.style.display = "block"; + errorDiv.textContent = "⚠ " + (error instanceof Error ? error.message : "Unknown error"); + } + }); + + let untrapFocus: (() => void) | null = null; + let untrapEscape: (() => void) | null = null; + let removeCloseListener: () => void = () => {}; + + const closeWidget = () => { + shadowRoot.host.remove(); + if (untrapFocus) { + untrapFocus(); + } + if (untrapEscape) { + untrapEscape(); + } + if (removeCloseListener) { + removeCloseListener(); + } + triggerEvent(widgetName, "closed"); + }; + + closeBtn.addEventListener("click", closeWidget); + removeCloseListener = listenEvent(widgetName, "close", null, false, closeWidget); + + document.body.appendChild(shadowContainer); + + feedbackText.focus(); + + untrapFocus = trapFocus(shadowRoot, wrapper, "textarea,input,button"); + untrapEscape = trapEscape(() => { + triggerEvent(widgetName, "close"); + }); + + triggerEvent(widgetName, "opened"); +}); + +installHook(widgetName); diff --git a/packages/widgets/src/widgets/feedback/styles.css b/packages/widgets/src/widgets/feedback/styles.css new file mode 100644 index 0000000..4a9cd1c --- /dev/null +++ b/packages/widgets/src/widgets/feedback/styles.css @@ -0,0 +1,158 @@ +/* Widget styles */ +#wrapper { + position: fixed; + z-index: 1000; + width: 350px; + height: 400px; + background: white; + border-radius: 12px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12); + display: flex; + flex-direction: column; +} + +#header { + background: #000091; + color: white; + display: flex; + align-items: center; + justify-content: space-between; + border-radius: 12px 12px 0 0; +} + +h6 { + padding: 16px; + font-weight: 600; + font-size: 16px; + margin: 0; +} + +#close { + background: none; + border: none; + color: white; + cursor: pointer; + font-size: 18px; + margin-right: 12px; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 8px; +} + +#content { + display: flex; + flex: 1; + flex-direction: column; +} + +form { + flex: 1; + padding: 16px; + display: flex; + flex-direction: column; + gap: 12px; +} + +#email { + border: 1px solid #e0e0e0; + border-radius: 8px; + padding: 12px; + font-family: inherit; + font-size: 14px; +} + +#feedback-text { + flex: 1; + border: 1px solid #e0e0e0; + border-radius: 8px; + padding: 12px; + font-family: inherit; + font-size: 14px; + resize: none; +} + +#submit { + background: #000091; + color: white; + border: 2px solid #000091; + border-radius: 8px; + padding: 12px; + font-weight: 600; + cursor: pointer; + transition: background 0.2s; +} + +#submit:hover, +#close:hover { + background: #1212ff; +} + +#feedback-text:focus, +#email:focus, +#submit:focus { + outline: 2px solid #0a76f6; + border-color: white; +} + +#close:focus { + outline: 2px solid white; +} + +#status { + font-size: 14px; + font-weight: 500; + text-align: center; +} + +#success { + display: none; + flex: 1; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 40px 20px; + text-align: center; +} + +#success i { + background: #27a658; + color: white; + width: 60px; + height: 60px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 24px; + font-weight: bold; + margin-bottom: 20px; + font-style: normal; +} + +#success p { + color: #0f4e27; + margin: 0; + font-size: 16px; + font-weight: 500; + margin-bottom: 30px; +} + +#error { + color: #dc3545; + margin-bottom: 12px; +} +#error:empty { + margin: 0; +} + +/* Responsive */ +@media (max-width: 420px) { + #wrapper { + width: 100%; + right: 0px !important; + border-radius: 0; + } +} diff --git a/packages/widgets/src/widgets/lagaufre/main.ts b/packages/widgets/src/widgets/lagaufre/main.ts new file mode 100644 index 0000000..d41816d --- /dev/null +++ b/packages/widgets/src/widgets/lagaufre/main.ts @@ -0,0 +1,367 @@ +import styles from "./styles.css?inline"; +import { createShadowWidget } from "../../shared/shadow-dom"; +import { installHook } from "../../shared/script"; +import { listenEvent, triggerEvent } from "../../shared/events"; +import { trapFocus, trapEscape } from "../../shared/focus"; + +const widgetName = "lagaufre"; + +type Service = { + name: string; + url: string; + maturity?: string; + logo?: string; +}; + +type Organization = { + name: string; + type: string; + siret: string; +}; + +type ServicesResponse = { + organization?: Organization; + services: Service[]; + error?: unknown; +}; + +type GaufreWidgetArgs = { + api?: string; + position?: string | (() => Record); + top?: number; + bottom?: number; + left?: number; + right?: number; + data?: ServicesResponse; + fontFamily?: string; + background?: string; + headerLogo?: string; + headerUrl?: string; + open?: boolean; + label?: string; + closeLabel?: string; + headerLabel?: string; + loadingText?: string; + newWindowLabelSuffix?: string; + showFooter?: boolean; + dialogElement?: HTMLElement; + buttonElement?: HTMLElement; +}; + +let loaded = false; + +// Initialize widget (load data and prepare shadow DOM) +listenEvent(widgetName, "init", null, false, async (args: GaufreWidgetArgs) => { + if (!args.api && !args.data) { + console.error("Missing API URL"); + return; + } + + if (loaded) { + triggerEvent(widgetName, "destroy"); + await new Promise((resolve) => setTimeout(resolve, 10)); + } + + const listeners: (() => void)[] = []; + let isVisible = false; + + // https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/ + /* prettier-ignore */ + const htmlContent = + ``; + + // Create shadow DOM widget + const shadowContainer = createShadowWidget(widgetName, htmlContent, styles); + const shadowRoot = shadowContainer.shadowRoot!; + + const wrapper = shadowRoot.querySelector("#wrapper")!; + const loadingDiv = shadowRoot.querySelector("#loading")!; + const servicesGrid = shadowRoot.querySelector("#services-grid")!; + const errorDiv = shadowRoot.querySelector("#error")!; + const closeBtn = shadowRoot.querySelector("#close"); + const okBtn = shadowRoot.querySelector("#ok-button")!; + const headerLogo = shadowRoot.querySelector("#header-logo"); + + // Configure dynamic properties + const configure = (newArgs: GaufreWidgetArgs) => { + const directions = ["top", "bottom", "left", "right"] as const; + + const applyPos = (obj: Record) => { + directions.forEach((prop) => { + wrapper.style[prop] = typeof obj[prop] === "number" ? `${obj[prop]}px` : "unset"; + }); + }; + + if (!directions.every((d) => newArgs[d] === undefined)) { + applyPos(newArgs as Record); + } + + // Positioning parameters + if (newArgs.position) { + if (typeof newArgs.position === "function") { + const pos = newArgs.position(); + wrapper.style.position = pos.position as string; + applyPos(pos); + } else { + wrapper.style.position = newArgs.position; + } + } + + // Apply font family (inherit from parent or use provided) + if (newArgs.fontFamily) { + wrapper.style.fontFamily = newArgs.fontFamily; + } + + // Apply background gradient if requested + if (newArgs.background) { + wrapper.style.background = newArgs.background; + } + + // Apply texts + const label = newArgs.label || "Services"; + const closeLabel = newArgs.closeLabel || "Close"; + loadingDiv.textContent = newArgs.loadingText || "Loading…"; + wrapper.setAttribute("aria-label", label); + if (closeBtn) { + closeBtn.setAttribute("aria-label", closeLabel); + } + + if (headerLogo) { + headerLogo.alt = (newArgs.headerLabel || "About LaSuite") + (newArgs.newWindowLabelSuffix || ""); + } + }; + + configure(args); + + listeners.push( + listenEvent("", "resize", window, false, () => { + configure(args); + }), + ); + + // Initially hide the widget + wrapper.style.display = "none"; + + const showError = (message: string) => { + loadingDiv.style.display = "none"; + servicesGrid.style.display = "none"; + errorDiv.style.display = "block"; + errorDiv.textContent = message; + }; + + const renderServices = (data: ServicesResponse) => { + // Clear previous content + servicesGrid.innerHTML = ""; + + data.services.forEach((service) => { + if (!service.logo) return; + if (service.maturity == "stable") delete service.maturity; + + const serviceCard = document.createElement("li"); + serviceCard.className = `service-card`; + + /* prettier-ignore */ + serviceCard.innerHTML = + `` + + `` + + `
` + + `
` + + `
` + + `
`; + + const anchor = serviceCard.querySelector("a")!; + const img = serviceCard.querySelector("img")!; + const serviceName = serviceCard.querySelector(".service-name")!; + + if (service.maturity) { + const maturityBadge = document.createElement("div"); + maturityBadge.className = "maturity-badge"; + maturityBadge.textContent = service.maturity; + anchor.insertBefore(maturityBadge, img.nextSibling); + } + + anchor.setAttribute( + "aria-label", + service.name + (service.maturity ? ` (${service.maturity})` : "") + (args.newWindowLabelSuffix || ""), + ); + anchor.href = service.url; + img.src = service.logo; + serviceName.textContent = service.name; + + servicesGrid.appendChild(serviceCard); + }); + + loadingDiv.style.display = "none"; + errorDiv.style.display = "none"; + servicesGrid.style.display = "grid"; + }; + + // Load data + if (args.data) { + renderServices(args.data); + } else { + // Fetch services from API + try { + const response = await fetch(args.api!, { + method: "GET", + }); + + const data = (await response.json()) as ServicesResponse; + + if (data.error) { + showError(`Error: ${JSON.stringify(data.error)}`); + } else if (data.services && data.services.length > 0) { + renderServices(data); + } else { + showError("No services found"); + } + } catch (error) { + showError(`Failed to load services: ${error instanceof Error ? error.message : "Unknown error"}`); + } + } + + const handleClickOutside = (event: MouseEvent) => { + if (args.dialogElement) { + return; + } + if (!shadowContainer.contains(event.target as Node)) { + triggerEvent(widgetName, "close"); + } + }; + + let untrapFocus: (() => void) | null = null; + let untrapEscape: (() => void) | null = null; + + // Open widget (show the prepared shadow DOM) + listeners.push( + listenEvent(widgetName, "open", null, false, () => { + wrapper.style.display = "block"; + + // Add click outside listener after a short delay to prevent immediate closing or double-clicks. + setTimeout(() => { + isVisible = true; + document.addEventListener("click", handleClickOutside); + wrapper.focus(); + }, 200); + + untrapFocus = trapFocus(shadowRoot, wrapper, "a,button"); + + if (!args.dialogElement) { + untrapEscape = trapEscape(() => { + triggerEvent(widgetName, "close"); + }); + } + + if (args.buttonElement) { + args.buttonElement.setAttribute("aria-expanded", "true"); + } + + triggerEvent(widgetName, "opened"); + }), + ); + + // Close widget (hide the shadow DOM) + listeners.push( + listenEvent(widgetName, "close", null, false, () => { + if (untrapFocus) { + untrapFocus(); + } + if (untrapEscape) { + untrapEscape(); + } + + if (!isVisible) { + return; // Already closed + } + + wrapper.style.display = "none"; + isVisible = false; + + // Return the focus to the button that opened the widget if any + if (args.buttonElement) { + args.buttonElement.focus(); + args.buttonElement.setAttribute("aria-expanded", "false"); + } + + // Remove click outside listener + document.removeEventListener("click", handleClickOutside); + + triggerEvent(widgetName, "closed"); + }), + ); + + // Toggle widget visibility + listeners.push( + listenEvent(widgetName, "toggle", null, false, () => { + if (isVisible) { + triggerEvent(widgetName, "close"); + } else { + triggerEvent(widgetName, "open"); + } + }), + ); + + listeners.push(listenEvent(widgetName, "configure", null, false, configure)); + + // Close button click handlers + if (okBtn) { + okBtn.addEventListener("click", () => { + triggerEvent(widgetName, "close"); + }); + } + if (closeBtn) { + closeBtn.addEventListener("click", () => { + triggerEvent(widgetName, "close"); + }); + } + + if (args.buttonElement) { + listeners.push( + listenEvent("", "click", args.buttonElement, false, () => { + triggerEvent(widgetName, "toggle"); + }), + ); + } + + // Add to DOM but keep hidden + if (args.dialogElement) { + args.dialogElement.appendChild(shadowContainer); + } else { + wrapper.className = "wrapper-dialog"; + document.body.appendChild(shadowContainer); + } + + listenEvent(widgetName, "destroy", null, true, () => { + triggerEvent(widgetName, "close"); + loaded = false; + shadowContainer.remove(); + // Unlisten all events + listeners.forEach((listener) => listener()); + }); + loaded = true; + + triggerEvent(widgetName, "initialized"); + + if (args.open) { + triggerEvent(widgetName, "open"); + } +}); + +installHook(widgetName); diff --git a/packages/widgets/src/widgets/lagaufre/styles.css b/packages/widgets/src/widgets/lagaufre/styles.css new file mode 100644 index 0000000..6f404ef --- /dev/null +++ b/packages/widgets/src/widgets/lagaufre/styles.css @@ -0,0 +1,271 @@ +/* La Gaufre Widget styles */ +#wrapper { + display: flex; + flex-direction: column; + font-family: inherit; +} + +.wrapper-dialog { + position: fixed; + top: 60px; + right: 60px; + z-index: 1000; + width: 340px; + max-height: 480px; + background: white; + border-radius: 0.25rem; + box-shadow: 0 0px 6px rgba(0, 0, 145, 0.1); + border: 1px solid #e5e5e5; + overflow: hidden; +} + +#header { + display: flex; + justify-content: center; + align-items: center; + padding: 4px 16px; + background: transparent; + border-bottom: 1px solid #dfe2ea; + min-height: 48px; + position: relative; +} + +#header-logo { + height: 25px; + width: auto; + object-fit: contain; + display: block; + margin: 0 auto; +} + +#close { + position: absolute; + right: 16px; +} + +#close { + background: none; + border: none; + color: #64748b; + cursor: pointer; + font-size: 36px; + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + transition: background-color 0.2s; +} + +#close:hover { + background-color: #f0f0f0; +} + +#close:focus { + outline: 2px solid #0a76f6; +} + +#footer { + display: flex; + padding: 16px; + background: transparent; + border-top: 1px solid #dfe2ea; + justify-content: flex-end; +} + +#ok-button { + background: #3e5de7; + color: white; + border: none; + border-radius: 6px; + padding: 8px 16px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: background-color 0.2s; + min-width: 60px; +} + +#ok-button:hover { + background: #1d4ed8; +} + +#ok-button:focus { + outline: 2px solid #0a76f6; +} + +#content { + flex: 1; + padding: 16px; + display: flex; + flex-direction: column; + overflow-y: auto; + min-height: 0; +} + +/* Loading state */ +#loading { + display: flex; + align-items: center; + justify-content: center; + padding: 40px 20px; + color: #666; + font-size: 14px; +} + +/* Error state */ +#error { + display: flex; + align-items: center; + justify-content: center; + padding: 40px 20px; + color: #dc3545; + font-size: 14px; + text-align: center; +} + +/* Services grid */ +#services-grid { + grid-template-columns: repeat(3, 1fr); + gap: 4px; + justify-items: center; + list-style: none; + padding: 0; + margin: 0; +} + +/* Service cards */ +.service-card { + background: transparent; + text-align: center; + transition: all 0.2s ease; + position: relative; + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + list-style: none; + padding: 0; + margin: 0; +} + +.service-card:hover { + background-color: #eef1f4; + border-radius: 6px; +} + +/* Service logo container */ +.service-card a { + position: relative; + padding: 8px; + width: 100%; + text-decoration: none; + display: block; +} + +.service-logo { + width: 42px; + height: 42px; + object-fit: contain; +} + +.maturity-badge { + position: absolute; + top: 40px; + left: 50%; + transform: translateX(-50%); + background: #eef1f4; + color: #2845c1; + border-radius: 12px; + padding: 2px 4px; + font-size: 9px; + line-height: 9px; + font-weight: bold; + text-transform: uppercase; + letter-spacing: 0.3px; + white-space: nowrap; +} + +/* Service info */ +.service-info { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + padding-top: 4px; +} + +.service-name { + font-weight: 600; + font-size: 14px; + color: #1e40af; + margin-bottom: 2px; + line-height: 1.2; + text-align: center; +} + +/* Responsive design */ +@media (max-width: 480px) { + #wrapper { + width: 100%; + right: 0 !important; + left: 0 !important; + border-radius: 0; + bottom: 0 !important; + top: 0 !important; + max-height: 100vh; + position: fixed !important; + } + + #header { + height: 40px; + display: flex; + } + + #header-logo { + height: 35px; + } + + #footer { + display: flex; + } + + #services-grid { + grid-template-columns: repeat(3, 1fr); + gap: 12px; + } + + .service-card { + width: 70px; + padding: 6px; + } + + .service-logo, + .service-logo-placeholder { + width: 40px; + height: 40px; + } + + .service-name { + font-size: 11px; + } +} + +/* Scrollbar styling */ +#content::-webkit-scrollbar { + width: 4px; +} + +#content::-webkit-scrollbar-track { + background: transparent; +} + +#content::-webkit-scrollbar-thumb { + background: #cbd5e1; + border-radius: 2px; +} + +#content::-webkit-scrollbar-thumb:hover { + background: #94a3b8; +} diff --git a/packages/widgets/src/widgets/loader/icon.svg b/packages/widgets/src/widgets/loader/icon.svg new file mode 100644 index 0000000..2c72d5c --- /dev/null +++ b/packages/widgets/src/widgets/loader/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/widgets/src/widgets/loader/main.ts b/packages/widgets/src/widgets/loader/main.ts new file mode 100644 index 0000000..750e10a --- /dev/null +++ b/packages/widgets/src/widgets/loader/main.ts @@ -0,0 +1,86 @@ +import styles from "./styles.css?inline"; +import { createShadowWidget } from "../../shared/shadow-dom"; +import icon from "./icon.svg?raw"; +import { injectScript, installHook, getLoaded, setLoaded, STATE_LOADED, STATE_LOADING } from "../../shared/script"; +import { triggerEvent, listenEvent } from "../../shared/events"; +const widgetName = "loader"; + +type LoaderWidgetArgs = { + widget: string; + closeLabel: string; + label: string; + params: Record; + script: string; + scriptType: string; +}; + +// The init event is sent from the embedding code +listenEvent(widgetName, "init", null, false, (args: LoaderWidgetArgs) => { + const targetWidget = args.widget || "feedback"; + + const htmlContent = `
`; + + // Create shadow DOM widget + const shadowContainer = createShadowWidget(widgetName, htmlContent, styles); + const shadowRoot = shadowContainer.shadowRoot!; + + const btn = shadowRoot.querySelector("button")!; + + const ariaOpen = () => { + btn.setAttribute("aria-label", String(args.closeLabel || "Close widget")); + btn.setAttribute("aria-expanded", "true"); + // TODO: How could we set the aria-controls attribute too, given that we + // have no id for the widget? Should we ask for it via an event? + }; + const ariaClose = () => { + btn.setAttribute("aria-label", String(args.label || "Load widget")); + btn.setAttribute("aria-expanded", "false"); + }; + ariaClose(); + + listenEvent(targetWidget, "closed", null, false, () => { + btn.classList.remove("opened"); + ariaClose(); + }); + listenEvent(targetWidget, "opened", null, false, () => { + btn.classList.add("opened"); + ariaOpen(); + }); + + btn.addEventListener("click", () => { + if (btn.classList.contains("opened")) { + triggerEvent(targetWidget, "close"); + return; + } + + const loadTimeout = setTimeout(() => { + btn.classList.remove("loading"); + }, 10000); + + // Add loading state to the UI + btn.classList.add("loading"); + + const loadedCallback = () => { + clearTimeout(loadTimeout); + btn.classList.remove("loading"); + const params = Object.assign({}, args.params); + params.bottomOffset = btn.offsetHeight + 20; + window._lasuite_widget.push([targetWidget, "init", params]); + }; + + if (getLoaded(targetWidget) === STATE_LOADED) { + loadedCallback(); + } else { + listenEvent(targetWidget, "loaded", null, true, loadedCallback); + // If it isn't even loading, we need to inject the script + if (!getLoaded(targetWidget)) { + injectScript(args.script, args.scriptType || ""); + setLoaded(targetWidget, STATE_LOADING); + } + } + }); + + document.body.appendChild(shadowContainer); +}); + +installHook(widgetName); diff --git a/packages/widgets/src/widgets/loader/styles.css b/packages/widgets/src/widgets/loader/styles.css new file mode 100644 index 0000000..f1b7cc5 --- /dev/null +++ b/packages/widgets/src/widgets/loader/styles.css @@ -0,0 +1,105 @@ +/* Widget styles */ +div { + position: fixed; + bottom: 20px; + right: 20px; + z-index: 1000; +} + +button { + width: 60px; + height: 60px; + border-radius: 50%; + background: #000091; + border: none; + cursor: pointer; + box-shadow: 0 4px 12px rgba(0, 0, 145, 0.3); + transition: + transform 0.2s ease, + box-shadow 0.2s ease, + background-color 0.2s ease; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + margin: 0; +} + +svg { + width: 35px; + height: 35px; +} + +button:focus-visible { + outline: 3px solid #0a76f6; + outline-offset: 2px; +} + +button:hover { + background: #1212ff; + transform: scale(1.1); + box-shadow: 0 6px 16px rgba(18, 18, 255, 0.4); +} + +button:active { + transform: scale(0.95); +} + +button.loading { + background: #2323ff; +} + +button.loading::after { + content: ""; + width: 25px; + height: 25px; + border: 3px solid transparent; + border-top: 3px solid white; + border-radius: 50%; + animation: spin 1s linear infinite; +} + +button.loading svg { + display: none; +} + +button.opened svg { + display: none; +} + +button.opened::after { + content: "+"; + font-size: 50px; + color: white; + height: 60px; + line-height: 60px; + font-family: Arial; + transform: rotate(45deg); +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +@media (max-width: 420px) { + button { + width: 40px; + height: 40px; + } + svg { + width: 25px; + height: 25px; + } + div { + right: 15px; + bottom: 15px; + } + button.opened::after { + font-size: 40px; + } +} diff --git a/packages/widgets/tsconfig.json b/packages/widgets/tsconfig.json new file mode 100644 index 0000000..4f5edc2 --- /dev/null +++ b/packages/widgets/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/packages/widgets/vite.config.ts b/packages/widgets/vite.config.ts new file mode 100644 index 0000000..c63019b --- /dev/null +++ b/packages/widgets/vite.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite' + + +export default defineConfig({ + server: { + proxy: { + '^/widgets/dist/(.+)\\.js$': { + target: 'http://localhost:8931', + rewrite: (path) => { + const match = path.match(/^\/widgets\/dist\/(.+)\.js$/) + if (match) { + return `/src/widgets/${match[1]}/main.ts` + } + return path + } + } + } + } +}) \ No newline at end of file diff --git a/website/Dockerfile b/website/Dockerfile new file mode 100644 index 0000000..5c1c835 --- /dev/null +++ b/website/Dockerfile @@ -0,0 +1,10 @@ +FROM node:22-slim AS website-deps + +WORKDIR /home/website/ + +RUN npm install -g npm@11.3.0 && npm cache clean -f + +ARG DOCKER_USER +USER ${DOCKER_USER} + +ENV npm_config_cache=/tmp/npm-cache diff --git a/website/README.md b/website/README.md index 7bb2850..8c68d7c 100644 --- a/website/README.md +++ b/website/README.md @@ -21,7 +21,6 @@ This is a starlight-based Astro app. Follow the official docs if more info is ne ```sh npm install -cp .env.example .env npm run dev ``` diff --git a/website/package.json b/website/package.json index 6feb253..3345cec 100644 --- a/website/package.json +++ b/website/package.json @@ -7,12 +7,12 @@ "node": "20" }, "scripts": { - "dev": "astro dev", + "dev": "astro dev --port 8930 --host 0.0.0.0", "start": "node ./server.mjs", "build-backgrounds": "node ./bin/build-services-backgrounds.mjs", "gaufre-glyphhanger-cmd": "node ./bin/gaufre-font-cmd.mjs", "build": "astro check && npm run build-backgrounds && astro build", - "preview": "astro preview", + "preview": "astro preview --port 8930 --host 0.0.0.0", "astro": "astro" }, "dependencies": { diff --git a/website/public/widgets/demo/feedback-api-error.json b/website/public/widgets/demo/feedback-api-error.json new file mode 100644 index 0000000..3d1cff4 --- /dev/null +++ b/website/public/widgets/demo/feedback-api-error.json @@ -0,0 +1 @@ +{"success": true, "config": {"captcha": false, "submitUrl": "/error"}} \ No newline at end of file diff --git a/website/public/widgets/demo/feedback-api.json b/website/public/widgets/demo/feedback-api.json new file mode 100644 index 0000000..ed13f72 --- /dev/null +++ b/website/public/widgets/demo/feedback-api.json @@ -0,0 +1 @@ +{"success": true, "config": {"captcha": false}} \ No newline at end of file diff --git a/website/public/widgets/demo/lagaufre-data.json b/website/public/widgets/demo/lagaufre-data.json new file mode 100644 index 0000000..0da3e44 --- /dev/null +++ b/website/public/widgets/demo/lagaufre-data.json @@ -0,0 +1,57 @@ +{ + "organization": { + "name": "Example Organization", + "type": "Public Administration", + "siret": "12345678901234" + }, + "services": [ + { + "id": 1, + "name": "Authentication Service", + "url": "https://example.com/auth", + "maturity": "stable", + "logo": "/widgets/demo/logos/auth.svg", + "subscribed": true + }, + { + "id": 2, + "name": "Document Portal", + "url": "https://example.com/docs", + "maturity": "stable", + "logo": "/widgets/demo/logos/docs.svg", + "subscribed": true + }, + { + "id": 3, + "name": "Payment Gateway", + "url": "https://example.com/payments", + "maturity": "stable", + "logo": "/widgets/demo/logos/payment.svg", + "subscribed": false + }, + { + "id": 4, + "name": "Analytics Dashboard", + "url": "https://example.com/analytics", + "maturity": "beta", + "logo": "/widgets/demo/logos/analytics.svg", + "subscribed": true + }, + { + "id": 5, + "name": "Notification Center", + "url": "https://example.com/notifications", + "maturity": "alpha", + "logo": "/widgets/demo/logos/notifications.svg", + "subscribed": false + }, + { + "id": 6, + "name": "File Storage", + "url": "https://example.com/storage", + "maturity": "stable", + "logo": "/widgets/demo/logos/storage.svg", + "subscribed": true + } + ] +} diff --git a/website/public/widgets/demo/logos/analytics.svg b/website/public/widgets/demo/logos/analytics.svg new file mode 100644 index 0000000..48b144f --- /dev/null +++ b/website/public/widgets/demo/logos/analytics.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/website/public/widgets/demo/logos/auth.svg b/website/public/widgets/demo/logos/auth.svg new file mode 100644 index 0000000..fbe693e --- /dev/null +++ b/website/public/widgets/demo/logos/auth.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/website/public/widgets/demo/logos/docs.svg b/website/public/widgets/demo/logos/docs.svg new file mode 100644 index 0000000..6dbd659 --- /dev/null +++ b/website/public/widgets/demo/logos/docs.svg @@ -0,0 +1,4 @@ + + + + diff --git a/website/public/widgets/demo/logos/notifications.svg b/website/public/widgets/demo/logos/notifications.svg new file mode 100644 index 0000000..bb2d968 --- /dev/null +++ b/website/public/widgets/demo/logos/notifications.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/website/public/widgets/demo/logos/payment.svg b/website/public/widgets/demo/logos/payment.svg new file mode 100644 index 0000000..543424b --- /dev/null +++ b/website/public/widgets/demo/logos/payment.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/website/public/widgets/demo/logos/storage.svg b/website/public/widgets/demo/logos/storage.svg new file mode 100644 index 0000000..07e6bde --- /dev/null +++ b/website/public/widgets/demo/logos/storage.svg @@ -0,0 +1,4 @@ + + + + diff --git a/website/public/widgets/dist/feedback.js b/website/public/widgets/dist/feedback.js new file mode 100644 index 0000000..5ec8519 --- /dev/null +++ b/website/public/widgets/dist/feedback.js @@ -0,0 +1 @@ +(function(){"use strict";const P="#wrapper{position:fixed;z-index:1000;width:350px;height:400px;background:#fff;border-radius:12px;box-shadow:0 8px 32px #0000001f;display:flex;flex-direction:column}#header{background:#000091;color:#fff;display:flex;align-items:center;justify-content:space-between;border-radius:12px 12px 0 0}h6{padding:16px;font-weight:600;font-size:16px;margin:0}#close{background:none;border:none;color:#fff;cursor:pointer;font-size:18px;margin-right:12px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;border-radius:8px}#content{display:flex;flex:1;flex-direction:column}form{flex:1;padding:16px;display:flex;flex-direction:column;gap:12px}#email{border:1px solid #e0e0e0;border-radius:8px;padding:12px;font-family:inherit;font-size:14px}#feedback-text{flex:1;border:1px solid #e0e0e0;border-radius:8px;padding:12px;font-family:inherit;font-size:14px;resize:none}#submit{background:#000091;color:#fff;border:2px solid #000091;border-radius:8px;padding:12px;font-weight:600;cursor:pointer;transition:background .2s}#submit:hover,#close:hover{background:#1212ff}#feedback-text:focus,#email:focus,#submit:focus{outline:2px solid #0a76f6;border-color:#fff}#close:focus{outline:2px solid white}#status{font-size:14px;font-weight:500;text-align:center}#success{display:none;flex:1;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;text-align:center}#success i{background:#27a658;color:#fff;width:60px;height:60px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:24px;font-weight:700;margin-bottom:20px;font-style:normal}#success p{color:#0f4e27;margin:0 0 30px;font-size:16px;font-weight:500}#error{color:#dc3545;margin-bottom:12px}#error:empty{margin:0}@media (max-width: 420px){#wrapper{width:100%;right:0!important;border-radius:0}}";function j(e,t,o){const n=`lasuite-widget-${e}-shadow`,s=document.getElementById(n);s&&s.remove();const i=document.createElement("div");i.id=n;const c=i.attachShadow({mode:"open"}),d=document.createElement("style");d.textContent=o;const f=document.createElement("div");return f.innerHTML=t,c.appendChild(d),c.appendChild(f),i}const T="lasuite-widget",u=(e,t,o,n)=>document.dispatchEvent(new CustomEvent(`${T}-${e}-${t}`,o?{detail:o}:void 0)),_=(e,t,o,n,s)=>{const i=d=>s(d.detail),c=`${T}-${e}-${t}`;return document.addEventListener(c,i,void 0),()=>document.removeEventListener(c,i,void 0)},b=2,L=e=>window._lasuite_widget?._loaded?.[e],F=(e,t)=>{window._lasuite_widget?._loaded&&(window._lasuite_widget._loaded[e]=t)},I=e=>{window._lasuite_widget||(window._lasuite_widget=[]);const t=window._lasuite_widget;if(t._loaded||(t._loaded={}),L(e)!==b){t.push=(...o)=>{for(const n of o)L(n[0])===b?u(n[0],n[1],n[2]):t[t.length]=n;return t.length},F(e,b);for(const o of t.splice(0,t.length))t.push(o)}u(e,"loaded")},q=e=>e.offsetWidth>0&&e.offsetHeight>0,O=(e,t,o)=>{const n=s=>{if(s.key!=="Tab")return;const i=Array.from(t.querySelectorAll(o)).filter(f=>q(f));if(i.length===0)return;const c=i[0],d=i[i.length-1];s.shiftKey&&e.activeElement===c?(s.preventDefault(),d.focus()):!s.shiftKey&&e.activeElement===d&&(s.preventDefault(),c.focus())};return t.addEventListener("keydown",n),()=>{t.removeEventListener("keydown",n)}},U=e=>{const t=o=>{o.key==="Escape"&&(o.preventDefault(),e())};return document.addEventListener("keydown",t),()=>{document.removeEventListener("keydown",t)}},a="feedback";_(a,"init",null,!1,async e=>{if(!e.api||!e.channel){console.error("Feedback widget requires an API URL and a channel ID");return}let t;try{const l=await(await fetch(`${e.api}config/`,{headers:{"X-Channel-ID":e.channel}})).json();if(!l.success)throw new Error(l.detail||"Unknown error");if(l.captcha)throw new Error("Captcha is not supported yet");t=l.config}catch(h){console.error("Error fetching config",h),u(a,"closed");return}const o=e.title||t?.title||"Feedback",n=e.placeholder||t?.placeholder||"Share your feedback...",s=e.emailPlaceholder||t?.emailPlaceholder||"Your email...",i=e.submitText||t?.submitText||"Send Feedback",c=e.successText||t?.successText||"Thank you for your feedback!",d=e.successText2||t?.successText2||"",f=e.closeLabel||t?.closeLabel||"Close the feedback widget",D=j(a,'

',P),p=D.shadowRoot,r=p.querySelector.bind(p),g=r("#wrapper"),W=r("#title"),B=r("#submit"),m=r("#feedback-text"),v=r("#error"),S=r("#close"),x=r("#email"),$=r("form"),K=r("#success"),M=r("#success-text"),H=r("#success-text2");g.style.bottom=20+(e.bottomOffset||0)+"px",g.style.right=20+(e.rightOffset||0)+"px",W.textContent=o,m.placeholder=n,x.placeholder=s,B.textContent=i,S.setAttribute("aria-label",f),e.email&&x.remove(),$.addEventListener("submit",async h=>{h.preventDefault(),v.textContent="";const l=m.value.trim(),A=e.email||x.value.trim();try{if(!l)throw m.focus(),new Error("Missing value");if(!A)throw x.focus(),new Error("Missing value");const w=await fetch(t?.submitUrl||`${e.api}deliver/`,{method:"POST",headers:{"Content-Type":"application/json","X-Channel-ID":e.channel},body:JSON.stringify({textBody:l,email:A})});let C;try{C=await w.json()}catch{throw new Error("Invalid response from server")}if(!C.success)throw new Error(C.detail||"Unknown error");$.remove(),K.style.display="flex",requestAnimationFrame(()=>{M.textContent=c,H.textContent=d})}catch(w){v.style.display="block",v.textContent="⚠ "+(w instanceof Error?w.message:"Unknown error")}});let y=null,E=null,k=()=>{};const z=()=>{p.host.remove(),y&&y(),E&&E(),k&&k(),u(a,"closed")};S.addEventListener("click",z),k=_(a,"close",null,!1,z),document.body.appendChild(D),m.focus(),y=O(p,g,"textarea,input,button"),E=U(()=>{u(a,"close")}),u(a,"opened")}),I(a)})(); diff --git a/website/public/widgets/dist/lagaufre.js b/website/public/widgets/dist/lagaufre.js new file mode 100644 index 0000000..c5c325d --- /dev/null +++ b/website/public/widgets/dist/lagaufre.js @@ -0,0 +1 @@ +(function(){"use strict";const F="#wrapper{display:flex;flex-direction:column;font-family:inherit}.wrapper-dialog{position:fixed;top:60px;right:60px;z-index:1000;width:340px;max-height:480px;background:#fff;border-radius:.25rem;box-shadow:0 0 6px #0000911a;border:1px solid #e5e5e5;overflow:hidden}#header{display:flex;justify-content:center;align-items:center;padding:4px 16px;background:transparent;border-bottom:1px solid #dfe2ea;min-height:48px;position:relative}#header-logo{height:25px;width:auto;object-fit:contain;display:block;margin:0 auto}#close{position:absolute;right:16px}#close{background:none;border:none;color:#64748b;cursor:pointer;font-size:36px;width:36px;height:36px;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:background-color .2s}#close:hover{background-color:#f0f0f0}#close:focus{outline:2px solid #0a76f6}#footer{display:flex;padding:16px;background:transparent;border-top:1px solid #dfe2ea;justify-content:flex-end}#ok-button{background:#3e5de7;color:#fff;border:none;border-radius:6px;padding:8px 16px;font-size:14px;font-weight:600;cursor:pointer;transition:background-color .2s;min-width:60px}#ok-button:hover{background:#1d4ed8}#ok-button:focus{outline:2px solid #0a76f6}#content{flex:1;padding:16px;display:flex;flex-direction:column;overflow-y:auto;min-height:0}#loading{display:flex;align-items:center;justify-content:center;padding:40px 20px;color:#666;font-size:14px}#error{display:flex;align-items:center;justify-content:center;padding:40px 20px;color:#dc3545;font-size:14px;text-align:center}#services-grid{grid-template-columns:repeat(3,1fr);gap:4px;justify-items:center;list-style:none;padding:0;margin:0}.service-card{background:transparent;text-align:center;transition:all .2s ease;position:relative;display:flex;flex-direction:column;align-items:center;width:100%;list-style:none;padding:0;margin:0}.service-card:hover{background-color:#eef1f4;border-radius:6px}.service-card a{position:relative;padding:8px;width:100%;text-decoration:none;display:block}.service-logo{width:42px;height:42px;object-fit:contain}.maturity-badge{position:absolute;top:40px;left:50%;transform:translate(-50%);background:#eef1f4;color:#2845c1;border-radius:12px;padding:2px 4px;font-size:9px;line-height:9px;font-weight:700;text-transform:uppercase;letter-spacing:.3px;white-space:nowrap}.service-info{display:flex;flex-direction:column;align-items:center;width:100%;padding-top:4px}.service-name{font-weight:600;font-size:14px;color:#1e40af;margin-bottom:2px;line-height:1.2;text-align:center}@media (max-width: 480px){#wrapper{width:100%;inset:0!important;border-radius:0;max-height:100vh;position:fixed!important}#header{height:40px;display:flex}#header-logo{height:35px}#footer{display:flex}#services-grid{grid-template-columns:repeat(3,1fr);gap:12px}.service-card{width:70px;padding:6px}.service-logo,.service-logo-placeholder{width:40px;height:40px}.service-name{font-size:11px}}#content::-webkit-scrollbar{width:4px}#content::-webkit-scrollbar-track{background:transparent}#content::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}#content::-webkit-scrollbar-thumb:hover{background:#94a3b8}";function D(e,t,n){const s=`lasuite-widget-${e}-shadow`,d=document.getElementById(s);d&&d.remove();const l=document.createElement("div");l.id=s;const r=l.attachShadow({mode:"open"}),p=document.createElement("style");p.textContent=n;const u=document.createElement("div");return u.innerHTML=t,r.appendChild(p),r.appendChild(u),l}const C="lasuite-widget",c=(e,t,n,s)=>document.dispatchEvent(new CustomEvent(`${C}-${e}-${t}`,n?{detail:n}:void 0)),m=(e,t,n,s,d)=>{const l=p=>d(p.detail),r=e?`${C}-${e}-${t}`:t;return(n||document).addEventListener(r,l,s?{once:!0}:void 0),()=>(n||document).removeEventListener(r,l,s?{once:!0}:void 0)},v=2,$=e=>window._lasuite_widget?._loaded?.[e],W=(e,t)=>{window._lasuite_widget?._loaded&&(window._lasuite_widget._loaded[e]=t)},B=e=>{window._lasuite_widget||(window._lasuite_widget=[]);const t=window._lasuite_widget;if(t._loaded||(t._loaded={}),$(e)!==v){t.push=(...n)=>{for(const s of n)$(s[0])===v?c(s[0],s[1],s[2]):t[t.length]=s;return t.length},W(e,v);for(const n of t.splice(0,t.length))t.push(n)}c(e,"loaded")},H=e=>e.offsetWidth>0&&e.offsetHeight>0,K=(e,t,n)=>{const s=d=>{if(d.key!=="Tab")return;const l=Array.from(t.querySelectorAll(n)).filter(u=>H(u));if(l.length===0)return;const r=l[0],p=l[l.length-1];d.shiftKey&&e.activeElement===r?(d.preventDefault(),p.focus()):!d.shiftKey&&e.activeElement===p&&(d.preventDefault(),r.focus())};return t.addEventListener("keydown",s),()=>{t.removeEventListener("keydown",s)}},M=e=>{const t=n=>{n.key==="Escape"&&(n.preventDefault(),e())};return document.addEventListener("keydown",t),()=>{document.removeEventListener("keydown",t)}},i="lagaufre";let w=!1;m(i,"init",null,!1,async e=>{if(!e.api&&!e.data){console.error("Missing API URL");return}w&&(c(i,"destroy"),await new Promise(o=>setTimeout(o,10)));const t=[];let n=!1;const s='",d=D(i,s,F),l=d.shadowRoot,r=l.querySelector("#wrapper"),p=l.querySelector("#loading"),u=l.querySelector("#services-grid"),k=l.querySelector("#error"),x=l.querySelector("#close"),q=l.querySelector("#ok-button"),z=l.querySelector("#header-logo"),E=o=>{const a=["top","bottom","left","right"],f=h=>{a.forEach(b=>{r.style[b]=typeof h[b]=="number"?`${h[b]}px`:"unset"})};if(a.every(h=>o[h]===void 0)||f(o),o.position)if(typeof o.position=="function"){const h=o.position();r.style.position=h.position,f(h)}else r.style.position=o.position;o.fontFamily&&(r.style.fontFamily=o.fontFamily),o.background&&(r.style.background=o.background);const g=o.label||"Services",y=o.closeLabel||"Close";p.textContent=o.loadingText||"Loading…",r.setAttribute("aria-label",g),x&&x.setAttribute("aria-label",y),z&&(z.alt=(o.headerLabel||"About LaSuite")+(o.newWindowLabelSuffix||""))};E(e),t.push(m("","resize",window,!1,()=>{E(e)})),r.style.display="none";const L=o=>{p.style.display="none",u.style.display="none",k.style.display="block",k.textContent=o},T=o=>{u.innerHTML="",o.services.forEach(a=>{if(!a.logo)return;a.maturity=="stable"&&delete a.maturity;const f=document.createElement("li");f.className="service-card",f.innerHTML=`
`;const g=f.querySelector("a"),y=f.querySelector("img"),h=f.querySelector(".service-name");if(a.maturity){const b=document.createElement("div");b.className="maturity-badge",b.textContent=a.maturity,g.insertBefore(b,y.nextSibling)}g.setAttribute("aria-label",a.name+(a.maturity?` (${a.maturity})`:"")+(e.newWindowLabelSuffix||"")),g.href=a.url,y.src=a.logo,h.textContent=a.name,u.appendChild(f)}),p.style.display="none",k.style.display="none",u.style.display="grid"};if(e.data)T(e.data);else try{const a=await(await fetch(e.api,{method:"GET"})).json();a.error?L(`Error: ${JSON.stringify(a.error)}`):a.services&&a.services.length>0?T(a):L("No services found")}catch(o){L(`Failed to load services: ${o instanceof Error?o.message:"Unknown error"}`)}const j=o=>{e.dialogElement||d.contains(o.target)||c(i,"close")};let S=null,_=null;t.push(m(i,"open",null,!1,()=>{r.style.display="block",setTimeout(()=>{n=!0,document.addEventListener("click",j),r.focus()},200),S=K(l,r,"a,button"),e.dialogElement||(_=M(()=>{c(i,"close")})),e.buttonElement&&e.buttonElement.setAttribute("aria-expanded","true"),c(i,"opened")})),t.push(m(i,"close",null,!1,()=>{S&&S(),_&&_(),n&&(r.style.display="none",n=!1,e.buttonElement&&(e.buttonElement.focus(),e.buttonElement.setAttribute("aria-expanded","false")),document.removeEventListener("click",j),c(i,"closed"))})),t.push(m(i,"toggle",null,!1,()=>{n?c(i,"close"):c(i,"open")})),t.push(m(i,"configure",null,!1,E)),q&&q.addEventListener("click",()=>{c(i,"close")}),x&&x.addEventListener("click",()=>{c(i,"close")}),e.buttonElement&&t.push(m("","click",e.buttonElement,!1,()=>{c(i,"toggle")})),e.dialogElement?e.dialogElement.appendChild(d):(r.className="wrapper-dialog",document.body.appendChild(d)),m(i,"destroy",null,!0,()=>{c(i,"close"),w=!1,d.remove(),t.forEach(o=>o())}),w=!0,c(i,"initialized"),e.open&&c(i,"open")}),B(i)})(); diff --git a/website/public/widgets/dist/loader.js b/website/public/widgets/dist/loader.js new file mode 100644 index 0000000..0eccae1 --- /dev/null +++ b/website/public/widgets/dist/loader.js @@ -0,0 +1 @@ +(function(){"use strict";const m='div{position:fixed;bottom:20px;right:20px;z-index:1000}button{width:60px;height:60px;border-radius:50%;background:#000091;border:none;cursor:pointer;box-shadow:0 4px 12px #0000914d;transition:transform .2s ease,box-shadow .2s ease,background-color .2s ease;display:flex;align-items:center;justify-content:center;padding:0;margin:0}svg{width:35px;height:35px}button:focus-visible{outline:3px solid #0a76f6;outline-offset:2px}button:hover{background:#1212ff;transform:scale(1.1);box-shadow:0 6px 16px #1212ff66}button:active{transform:scale(.95)}button.loading{background:#2323ff}button.loading:after{content:"";width:25px;height:25px;border:3px solid transparent;border-top:3px solid white;border-radius:50%;animation:spin 1s linear infinite}button.loading svg{display:none}button.opened svg{display:none}button.opened:after{content:"+";font-size:50px;color:#fff;height:60px;line-height:60px;font-family:Arial;transform:rotate(45deg)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media (max-width: 420px){button{width:40px;height:40px}svg{width:25px;height:25px}div{right:15px;bottom:15px}button.opened:after{font-size:40px}}';function x(e,t,n){const i=`lasuite-widget-${e}-shadow`,a=document.getElementById(i);a&&a.remove();const o=document.createElement("div");o.id=i;const s=o.attachShadow({mode:"open"}),d=document.createElement("style");d.textContent=n;const u=document.createElement("div");return u.innerHTML=t,s.appendChild(d),s.appendChild(u),o}const v='',f="lasuite-widget",p=(e,t,n,i)=>document.dispatchEvent(new CustomEvent(`${f}-${e}-${t}`,n?{detail:n}:void 0)),r=(e,t,n,i,a)=>{const o=d=>a(d.detail),s=e?`${f}-${e}-${t}`:t;return document.addEventListener(s,o,i?{once:!0}:void 0),()=>document.removeEventListener(s,o,i?{once:!0}:void 0)},C=1,l=2,c=e=>window._lasuite_widget?._loaded?.[e],h=(e,t)=>{window._lasuite_widget?._loaded&&(window._lasuite_widget._loaded[e]=t)},_=e=>{window._lasuite_widget||(window._lasuite_widget=[]);const t=window._lasuite_widget;if(t._loaded||(t._loaded={}),c(e)!==l){t.push=(...n)=>{for(const i of n)c(i[0])===l?p(i[0],i[1],i[2]):t[t.length]=i;return t.length},h(e,l);for(const n of t.splice(0,t.length))t.push(n)}p(e,"loaded")},E=(e,t="")=>{const n=document.createElement("script");n.src=e,n.type=t,n.defer=!0,document.body.appendChild(n)},g="loader";r(g,"init",null,!1,e=>{const t=e.widget||"feedback",n=`
`,i=x(g,n,m),o=i.shadowRoot.querySelector("button"),s=()=>{o.setAttribute("aria-label",String(e.closeLabel||"Close widget")),o.setAttribute("aria-expanded","true")},d=()=>{o.setAttribute("aria-label",String(e.label||"Load widget")),o.setAttribute("aria-expanded","false")};d(),r(t,"closed",null,!1,()=>{o.classList.remove("opened"),d()}),r(t,"opened",null,!1,()=>{o.classList.add("opened"),s()}),o.addEventListener("click",()=>{if(o.classList.contains("opened")){p(t,"close");return}const u=setTimeout(()=>{o.classList.remove("loading")},1e4);o.classList.add("loading");const w=()=>{clearTimeout(u),o.classList.remove("loading");const b=Object.assign({},e.params);b.bottomOffset=o.offsetHeight+20,window._lasuite_widget.push([t,"init",b])};c(t)===l?w():(r(t,"loaded",null,!0,w),c(t)||(E(e.script,e.scriptType||""),h(t,C)))}),document.body.appendChild(i)}),_(g)})(); diff --git a/website/src/content/docs/guides/feedback.mdx b/website/src/content/docs/guides/feedback.mdx new file mode 100644 index 0000000..12acfc2 --- /dev/null +++ b/website/src/content/docs/guides/feedback.mdx @@ -0,0 +1,64 @@ +--- +title: Retours utilisateurs +sidebar: + order: 50 +--- + +
+![](./feedback.png) +
+ +Ce widget permet aux visiteurs de votre service d'envoyer des questions ou des retours à votre équipe. + +Ces retours sont ensuite consultables dans une instance de [Messages](https://github.com/suitenumerique/messages), +qui permet d'y répondre collaborativement par email. + + +## Intégration + +Il y a deux façons principales d'intégrer ce widget dans votre service: + +### 1. Via le composant React + +Ce composant sera bientôt disponible dans le [UI Kit](https://github.com/suitenumerique/ui-kit). + +En attendant, vous pouvez : +* soit [copier ce composant](https://github.com/suitenumerique/messages/blob/main/src/frontend/src/features/ui/components/feedback-widget/index.tsx) +si vous souhaitez intégrer la pop-in de retour avec son bouton de chargement qui s'affiche en bas à droite des pages, +* soit [copier ce composant](https://github.com/suitenumerique/messages/blob/main/src/frontend/src/features/ui/components/feedback-button/index.tsx) +si vous souhaitez juste ouvrir la pop-in de retour dynamiquement, avec un bouton existant de votre application par exemple. + +### 2. Via le script JavaScript + +Cette option est à privilégier si vous n'utilisez pas React ou si vous ne souhaitez pas intégrer l'UI Kit dans votre application. + +Voici comment l'intégrer avec le bouton de chargement : + +```html + + +``` + +D'autres exemples d'intégration sont disponibles ci-dessous. + +## Exemples + +Nous avons une documentation interactive avec plusieurs exemples de configuration pour : + * [version avec bouton de chargement](/widgets-demo/loader). + * [version sans bouton de chargement](/widgets-demo/feedback). + +Vous pouvez aussi tester La Gaufre v2 en ligne sur ces services : + +* [Suite territoriale - site vitrine](https://suiteterritoriale.anct.gouv.fr/) +* [Suite territoriale - Messages](https://messages.suite.anct.gouv.fr) diff --git a/website/src/content/docs/guides/feedback.png b/website/src/content/docs/guides/feedback.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba0954eddd161e0972689081b4b831dde69d3c1 GIT binary patch literal 24555 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 literal 0 HcmV?d00001 diff --git a/website/src/content/docs/guides/gaufre-v2-anct.png b/website/src/content/docs/guides/gaufre-v2-anct.png new file mode 100644 index 0000000000000000000000000000000000000000..d9e47f94e37c2022e6784e8c34bddfd090d0b7e7 GIT binary patch literal 45661 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 literal 0 HcmV?d00001 diff --git a/website/src/content/docs/guides/gaufre-v2-dinum.png b/website/src/content/docs/guides/gaufre-v2-dinum.png new file mode 100644 index 0000000000000000000000000000000000000000..e6400694500fb9c85b939888a778197693c70064 GIT binary patch literal 55662 zcmeFZ2U}B17cffi5Kt*1gr=a<1?eFmAR^692kD)Fw9r97x}Yd1y%*^nsgV|>OO+ma z2_@7(Lc)#beb0N&z4sq{&$s8<*|TTXS~GjqnYA}WJ<(C8r(vfdA|j&Kc%=G_h=>G5 zI18vK2rYtc-x7$3=ydE=RGw(4sBk}d1F^ApvL+&W6!lq;Qvdl+mJFk38dQvt!JkG_ zxp{8|e_}Kw+EQcuoIpl(t0yeWLY5A}l+7 zsfxYU<2CUK%Cvt95*?m#l4ul$U?62v1rAqve(U#LCV z#0(Ka%o=%&Se2dBWa*b=2mX=H+4O0N*`phILAiMMvv=+1ZGCvkh$ISLzVfuam8PcpQ#Q4O z-}tK{#E&#$madg+-`y^V6<^(?qKo)VwM=L4V$~I_{q)^UeQVOAh$PL!^8-etim~u3 zvTpj{X$iVlW*=<2xWh_Kb{RC-gef<#en;1Lq6aC|N)m4KlfvZGq zX_?Gi--eh^AKl(WbM?GEiOio1Q|7F)c+mA)h}Z3Pf}B^HP!fMvv5&D?5*K3$FlM&@ zO)llm0g;`gJW6N&Djk^;!@UqT83wUXzKOGtkg29-}vhaH_)LSC!J29M_SFFRh;~86)S`E;Qzo zMKeBB%*3`7SATt@Ve?8cmA0MDLdxu}2Ya`do0l7@(h2Tq`+{lragZM4E2N&w(mv4{ z$37B?-4bN=;s_=MqCUH>3flIEWU|l`4RJEvT_bm3&@-Vz4gLsj9wz!iMEja{#f^9m zcH=CRn~@?%N#PMiVm8{qHNF3bhu94vqVB9~rDRAY^4}!&p$?U-9Axxa*VD+rp|prA zjTA1O6JyjFAwU#`zba!`*a#E9MerBiSCOR4Z(SM9Zc;@lS$wd%N&izdFY?OQI3d-? zA0{4=SJM|OGjOXXB=-8`aefblU~4ufGbPFxN)O zn*ETgblCyvbbXb%;T?AJkPIYmk4GcSs65^>{Rly*A+GW> z-lHC)?hd=xq0?dBalJ8Fjv5lF${S;+avba@{`HG?nws&$In_CJ1!X4z#ha%eAKfJV zNcuD4n%b3wLyhh{`aDqHN?w1S&ZvAf#q_702Mqj$3HhtMZ?5}DpR=9cJEuP9Q;V@s zJIGOes`}~cC+1I_pZNRK9t*7Ty-ambImzyMUQoH z>~Y>S-IU+t=Q-=)ckFR&d~)T)X7lAX=LGV#xsW4E=I4IHA9B4-Lm06RD4BN{v}=^f zlTRcbS^|EyXl7Pwmea0#nS!SztyfM^e*fccC`D-VyTgO6foQ*S#^NrJvRf)Ckxe=>--8;2X>q5I)doqPXV(XrD3MS>T z)>H~m8W&myU$1tbUfUVl0ZQ=IJdwzsma37eiC>pmr(RcE#}4cpJ`t8-xz6G!Y$)U_ zq%90L8mcd?yBLhN=&tIkHiURiZkN@?d44>xKvEzJr7%+dsSi>OQ|0SDjKH(@^)Ku7 zb|bwwnmL-ay^?pH`blGju#d4Z3`L>MpQy0arczzB8V+1y<_+f*oBbO5=aF;G3PPY!1u5S-#O9kE*?yS~1?mjq zj3b3q(4yaWzcoM3V@&_-FL}6M1A5F&YNcz%E7ot*a*q!+y*{?of2w^nzdgHTyDoq# zIrKw7mP8L1w=TmR;e+dYONszjh6G9u25A4$^59ZBRTqg0i6+VHTaUL_-rjw?N1jS) zOEE=(4r>e_ppj*IOhpecVfGD$46q(Lo`KAP=I$Lj5n~-I9fBQPs=w8H`BHjvS2}wt zt_KN>-hIYC%}Abe_S7+F@8PVfZVdj;JGQHw JcxmnI{H}2uXuRXryt2?m*;NtQ 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 literal 0 HcmV?d00001 diff --git a/website/src/content/docs/guides/gaufre-v2.mdx b/website/src/content/docs/guides/gaufre-v2.mdx new file mode 100644 index 0000000..d7adc9b --- /dev/null +++ b/website/src/content/docs/guides/gaufre-v2.mdx @@ -0,0 +1,87 @@ +--- +title: La Gaufre v2 +sidebar: + order: 40 +--- + + +

+![](./gaufre-v2-dinum.png) +
+ +La Gaufre v2 est une évolution de la [première version](/guides/gaufre) historique, qui ajoute plusieurs fonctionnalités : +* Un design en accord avec le [UI Kit](https://github.com/suitenumerique/ui-kit) de LaSuite. +* Un chargement des services à afficher en JSON, qui peut être effectué via une API dynamique ou fichier statique. +* L'utilisation du "Shadow DOM" qui permet aux styles du widget d'être indépendants de ceux de la page + +En configurant la Gaufre v2, il est possible de changer son contenu ou même son apparence. + +Voici par exemple une Gaufre pour la Suite territoriale : + +
+![](./gaufre-v2-anct.png) +
+ +## Intégration + +Il y a deux façons principales d'intégrer La Gaufre v2 dans votre service: + +### 1. Via le composant React + +Ce composant, qui intègre le bouton "Gaufre" ainsi que la pop-in, sera bientôt disponible dans le [UI Kit](https://github.com/suitenumerique/ui-kit). + +En attendant, vous pouvez [copier ce composant](https://github.com/suitenumerique/messages/blob/main/src/frontend/src/features/ui/components/lagaufre/index.tsx). + +### 2. Via le script JavaScript + +Cette option est à privilégier si vous n'utilisez pas React ou si vous ne souhaitez pas intégrer l'UI Kit dans votre application. + +Dans ce cas, vous devez intégrer le bouton "Gaufre". Le script gérera la pop-in et s'occupera de mettre à jour les attributs nécessaires sur le bouton lors des interactions. + +Voici un exemple complet d'intégration dans ce cas : + +```html + + + + + +``` + +Vous pouvez tester cet exemple sur cette [page dédiée](/widgets-demo/lagaufre-single). + +Nous avons une documentation interactive avec plusieurs [autres exemples de configuration](/widgets-demo/lagaufre). + +## Intégrations existantes + +Vous pouvez tester La Gaufre v2 en ligne sur ces services : + +* [Suite territoriale - Messages](https://messages.suite.anct.gouv.fr) diff --git a/website/src/pages/widgets-demo/feedback.html b/website/src/pages/widgets-demo/feedback.html new file mode 100644 index 0000000..812e44c --- /dev/null +++ b/website/src/pages/widgets-demo/feedback.html @@ -0,0 +1,98 @@ + + + + + + Feedback Widget Demo + + + +
Back to index +

Feedback Widget Demo

+ + + + + + + + +

+ + + + + +

+ + + + + \ No newline at end of file diff --git a/website/src/pages/widgets-demo/lagaufre-single.html b/website/src/pages/widgets-demo/lagaufre-single.html new file mode 100644 index 0000000..5817348 --- /dev/null +++ b/website/src/pages/widgets-demo/lagaufre-single.html @@ -0,0 +1,89 @@ + + + + + + La Gaufre Widget Demo + + + +
+ +

+ Back to index +

+ + + + + + + + + + +

La Gaufre - Single Page Demo

+

+ Try opening the Gaufre by clicking on the button on the top right! You can also use keyboard navigation. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +

+ + + +
diff --git a/website/src/pages/widgets-demo/lagaufre.html b/website/src/pages/widgets-demo/lagaufre.html new file mode 100644 index 0000000..53b8887 --- /dev/null +++ b/website/src/pages/widgets-demo/lagaufre.html @@ -0,0 +1,297 @@ + + + + + + La Gaufre Widget Demo + + + +
+ Back to index +

La Gaufre Widget Demo

+

This demo shows how to use the La Gaufre widget to display a list of services with subscription status.

+ +
+

Basic Usage

+

Open the widget with default settings:

+ +
+_lasuite_widget.push(['lagaufre', 'init', {
+    api: '/widgets/demo/lagaufre-data.json',
+    open: true
+}]);
+
+ +
+

With ANCT Data

+

Open the widget with ANCT services data:

+ +
+_lasuite_widget.push(['lagaufre', 'init', {
+    api: 'https://operateurs.suite.anct.gouv.fr/api/v1.0/lagaufre/services/?operator=9f5624fc-ef99-4d10-ae3f-403a81eb16ef&siret=21870030000013',
+    open: true
+}]);
+
+ +
+

With LaSuite data and style

+

Open the widget with gradient background:

+ +
+// With gradient background
+_lasuite_widget.push(['lagaufre', 'init', {
+    api: 'https://lasuite.numerique.gouv.fr/api/services',
+    open: true,
+    background: 'linear-gradient(180deg, #eceffd 0%, #FFFFFF 20%)',
+    headerLogo: 'https://lasuite.numerique.gouv.fr/_next/static/media/suite-numerique.ebdb6ce9.svg',
+    headerUrl: 'https://lasuite.numerique.gouv.fr',
+    showFooter: true
+}]);
+
+ +
+

With Custom Font

+

Open the widget with custom font family:

+ +
+// With custom font
+_lasuite_widget.push(['lagaufre', 'init', {
+    api: '/widgets/demo/lagaufre-data.json',
+    open: true,
+    fontFamily: 'Georgia, serif'
+}]);
+
+ +
+

Positioning Options

+

Control widget position and behavior:

+ + +
+// Top Right positioning
+_lasuite_widget.push(['lagaufre', 'init', {
+    api: '/widgets/demo/lagaufre-data.json',
+    open: true,
+    label: 'La Gaufre - Top Right',
+    position: 'fixed',
+    top: 20,
+    right: 20
+}]);
+ + +
+// Bottom Left positioning
+_lasuite_widget.push(['lagaufre', 'init', {
+    api: '/widgets/demo/lagaufre-data.json',
+    open: true,
+    label: 'La Gaufre - Bottom Left',
+    position: 'fixed',
+    bottom: 20,
+    left: 20
+}]);
+ + +
+// Absolute & dynamic positioning, tied to a button
+(button) => {
+    _lasuite_widget.push(['lagaufre', 'init', {
+        api: '/widgets/demo/lagaufre-data.json',
+        open: true,
+        label: 'La Gaufre - Bottom Left',
+        position: () => {
+            return {
+                position: 'absolute',
+                top: button.offsetTop + button.offsetHeight + 10,
+                right: window.innerWidth - button.offsetLeft - button.offsetWidth
+            };
+        },
+        buttonElement: button
+    }]);
+}
+ +
+ +
+

No dialog

+

You can insert the widget into an existing container:

+
+ + +
+// No dialog
+_lasuite_widget.push(['lagaufre', 'init', {
+    api: '/widgets/demo/lagaufre-data.json',
+    open: true,
+    dialogElement: document.getElementById('custom-box')
+}]);
+ + +
+_lasuite_widget.push(['lagaufre', 'close']);
+
+ +
+

With hardcoded data

+

You can pass static data and avoid any API calls:

+ +
+_lasuite_widget.push(['lagaufre', 'init', {
+    open: true,
+    data: {
+        "services": [
+            {
+                "name": "Authentication Service",
+                "url": "https://example.com/auth",
+                "logo": "/widgets/demo/logos/auth.svg",
+            },
+            {
+                "name": "Document Portal",
+                "url": "https://example.com/docs",
+                "logo": "/widgets/demo/logos/docs.svg",
+            },
+        ]
+    }
+}]);
+
+ +
+

Open and close Widget Programmatically

+

Close the widget programmatically after 2 seconds:

+ +
+_lasuite_widget.push(['lagaufre', 'init', {
+    api: '/widgets/demo/lagaufre-data.json'
+}]);
+setTimeout(() => {
+    _lasuite_widget.push(['lagaufre', 'open']);
+}, 300);
+setTimeout(() => {
+    _lasuite_widget.push(['lagaufre', 'close']);
+}, 2000);
+ + +
+_lasuite_widget.push(['lagaufre', 'toggle']);
+ +
+ +
+

Full localization

+

You can fully localize the widget:

+ +
+// Full localization
+_lasuite_widget.push(['lagaufre', 'init', {
+    api: '/widgets/demo/lagaufre-data.json',
+    open: true,
+    label: 'La Gaufre',
+    headerLogo: 'https://lasuite.numerique.gouv.fr/_next/static/media/suite-numerique.ebdb6ce9.svg',
+    headerUrl: 'https://lasuite.numerique.gouv.fr',
+    headerLabel: 'A propos de LaSuite',
+    closeLabel: 'Fermer la liste des services',
+    loadingText: 'Chargement des services...',
+    newWindowLabelSuffix: ' (nouvelle fenêtre)'
+}]);
+
+ +
+

API Response Format

+

The widget expects the following API response format:

+
+{
+  "services": [
+    {
+      "name": "Service Name",
+      "url": "https://service-url.com",
+      "maturity": "stable",
+      "logo": "/path/to.svg"
+    }
+  ]
+}
+
+
+ + + + + + + diff --git a/website/src/pages/widgets-demo/loader.html b/website/src/pages/widgets-demo/loader.html new file mode 100644 index 0000000..f974ff6 --- /dev/null +++ b/website/src/pages/widgets-demo/loader.html @@ -0,0 +1,69 @@ + + + + + + Loader Widget Demo + + + + Back to index +

Loader Widget Demo

+ + + + + + + + + + \ No newline at end of file