From 6bd352c7d5301d731a41ad921fddb33fab1de801 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Sat, 29 Aug 2026 16:23:52 -0700 Subject: [PATCH] feat(docs): added Python and Go docs, bump deps --- npm-shrinkwrap.json | 1046 ++++++++++------- package.json | 44 +- .../docs/lib-go.component.ts | 24 + .../docs/lib-python.component.ts | 24 + .../documentation.routing.ts | 4 + .../documentation.component.html | 2 + src/assets/documentation/libgo.md | 506 ++++++++ src/assets/documentation/libjava.md | 72 +- src/assets/documentation/libjavascript.md | 81 +- src/assets/documentation/libpython.md | 453 +++++++ .../ng2-charts/src/lib/ng-charts.provider.ts | 5 +- tsconfig.json | 1 + 12 files changed, 1760 insertions(+), 502 deletions(-) create mode 100644 src/app/documentation-module/docs/lib-go.component.ts create mode 100644 src/app/documentation-module/docs/lib-python.component.ts create mode 100644 src/assets/documentation/libgo.md create mode 100644 src/assets/documentation/libpython.md diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 0931f65b..60e92a22 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -9,42 +9,44 @@ "version": "2.2.1", "license": "MIT", "dependencies": { - "@angular/animations": "~22.1.2", - "@angular/cdk": "~22.1.2", - "@angular/common": "~22.1.2", - "@angular/compiler": "~22.1.2", - "@angular/core": "~22.1.2", - "@angular/forms": "~22.1.2", - "@angular/localize": "~22.1.2", - "@angular/material": "~22.1.2", - "@angular/platform-browser": "~22.1.2", - "@angular/platform-browser-dynamic": "~22.1.2", - "@angular/router": "~22.1.2", - "@angular/service-worker": "~22.1.2", + "@angular/animations": "~22.1.4", + "@angular/cdk": "~22.1.4", + "@angular/common": "~22.1.4", + "@angular/compiler": "~22.1.4", + "@angular/core": "~22.1.4", + "@angular/forms": "~22.1.4", + "@angular/localize": "~22.1.4", + "@angular/material": "~22.1.4", + "@angular/platform-browser": "~22.1.4", + "@angular/platform-browser-dynamic": "~22.1.4", + "@angular/router": "~22.1.4", + "@angular/service-worker": "~22.1.4", "@apollo/client": "^4.2.12", "@ng-bootstrap/ng-bootstrap": "~21.0.0", "@types/grecaptcha": "^3.0.9", "apollo-angular": "^14.2.0", "chart.js": "^4.5.1", "core-js": "^3.50.0", - "es-toolkit": "^1.50.0", + "es-toolkit": "^1.52.0", "graphql": "^17.0.2", "graphql-tag": "^2.12.7", - "ngx-markdown": "^22.0.0", + "katex": "^0.18.4", + "marked-katex-extension": "^5.1.12", + "ngx-markdown": "^22.0.2", "rxjs": "^7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.4", - "@angular/cli": "^22.1.4", - "@angular/compiler-cli": "~22.1.2", - "@types/node": "^26.2.0", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", + "@angular/compiler-cli": "~22.1.4", + "@types/node": "^26.4.0", "@types/react": "^19.2.18", "angular-eslint": "22.1.0", - "eslint": "^10.8.1", + "eslint": "^10.9.1", "ts-node": "^10.9.2", "typescript": "^6.0.3", - "typescript-eslint": "8.67.0" + "typescript-eslint": "8.68.0" } }, "node_modules/@ampproject/remapping": { @@ -62,13 +64,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2201.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2201.4.tgz", - "integrity": "sha512-a2J9hdBYFobhMx9G0KwCdo6+LrWIOOyIeijrA/QSZiPOjg8dAprhMh7BEQkF3eT6R1q7wDGP+IElVR9LsBlXQw==", + "version": "0.2201.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2201.6.tgz", + "integrity": "sha512-oGQEdof2/1bZk58PN9dvpGi8pvtbgE5vkP1xRtCqN8dSVxwre1l0pKynOj/Uge1KxjCvs4c1QrQu0vsAnY0vpg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "22.1.4", + "@angular-devkit/core": "22.1.6", "rxjs": "7.8.2" }, "bin": { @@ -81,9 +83,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "22.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.1.4.tgz", - "integrity": "sha512-40jG/6chng9fQuWtpg1kadPO17sRTurNh0aav6Uxebn65PfNpTpvhPIYVIcRgv4tCKdMd++YH95A8SiaIOwqig==", + "version": "22.1.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.1.6.tgz", + "integrity": "sha512-KLBsZoc2RhOy0xSdeYcLoSOqV/fBP3feBmhY9o12ry2IuyW/17sCmWr6XbIfTIYQN6M98Y1ewmwVNFsvV5b0gA==", "dev": true, "license": "MIT", "dependencies": { @@ -109,13 +111,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "22.1.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-22.1.4.tgz", - "integrity": "sha512-UBJ7jc7B0vRfmrVwlvpmuudo1D7AfpO6ugf1BxvkM4sw5m8cJpZtaIJFKBorv0QZo78CyDOroQfQdXaijjB2ZA==", + "version": "22.1.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-22.1.6.tgz", + "integrity": "sha512-IbDO9KbQyQm20uinsfT8d9ZtQw41/WVutI/65mAw39WZfN8Ky+MOgOUJCGLiSccMprvZ9YdodBTnN9bLH149Ag==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "22.1.4", + "@angular-devkit/core": "22.1.6", "jsonc-parser": "3.3.1", "magic-string": "1.0.0", "ora": "9.4.1", @@ -237,9 +239,10 @@ } }, "node_modules/@angular/animations": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-22.1.2.tgz", - "integrity": "sha512-SHvopFG8I92isKE6lgoWVVmmt6fSGKt76bfrBuJ9qvrKWYqWmWUh87Z5J3XRPUM8zdzuEkXjcTbn+GTGOGRiaA==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-22.1.4.tgz", + "integrity": "sha512-DZqSHhmSRBVfLlrFxNLQj6PYVhu1w8vj1iUdD6fmlhfGGafuiw/VcUpBgYmy2YNcXmGmwbZsKr1oeJP7fT8zNQ==", + "deprecated": "@angular/animations is deprecated. Use `animate.enter` and `animate.leave` instead. For more information see: https://v22.angular.dev/guide/animations.", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -248,18 +251,18 @@ "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/core": "22.1.2" + "@angular/core": "22.1.4" } }, "node_modules/@angular/build": { - "version": "22.1.4", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-22.1.4.tgz", - "integrity": "sha512-y5wxiyUu1DjYNG5jiFjjgFp7O5bkyYjWzy2kfyTGq+DjKMEveTzNH3tBkZrE33EJ4wYyfx+rQ01IG9nZbhfdvA==", + "version": "22.1.6", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-22.1.6.tgz", + "integrity": "sha512-J7JBd3hDAV4dlGNMavDC0KjtvbDd4KOddaom1inwkq92tYnD1ljmhDDigAsUBnRvQhJ82cvagD8zi0s9Ki4rTQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2201.4", + "@angular-devkit/architect": "0.2201.6", "@babel/core": "8.0.1", "@babel/helper-annotate-as-pure": "8.0.0", "@babel/helper-split-export-declaration": "7.24.7", @@ -270,7 +273,7 @@ "esbuild": "0.28.2", "https-proxy-agent": "9.1.0", "jsonc-parser": "3.3.1", - "listr2": "10.2.2", + "listr2": "11.0.0", "magic-string": "1.0.0", "mrmime": "2.0.1", "oxc-parser": "0.142.0", @@ -301,7 +304,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/platform-server": "^22.0.0", "@angular/service-worker": "^22.0.0", - "@angular/ssr": "^22.1.4", + "@angular/ssr": "^22.1.6", "istanbul-lib-instrument": "^6.0.0", "karma": "^6.4.0", "less": "^4.2.0", @@ -358,27 +361,10 @@ } } }, - "node_modules/@angular/build/node_modules/listr2": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-10.2.2.tgz", - "integrity": "sha512-JtNtbZj8q5BnDMR7trpwvwk3RIrANtIVzEUm8w7amp6xelLgyuq+4WZoTH913XaQAoH/cNdYhaNzBPA2U3xbDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^5.2.0", - "eventemitter3": "^5.0.4", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^10.0.0" - }, - "engines": { - "node": ">=22.13.0" - } - }, "node_modules/@angular/cdk": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-22.1.2.tgz", - "integrity": "sha512-YwTzVnTgZIQDLq3lnnPLINIB24e0SiDn7XxBxHSrOzD/+Y0zLAid5XIiMALXWOqa7rfdhfVh1kEeM93RRLnllQ==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-22.1.4.tgz", + "integrity": "sha512-//KICh/rxeLbYLgNj8HawaliVAPNlSV0aRmki45Tf/YhoXVhzon9DfFqCs5u1cLvmMkMTHdFm5ghGTB8SUv3DA==", "license": "MIT", "dependencies": { "parse5": "^8.0.0", @@ -392,21 +378,21 @@ } }, "node_modules/@angular/cli": { - "version": "22.1.4", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-22.1.4.tgz", - "integrity": "sha512-Yt6q7a1vXh0ICFHnRdUOmx/gEXZ87zpkvE1eUWREUqeQ3ARkwqNZVzF3IP+s9NpDDrnc+EB9cqel9SnGZ/0z2Q==", + "version": "22.1.6", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-22.1.6.tgz", + "integrity": "sha512-HT3OzYkSpCyXMTgD5G1tsS7vkrY8cYJ/JgSjRjrpwOAooSMtKF1hv7BgBcn79sKg4eaiPLrDpQLXP93vHxgSFg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2201.4", - "@angular-devkit/core": "22.1.4", - "@angular-devkit/schematics": "22.1.4", + "@angular-devkit/architect": "0.2201.6", + "@angular-devkit/core": "22.1.6", + "@angular-devkit/schematics": "22.1.6", "@inquirer/prompts": "8.5.2", - "@listr2/prompt-adapter-inquirer": "4.2.4", + "@listr2/prompt-adapter-inquirer": "4.2.5", "@modelcontextprotocol/sdk": "1.30.0", - "@schematics/angular": "22.1.4", + "@schematics/angular": "22.1.6", "jsonc-parser": "3.3.1", - "listr2": "10.2.2", + "listr2": "11.0.0", "npm-package-arg": "14.0.0", "parse5-html-rewriting-stream": "8.0.1", "semver": "7.8.5", @@ -422,27 +408,10 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/listr2": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-10.2.2.tgz", - "integrity": "sha512-JtNtbZj8q5BnDMR7trpwvwk3RIrANtIVzEUm8w7amp6xelLgyuq+4WZoTH913XaQAoH/cNdYhaNzBPA2U3xbDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^5.2.0", - "eventemitter3": "^5.0.4", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^10.0.0" - }, - "engines": { - "node": ">=22.13.0" - } - }, "node_modules/@angular/common": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-22.1.2.tgz", - "integrity": "sha512-8TzyYPBDvSItV8Vqq8k5u8a9fWaomC9bMEr8z1vVLRZDIPhNQ/UcCyuTYbC7GZkeqrrKGu5m8tjUrA09RCwuaQ==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-22.1.4.tgz", + "integrity": "sha512-UtWCloA/d0I5twV9Lu/Fcc7T6uQb40f/k0Hj5HLohIsiLTyvXVxWINBfa7LWWLtcq/0UOIY/yCs9Zq9Sj4dWqA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -451,14 +420,14 @@ "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/core": "22.1.2", + "@angular/core": "22.1.4", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-22.1.2.tgz", - "integrity": "sha512-aQv0p5MeXuguCeftUUxK4H8Hbw1hC5Zyu+cFsGbsi025LZ9Ngw+BW+iUHDQZAcqHvWDw2wgGOdKh4e7IkcfRyQ==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-22.1.4.tgz", + "integrity": "sha512-o+W0shjR5KmPPWchFmqN9bLINYAy14zIW//g9T5WqKDMOqjt4IbeY6AKOoE1db/dXffprLEH9nyPOmi19iKNxg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -468,9 +437,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-22.1.2.tgz", - "integrity": "sha512-GWRtvQQz/LvKejF/Zpls+hGnnJkvaPPtd3TZnxfZQ1fYCs7b7gpi0YM9PP02TJz51vhlsgkPYJwgtJAKDJEHNQ==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-22.1.4.tgz", + "integrity": "sha512-h9CcVG614TJLbk+dswlzSjYARYJh2MLOEwcnpt9zUGtOffhrrSS9BFJGjSwzdDSVM3J5mvf5ZuW+0hPAuRRoOA==", "license": "MIT", "dependencies": { "@babel/core": "8.0.1", @@ -490,7 +459,7 @@ "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/compiler": "22.1.2", + "@angular/compiler": "22.1.4", "typescript": ">=6.0 <6.1" }, "peerDependenciesMeta": { @@ -500,9 +469,9 @@ } }, "node_modules/@angular/core": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-22.1.2.tgz", - "integrity": "sha512-t7BrgfdeqbdSbFe3CsGX8ySMeKDlZNBPxFMCOanAAqd6W0H1Kh1WFILBs3DIg0NfjpybfSRJAzKcagOFQWNtiw==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-22.1.4.tgz", + "integrity": "sha512-0dW+lw8nHo6RGBUOXtjs02vjHIPJ8rEbw4fd0NH3Dii4p+gIB4ZaTw+o7Se3Nf4m1oZ8+2qAYmWVHXlfhKcCDg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -511,7 +480,7 @@ "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/compiler": "22.1.2", + "@angular/compiler": "22.1.4", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, @@ -525,9 +494,9 @@ } }, "node_modules/@angular/forms": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-22.1.2.tgz", - "integrity": "sha512-pKDYSNKje/jox74KzswBdX4sL7kJ8OFkJwLnqng8oc7a/NVl/Vf4/Xq4kyowRAdtPcZfLTUnZG6s0qbegfV5mg==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-22.1.4.tgz", + "integrity": "sha512-w8ZXe4oURrb/DS5zAFrR4AmGXC84sdLeOKXRM76ndRRgSCzyRLEe4wDU1KHnDejNVIGvoSZYJJjOajG1lpj8TA==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -538,16 +507,16 @@ "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/common": "22.1.2", - "@angular/core": "22.1.2", - "@angular/platform-browser": "22.1.2", + "@angular/common": "22.1.4", + "@angular/core": "22.1.4", + "@angular/platform-browser": "22.1.4", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/localize": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-22.1.2.tgz", - "integrity": "sha512-FOCVI/DPmPtDOVHhpAJ6xPaTi924KAcw9GBoh1ne8/l6/aj6oVwfR36qM+3RNhkxqQjVr2Bbu8roihk07s8I1Q==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-22.1.4.tgz", + "integrity": "sha512-U9Kq6b/JuSQBEmkpwlspbPHb5/Z2ZOEOBbgeZWOytmAud2FIYR9kW6mcyXbYNRbB4Jnv3GzNrP8avbCMG984PQ==", "license": "MIT", "dependencies": { "@babel/core": "8.0.1", @@ -563,20 +532,20 @@ "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/compiler": "22.1.2", - "@angular/compiler-cli": "22.1.2" + "@angular/compiler": "22.1.4", + "@angular/compiler-cli": "22.1.4" } }, "node_modules/@angular/material": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-22.1.2.tgz", - "integrity": "sha512-KX0bVUppfwjDfUepsjpG1CAQGUGHI0l5e0QYpFcskB+1wNRCocBGsIO1br5z6neYu0rzsbhtWocjCeH05gwi7w==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-22.1.4.tgz", + "integrity": "sha512-d4+uajpIYmyjar/4dypd5L+z8pbgkaCOsSxsrslmE0o0wK7mfFvXCkn0wwfucey5yUHXjswlKu1X5RzJZLOZ+w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/cdk": "22.1.2", + "@angular/cdk": "22.1.4", "@angular/common": "^22.0.0 || ^23.0.0", "@angular/core": "^22.0.0 || ^23.0.0", "@angular/forms": "^22.0.0 || ^23.0.0", @@ -585,9 +554,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-22.1.2.tgz", - "integrity": "sha512-MQO735ve/tk4gLsWbw8NyBD/DxPfbbmf1pM/vp6K7tZz2xyysMXilqF/k8PBdQBZVOofST8S13inZHQ35nHuRA==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-22.1.4.tgz", + "integrity": "sha512-zhEWnRShG6GjnEvCVROD68XfnrV6+HJ9bPjwZx4LsAz7spX823Nhiml8Uqpvijsa1w7UdWLU7nK/magr9IEMOQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -596,9 +565,9 @@ "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/animations": "22.1.2", - "@angular/common": "22.1.2", - "@angular/core": "22.1.2" + "@angular/animations": "22.1.4", + "@angular/common": "22.1.4", + "@angular/core": "22.1.4" }, "peerDependenciesMeta": { "@angular/animations": { @@ -607,9 +576,10 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-22.1.2.tgz", - "integrity": "sha512-nNARbs9zXfoJL72zsTso6GHt1VuIGXWEpyZtzxcC32qQFG1YbzVqGkQTwZ0mZ2/Ctv8dAZ6PPiDo8sbYvAvUDw==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-22.1.4.tgz", + "integrity": "sha512-gtaQ05csHot468owe3AOXJYd2/VPlIQFr3tyXV8O2vhkfTokAyynpaMLc2q7EWbrDDuMvzETR2sBKBhgqIul+A==", + "deprecated": "@angular/platform-browser-dynamic is deprecated. Use `@angular/platform-browser` instead.", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -618,16 +588,16 @@ "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/common": "22.1.2", - "@angular/compiler": "22.1.2", - "@angular/core": "22.1.2", - "@angular/platform-browser": "22.1.2" + "@angular/common": "22.1.4", + "@angular/compiler": "22.1.4", + "@angular/core": "22.1.4", + "@angular/platform-browser": "22.1.4" } }, "node_modules/@angular/router": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-22.1.2.tgz", - "integrity": "sha512-C2c6NJ9HZUfb1L07M554Zpgvi0TvpOBO6Og9L36v/jsv42m7tpOenvqQVPa8R3va7eqLEszCL7wLFcWeJ8naew==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-22.1.4.tgz", + "integrity": "sha512-vCwJLRnFBSRH5LxSF8OXKBhdmJ526hVGb/5sfeLTQW/oWCdcfXb2RvHfB077m5cdqKX9sBwFVlkJ8Z8kgx/pLQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -636,16 +606,16 @@ "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/common": "22.1.2", - "@angular/core": "22.1.2", - "@angular/platform-browser": "22.1.2", + "@angular/common": "22.1.4", + "@angular/core": "22.1.4", + "@angular/platform-browser": "22.1.4", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "22.1.2", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-22.1.2.tgz", - "integrity": "sha512-5hq1Xm1iltF6sYVtgVuV8kP17X7QU8oPHwQhbl3S8r4Kobx9daH1ERsUx6DvOBeL7na7qVHGD3iJ5vUUgRQxtg==", + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-22.1.4.tgz", + "integrity": "sha512-UKRtwePIiZtrKFNn8Uc/I8TNu0941K7Z56klSXaP6F0xaS2U4FsOcqIdWxDBIL6CEnyxjjX1n4v71v2hbSkXQQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -657,7 +627,7 @@ "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/core": "22.1.2", + "@angular/core": "22.1.4", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -1660,16 +1630,43 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.1.tgz", - "integrity": "sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.3.tgz", + "integrity": "sha512-XEYX2WA8SBkLPczL6/yXPHLPCvDoptmh9v56Cy05BSV1Smk1vWy19bTC4qJBuIffw7+6l4CcaYYzGqG60RfW1g==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/ansi": "^2.0.7", - "@inquirer/core": "^11.2.1", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.1", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/checkbox/node_modules/@inquirer/core": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.1.tgz", + "integrity": "sha512-JMD5Jy/ScL5TZE18m83Nw25HjqGFLoWXwnEkW7IdwwAhZpB9Bus55/WU7zn3UqR1MOCjjTQOIYpiD4vjWA3LPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1733,15 +1730,42 @@ } }, "node_modules/@inquirer/editor": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.2.2.tgz", - "integrity": "sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.3.1.tgz", + "integrity": "sha512-y43COoyVUjPWIobn2Qep/uI1drPS78aaZZZ9kVi94Tyu/GuW2N8d8Q4rifJXGAXCEAXCPTTMjD8gC1HyvM5ukA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/external-editor": "^3.0.3", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.1", + "@inquirer/external-editor": "^3.0.4", + "@inquirer/type": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor/node_modules/@inquirer/core": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.1.tgz", + "integrity": "sha512-JMD5Jy/ScL5TZE18m83Nw25HjqGFLoWXwnEkW7IdwwAhZpB9Bus55/WU7zn3UqR1MOCjjTQOIYpiD4vjWA3LPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1756,14 +1780,41 @@ } }, "node_modules/@inquirer/expand": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.1.tgz", - "integrity": "sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.3.tgz", + "integrity": "sha512-3NQJiXNJ/aj9wiAsr7pECdp5Qe9J0X9YUJCKsaFXS+ddOxfL6J4AIl3w3T4Gq3kK0WsQY5GMoDokK5X94m6lHw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.1", + "@inquirer/type": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand/node_modules/@inquirer/core": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.1.tgz", + "integrity": "sha512-JMD5Jy/ScL5TZE18m83Nw25HjqGFLoWXwnEkW7IdwwAhZpB9Bus55/WU7zn3UqR1MOCjjTQOIYpiD4vjWA3LPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1778,9 +1829,9 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.4.tgz", + "integrity": "sha512-tZbbaK2ovq6vlrRBNQvjrypmrED/p5x2ncIHQ79cD55tei3dD96v5glMMA+6tiq7K104i/25DVYKWVPJuV6ptA==", "dev": true, "license": "MIT", "dependencies": { @@ -1800,9 +1851,9 @@ } }, "node_modules/@inquirer/figures": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz", - "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.8.tgz", + "integrity": "sha512-tApbon79GM9ry56ja/Ud3SY2CL4TQsao9fIwDQbgTeNY55025GdMzQ2+UdegV/lx51VNGUB59M0v0nMpybYY4Q==", "dev": true, "license": "MIT", "engines": { @@ -1810,14 +1861,41 @@ } }, "node_modules/@inquirer/input": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.2.tgz", - "integrity": "sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.4.tgz", + "integrity": "sha512-3xQkQrOvgOzpSN2ciTVdRDlg1FWMCA8l+0KfB6SNlILoTCGzJTzO/gc0Rwjcb3usuGyKdaGtI6OiyMdeMeLWkg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.1", + "@inquirer/type": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/input/node_modules/@inquirer/core": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.1.tgz", + "integrity": "sha512-JMD5Jy/ScL5TZE18m83Nw25HjqGFLoWXwnEkW7IdwwAhZpB9Bus55/WU7zn3UqR1MOCjjTQOIYpiD4vjWA3LPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1832,14 +1910,41 @@ } }, "node_modules/@inquirer/number": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.1.1.tgz", - "integrity": "sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.2.1.tgz", + "integrity": "sha512-5KaqwZNLRpUuWcoCrYghPP9TMaXL5v2Sk4xqePM7RCVegcJStoXdWibio60YIC1bec+z1fCyb67N6XPJIkZtGA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.1", + "@inquirer/type": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number/node_modules/@inquirer/core": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.1.tgz", + "integrity": "sha512-JMD5Jy/ScL5TZE18m83Nw25HjqGFLoWXwnEkW7IdwwAhZpB9Bus55/WU7zn3UqR1MOCjjTQOIYpiD4vjWA3LPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1854,15 +1959,42 @@ } }, "node_modules/@inquirer/password": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.1.1.tgz", - "integrity": "sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.2.0.tgz", + "integrity": "sha512-CvVcW09emkBESEOW+4R8CjLNkP3fB3XrjeL8CDvfpjgrJN+V9oerXmJAXXM3l+4xqYPD5Yaujzy/Ph0PLOdDuA==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/ansi": "^2.0.7", - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.1", + "@inquirer/type": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password/node_modules/@inquirer/core": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.1.tgz", + "integrity": "sha512-JMD5Jy/ScL5TZE18m83Nw25HjqGFLoWXwnEkW7IdwwAhZpB9Bus55/WU7zn3UqR1MOCjjTQOIYpiD4vjWA3LPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1907,14 +2039,41 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.1.tgz", - "integrity": "sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.3.tgz", + "integrity": "sha512-Mu7WrtmDLaXBDEyrRLS70SZgX9ZSm4Up1w0ZxiH8C1OOp9oaVCn2k8q3QGgmlnhsKYUhuaU3zFWhAP6wxkVIMA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.1", + "@inquirer/type": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist/node_modules/@inquirer/core": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.1.tgz", + "integrity": "sha512-JMD5Jy/ScL5TZE18m83Nw25HjqGFLoWXwnEkW7IdwwAhZpB9Bus55/WU7zn3UqR1MOCjjTQOIYpiD4vjWA3LPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1929,15 +2088,42 @@ } }, "node_modules/@inquirer/search": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.2.1.tgz", - "integrity": "sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.3.1.tgz", + "integrity": "sha512-0VWOvsHWI0rPj6CG70MoP4oXNCB6adcyN8bVFZXnh11eLDdPIK2f2XCmva78acPPDfJisfab7qNakwBh7hdBXw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.1", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search/node_modules/@inquirer/core": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.1.tgz", + "integrity": "sha512-JMD5Jy/ScL5TZE18m83Nw25HjqGFLoWXwnEkW7IdwwAhZpB9Bus55/WU7zn3UqR1MOCjjTQOIYpiD4vjWA3LPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1952,16 +2138,43 @@ } }, "node_modules/@inquirer/select": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.1.tgz", - "integrity": "sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.3.tgz", + "integrity": "sha512-KuRTodDa6xBXX2noIpjuitpX/QT7Sfav7dIZ/OfUY54Hxg95nrGoshSzxx6Ey7qqLbImKdiGkSDt7KjPXjQgmA==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/ansi": "^2.0.7", - "@inquirer/core": "^11.2.1", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.1", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select/node_modules/@inquirer/core": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.1.tgz", + "integrity": "sha512-JMD5Jy/ScL5TZE18m83Nw25HjqGFLoWXwnEkW7IdwwAhZpB9Bus55/WU7zn3UqR1MOCjjTQOIYpiD4vjWA3LPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.8", + "@inquirer/type": "^4.1.0", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1976,9 +2189,9 @@ } }, "node_modules/@inquirer/type": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", - "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.1.0.tgz", + "integrity": "sha512-FMiJpuHUG3Dk0ex+UIXkre7i+i4OcwHWk9YdcVtZHFwb/r2rnrU2ipTCNAB7A+QOP0ryzIcqOfy76fRyyvOEAw==", "dev": true, "license": "MIT", "engines": { @@ -2013,9 +2226,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -2035,20 +2248,20 @@ "license": "MIT" }, "node_modules/@listr2/prompt-adapter-inquirer": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-4.2.4.tgz", - "integrity": "sha512-/KRI2DMD7JGSYaREF0Ygl7AefJ/2ase4Gc5cBiKqT5l4tFjsSJfhFGcc5nSkgl0Sp9LkCQNzl/cqbVJYP2L3dw==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-4.2.5.tgz", + "integrity": "sha512-pYGy9dTdTwXdasPgyohkr0HoQ4FrkAzFnsUZl/gcnadDArbpZ8e+fgr+F9WBdNEl2y00mb9bCM4WgmoBkZJ27A==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/type": "^4.0.6" + "@inquirer/type": "^4.0.7" }, "engines": { "node": ">=22.13.0" }, "peerDependencies": { "@inquirer/prompts": ">= 3 < 9", - "listr2": "10.2.1" + "listr2": "11.0.0" } }, "node_modules/@lmdb/lmdb-darwin-arm64": { @@ -3641,14 +3854,14 @@ "license": "MIT" }, "node_modules/@schematics/angular": { - "version": "22.1.4", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-22.1.4.tgz", - "integrity": "sha512-uiYKuiCnkTEbs4eOU1QJlM5NPw6BR1qgpct8VlrhS4n861WCCjTy5cxiAWJ3Doc0R72d44j3uoBfAEp7KEVn2w==", + "version": "22.1.6", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-22.1.6.tgz", + "integrity": "sha512-RiD4OZJ4yuaM1aXb3pt1gjDSWwkP0jrgiCuoaBls1eabcrDmlsNuQv0ekxbcGgCRPdSJvmHRZIHHmFPzei8w3Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "22.1.4", - "@angular-devkit/schematics": "22.1.4", + "@angular-devkit/core": "22.1.6", + "@angular-devkit/schematics": "22.1.6", "jsonc-parser": "3.3.1", "typescript": "6.0.3" }, @@ -3665,9 +3878,9 @@ "license": "MIT" }, "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.13.tgz", + "integrity": "sha512-gcLdvR9HO1ZJBypsOGqaP6TFEzb6vIta0KSTLt9NAQ6pXQO3cRgSVyCN6pzYqI9DlJgY71XKO0dpDhCf08b3pg==", "dev": true, "license": "MIT" }, @@ -3743,9 +3956,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", - "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.0.tgz", + "integrity": "sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3763,17 +3976,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz", - "integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.68.0.tgz", + "integrity": "sha512-WASHDpCm6qO5jj9g1a+8NiW5+GCkAyLReR56/4VruYmNgfUmqpxOfZ2Yfb8xGfJPWv5Qi6LSD8sXdces3vbp/Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/type-utils": "8.67.0", - "@typescript-eslint/utils": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/type-utils": "8.68.0", + "@typescript-eslint/utils": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -3786,22 +3999,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.67.0", + "@typescript-eslint/parser": "^8.68.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz", - "integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.68.0.tgz", + "integrity": "sha512-fHq2VC1kpyYfvEcbiMjOpySY4WS7voEp89yAThrHRX5sm9j2lzYppCb2umFMEed4fWcyeLjHxrz0mpjNBaBxMQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", "debug": "^4.4.3" }, "engines": { @@ -3817,14 +4030,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz", - "integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.68.0.tgz", + "integrity": "sha512-5GQtWZCXFcFYux955pvoS02WLc49pXNlvIxocKjS0clvwo3in1RdlzVKyiqQH9vE5AKWFLTaUgeQkOrTS+0Qxw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.67.0", - "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/tsconfig-utils": "^8.68.0", + "@typescript-eslint/types": "^8.68.0", "debug": "^4.4.3" }, "engines": { @@ -3839,14 +4052,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", - "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.68.0.tgz", + "integrity": "sha512-T5eXpcaJNg8bhjHJ8Rjp68Vq/QBteYtTKY8TZqVNPaUbuz0f6jI9t6aDkylwvalpAB9XTTFeFOjrjXAZ3YvmVA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0" + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3857,9 +4070,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz", - "integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.68.0.tgz", + "integrity": "sha512-F7zrGQfiJHojPwi8vhxZQC1tWtJzvL74cK/nqri2lk8YUXvYaYwl263xOJ69jDWPUk1hmcdoayFwk9lX09npVw==", "dev": true, "license": "MIT", "engines": { @@ -3874,15 +4087,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz", - "integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.68.0.tgz", + "integrity": "sha512-X77zqoY1EjeWGs/0JNxeaMfp5C5lIz4Tw8y66F1Ne8Faq6g424sBNYM6xBAqElfGZPLpWS+CZAp0DXyKDzWiHg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/utils": "8.67.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/utils": "8.68.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -3899,9 +4112,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", - "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.68.0.tgz", + "integrity": "sha512-9RnpsGJjrAllCMefGVVsImJM24YurhC0Q1h4UbvivtvOqXmR/vEJge2OoE++z9m6hyg8T1Q8t5SNT6tHSbrxcg==", "dev": true, "license": "MIT", "engines": { @@ -3913,16 +4126,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", - "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.68.0.tgz", + "integrity": "sha512-OKKsD0tYmoNiU5PW2zehO1yO56jYOm1ShYlxon/Z0SJNidAkdVg86eg9ruRuoXf8xfnuWZGbwDsStkoXbZtIIA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.67.0", - "@typescript-eslint/tsconfig-utils": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", + "@typescript-eslint/project-service": "8.68.0", + "@typescript-eslint/tsconfig-utils": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/visitor-keys": "8.68.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -3941,16 +4154,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz", - "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.68.0.tgz", + "integrity": "sha512-PB5gJMMOg0Q5P1tsgWtEAqQacJXq0qEqRHDX/YJ4FaTMLfZPpHB3gjl2EJuiZyPABxmj4ZQYiY9m1bdAJ5y7tQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0" + "@typescript-eslint/scope-manager": "8.68.0", + "@typescript-eslint/types": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3965,13 +4178,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", - "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.68.0.tgz", + "integrity": "sha512-YR65gGdGvTUAWLldC3xLOvOzamdGzB4A5/N8rehEaHs3Zvoe39BhgY+u0SPch1OvrVTfLcc55wsSgK2NcnTS/A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/types": "8.68.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -4271,9 +4484,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.11.14", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.14.tgz", - "integrity": "sha512-JyJ954WzuIR8/FFzX0o5krdSTrBAkcCSRfWSleRsIHSWV+cZe2FI1PKggVkFke1hBldRs+LRxUczzE9iPmgZww==", + "version": "2.11.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", + "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -4444,9 +4657,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001809", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", - "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==", + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", "funding": [ { "type": "opencollective", @@ -4540,17 +4753,17 @@ } }, "node_modules/cli-truncate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", - "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-6.1.1.tgz", + "integrity": "sha512-06p9vyLahLa4zkGcgsGxU6iEkSOiuI4fhCH6Emhe2lPAcoUv73n72DnODsnHA+5wwXGnV0n9M9/qOQJSjYhFhw==", "dev": true, "license": "MIT", "dependencies": { - "slice-ansi": "^8.0.0", + "slice-ansi": "^9.0.0", "string-width": "^8.2.0" }, "engines": { - "node": ">=20" + "node": ">=22" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4614,6 +4827,15 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/content-disposition": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", @@ -4892,9 +5114,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.406", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.406.tgz", - "integrity": "sha512-hWH5ORBi3d0IipnMh7BN5GDTaAmrSSSWmznwt2zltdiRNEWoEQyTwF0FFSBxzHO7hLSRT6loQu3IQGV0wg/Tvg==", + "version": "1.5.416", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.416.tgz", + "integrity": "sha512-K6bvB2BjnNrugtIih6ewlbBI9DXa976jIdiIlRLHhBoEI9a4JaQjjHyF+A1IQI543aQYR4LnmOrT/K5fZj0aPA==", "license": "ISC" }, "node_modules/emoji-regex": { @@ -4982,14 +5204,15 @@ } }, "node_modules/es-toolkit": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.50.0.tgz", - "integrity": "sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", + "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==", "license": "MIT", "workspaces": [ "docs", "benchmarks", - "tests/types" + "tests/types", + "tests/browser-compat" ] }, "node_modules/esbuild": { @@ -5064,9 +5287,9 @@ } }, "node_modules/eslint": { - "version": "10.8.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.1.tgz", - "integrity": "sha512-wqA7W2jbsC/BnV9Iv1UZpKVFkO1AdNoSmYW8NWG4HNOBbkAMvIqDZ27pI2f07dqn583NcIC44ckjAcOXDL1QbQ==", + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.9.1.tgz", + "integrity": "sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A==", "dev": true, "license": "MIT", "workspaces": [ @@ -5288,13 +5511,6 @@ "node": ">= 0.6" } }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true, - "license": "MIT" - }, "node_modules/eventsource": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", @@ -5363,9 +5579,9 @@ } }, "node_modules/express-rate-limit": { - "version": "8.6.2", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.6.2.tgz", - "integrity": "sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.7.0.tgz", + "integrity": "sha512-hOwV7WOxXfjRpAM1DSJWZDXx3GhplwD8IfwuwvogD8i1Qnkgosw/H45s4ZnFAUHDAhPjlY9hLBvJhKmGMyY26g==", "dev": true, "license": "MIT", "dependencies": { @@ -5421,9 +5637,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.6.tgz", + "integrity": "sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==", "dev": true, "funding": [ { @@ -5735,9 +5951,9 @@ } }, "node_modules/hono": { - "version": "4.13.2", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.2.tgz", - "integrity": "sha512-JydRilDRkYBQMt9qR9U92mXxmbGqsqSn/IKOrh4e7/gEbn+0zSr8igTu0obwJoNGN4sez28DIql7FBHWydoJpA==", + "version": "4.13.5", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.5.tgz", + "integrity": "sha512-O6+/eCYRkzzzy0rPWwKLiGBR1nFuUPZynnwjxN1MBA62NNqbT0wQEzQyK2gSO5yDIDB336sXQleAhOHrzlYyKw==", "dev": true, "license": "MIT", "engines": { @@ -5888,9 +6104,9 @@ "license": "ISC" }, "node_modules/ip-address": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.5.0.tgz", - "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz", + "integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==", "dev": true, "license": "MIT", "engines": { @@ -5987,9 +6203,9 @@ "license": "ISC" }, "node_modules/jose": { - "version": "6.2.8", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.8.tgz", - "integrity": "sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==", + "version": "6.2.10", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.10.tgz", + "integrity": "sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g==", "dev": true, "license": "MIT", "funding": { @@ -6061,6 +6277,22 @@ "dev": true, "license": "MIT" }, + "node_modules/katex": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.18.4.tgz", + "integrity": "sha512-IMPntbRLOU+eu88XDiFKqQ8Akhr9Tv7jDMXqPhjG9SI1JMA4DIgXk4x9k4skJz2NZJXBRbC+2pYBLj9olqcZow==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -6359,17 +6591,14 @@ } }, "node_modules/listr2": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-10.2.1.tgz", - "integrity": "sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-11.0.0.tgz", + "integrity": "sha512-8K88S0aSrcSXdJfiZtEy5BQMnR+TyjrCGLcgAvQs6ta0NEnIm0RJ72/Pv67Jvg07cfBhDbuN74V81lSSVYEFEw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "cli-truncate": "^5.2.0", - "eventemitter3": "^5.0.4", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", + "cli-truncate": "^6.1.1", + "log-update": "^8.0.0", "wrap-ansi": "^10.0.0" }, "engines": { @@ -6439,78 +6668,26 @@ } }, "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-8.0.0.tgz", + "integrity": "sha512-lddSgOt3bPASrylL54ZSpy8nBHns+vBVSoILlVOx+dei300pnLRN958rj/EdlVLKuWlSESU3qdnDZdAI7FXYGg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-escapes": "^7.0.0", + "ansi-escapes": "^7.3.0", "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "slice-ansi": "^9.0.0", + "string-width": "^8.2.0", + "strip-ansi": "^7.2.0", + "wrap-ansi": "^10.0.0" }, "engines": { - "node": ">=18" + "node": ">=22" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/lru-cache": { "version": "11.5.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", @@ -6538,9 +6715,9 @@ "license": "ISC" }, "node_modules/marked": { - "version": "18.0.9", - "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.9.tgz", - "integrity": "sha512-/Sa4qiiHZxf0/FQdBBowr9q4r10krCwMvpK48FUBdXdUXScDxiQGR9zCPrFgRVR5LU3iySOiIjy09ZQvADir1w==", + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.11.tgz", + "integrity": "sha512-HnslJfsZkRPBDJRHvVtAaWlZHEpSu7u8LgQuJCELjRKuWR+hpq4A7sLq3p8HaI9ypVoXDXxV34CsQJEe1+J5Aw==", "license": "MIT", "peer": true, "bin": { @@ -6550,6 +6727,16 @@ "node": ">= 20" } }, + "node_modules/marked-katex-extension": { + "version": "5.1.12", + "resolved": "https://registry.npmjs.org/marked-katex-extension/-/marked-katex-extension-5.1.12.tgz", + "integrity": "sha512-DgfH0CFrOuVwVEXNJ+rTtYOtZZECpHhA0bu7xBiACAJI4geeaCZfDq+hiJ1yJx780fDh2HWHlr+NySxuc2DD1w==", + "license": "MIT", + "peerDependencies": { + "katex": ">=0.16 <0.19", + "marked": ">=4 <19" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -6731,19 +6918,40 @@ "license": "MIT" }, "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", "dev": true, "license": "MIT", + "dependencies": { + "content-type": "^2.1.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/negotiator/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ngx-markdown": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-22.0.0.tgz", - "integrity": "sha512-ES4uWsxtJuiFK8PPG4I9hIlQOTj0+HWm6BqEjgMb+FOzmZJopAuba4uAGSZyBEqFnwlqv+hYKhS8ddzTqveedw==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-22.0.2.tgz", + "integrity": "sha512-1vIlacu+UOYI3HbHk/uAa+hStk3Jc9iKy8pW0KYqkrRAJh4jSaaMYbcXAzKWzJgi6ncauqobd0Cxj6iOGwkrtQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -6753,7 +6961,7 @@ "@angular/core": "^22.0.0", "@angular/platform-browser": "^22.0.0", "clipboard": "^2.0.11", - "emoji-toolkit": ">= 8.0.0 < 11.0.0", + "emoji-toolkit": ">= 8.0.0 < 12.0.0", "katex": "^0.16.0", "marked": "^17.0.0 || ^18.0.0", "marked-katex-extension": "^5.0.0", @@ -6808,9 +7016,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.53", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", - "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", "license": "MIT", "engines": { "node": ">=18" @@ -7416,13 +7624,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, "node_modules/rolldown": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.0.tgz", @@ -7700,9 +7901,9 @@ } }, "node_modules/slice-ansi": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", - "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-9.0.0.tgz", + "integrity": "sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==", "dev": true, "license": "MIT", "dependencies": { @@ -7710,7 +7911,7 @@ "is-fullwidth-code-point": "^5.1.0" }, "engines": { - "node": ">=20" + "node": ">=22" }, "funding": { "url": "https://github.com/chalk/slice-ansi?sponsor=1" @@ -7974,16 +8175,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.67.0.tgz", - "integrity": "sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==", + "version": "8.68.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.68.0.tgz", + "integrity": "sha512-MHy0Y0ynqeEbx/S45+i/bBssdy3X6KNBfmJAP35GrgtNxu2TQ5K5xsFDhAnmsq1jvpdoZOPG1LGtJo0HWqYCrQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.67.0", - "@typescript-eslint/parser": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/utils": "8.67.0" + "@typescript-eslint/eslint-plugin": "8.68.0", + "@typescript-eslint/parser": "8.68.0", + "@typescript-eslint/typescript-estree": "8.68.0", + "@typescript-eslint/utils": "8.68.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8015,9 +8216,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz", - "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", "funding": [ { "type": "opencollective", @@ -8549,15 +8750,14 @@ } }, "node_modules/wrap-ansi": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.0.tgz", - "integrity": "sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.1.tgz", + "integrity": "sha512-M0N4xzyzosiIok3svYlEo1sdLZts/8FPgYH/GPC3wvlmPoRvnoManGMrE54waYj3tISA8w6lsdesfVv67qSr8Q==", "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.2.3", - "string-width": "^8.2.0", - "strip-ansi": "^7.1.2" + "string-width": "^8.2.0" }, "engines": { "node": ">=20" diff --git a/package.json b/package.json index f414ab0f..e970dd91 100644 --- a/package.json +++ b/package.json @@ -24,45 +24,47 @@ "license": "MIT", "private": true, "dependencies": { - "@angular/animations": "~22.1.2", - "@angular/cdk": "~22.1.2", - "@angular/common": "~22.1.2", - "@angular/compiler": "~22.1.2", - "@angular/core": "~22.1.2", - "@angular/forms": "~22.1.2", - "@angular/material": "~22.1.2", - "@angular/platform-browser": "~22.1.2", - "@angular/platform-browser-dynamic": "~22.1.2", - "@angular/router": "~22.1.2", - "@angular/service-worker": "~22.1.2", - "@angular/localize": "~22.1.2", + "@angular/animations": "~22.1.4", + "@angular/cdk": "~22.1.4", + "@angular/common": "~22.1.4", + "@angular/compiler": "~22.1.4", + "@angular/core": "~22.1.4", + "@angular/forms": "~22.1.4", + "@angular/localize": "~22.1.4", + "@angular/material": "~22.1.4", + "@angular/platform-browser": "~22.1.4", + "@angular/platform-browser-dynamic": "~22.1.4", + "@angular/router": "~22.1.4", + "@angular/service-worker": "~22.1.4", "@apollo/client": "^4.2.12", "@ng-bootstrap/ng-bootstrap": "~21.0.0", "@types/grecaptcha": "^3.0.9", "apollo-angular": "^14.2.0", "chart.js": "^4.5.1", "core-js": "^3.50.0", - "es-toolkit": "^1.50.0", + "es-toolkit": "^1.52.0", "graphql": "^17.0.2", "graphql-tag": "^2.12.7", - "ngx-markdown": "^22.0.0", + "katex": "^0.18.4", + "marked-katex-extension": "^5.1.12", + "ngx-markdown": "^22.0.2", "rxjs": "^7.8.2", "tslib": "^2.8.1" }, "devDependencies": { - "@angular/build": "^22.1.4", - "@angular/cli": "^22.1.4", - "@angular/compiler-cli": "~22.1.2", - "@types/node": "^26.2.0", + "@angular/build": "^22.1.6", + "@angular/cli": "^22.1.6", + "@angular/compiler-cli": "~22.1.4", + "@types/node": "^26.4.0", "@types/react": "^19.2.18", "angular-eslint": "22.1.0", - "eslint": "^10.8.1", + "eslint": "^10.9.1", "ts-node": "^10.9.2", "typescript": "^6.0.3", - "typescript-eslint": "8.67.0" + "typescript-eslint": "8.68.0" }, "repository": { "type": "git", "url": "https://github.com/switcherapi/switcher-management" } -} \ No newline at end of file +} diff --git a/src/app/documentation-module/docs/lib-go.component.ts b/src/app/documentation-module/docs/lib-go.component.ts new file mode 100644 index 00000000..4d7d9eda --- /dev/null +++ b/src/app/documentation-module/docs/lib-go.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; +import { MarkdownInjector } from './markdown-injector.component'; +import { MarkdownComponent } from 'ngx-markdown'; + +@Component({ + selector: 'app-libgo', + template: ` +
+

Go Library

+ Switcher API +
+ + `, + styleUrls: ['../documentation/documentation.component.css'], + imports: [MarkdownComponent] +}) +export class LibGoComponent extends MarkdownInjector { + + constructor() { + super(); + this.init('documentation/libgo.md'); + } + +} diff --git a/src/app/documentation-module/docs/lib-python.component.ts b/src/app/documentation-module/docs/lib-python.component.ts new file mode 100644 index 00000000..588af9b8 --- /dev/null +++ b/src/app/documentation-module/docs/lib-python.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; +import { MarkdownInjector } from './markdown-injector.component'; +import { MarkdownComponent } from 'ngx-markdown'; + +@Component({ + selector: 'app-libpython', + template: ` +
+

Python Library

+ Switcher API +
+ + `, + styleUrls: ['../documentation/documentation.component.css'], + imports: [MarkdownComponent] +}) +export class LibPythonComponent extends MarkdownInjector { + + constructor() { + super(); + this.init('documentation/libpython.md'); + } + +} diff --git a/src/app/documentation-module/documentation.routing.ts b/src/app/documentation-module/documentation.routing.ts index cdf752c4..c4ebd9b6 100644 --- a/src/app/documentation-module/documentation.routing.ts +++ b/src/app/documentation-module/documentation.routing.ts @@ -11,6 +11,8 @@ import { MetricsComponent } from './docs/metrics.component'; import { StrategiesComponent } from './docs/strategies.component'; import { LibJavaComponent } from './docs/lib-java.component'; import { LibJavaScriptComponent } from './docs/lib-javascript.component'; +import { LibPythonComponent } from './docs/lib-python.component'; +import { LibGoComponent } from './docs/lib-go.component'; import { SearchComponent } from './search/search.component'; import { ApiComponent } from './docs/api.component'; import { ShortcutsComponent } from './docs/shortcuts.component'; @@ -33,6 +35,8 @@ const routes: Routes = [ { path: 'strategies', component: StrategiesComponent }, { path: 'libjava', component: LibJavaComponent }, { path: 'libjavascript', component: LibJavaScriptComponent }, + { path: 'libpython', component: LibPythonComponent }, + { path: 'libgo', component: LibGoComponent }, { path: 'api', component: ApiComponent }, { path: 'shortcuts', component: ShortcutsComponent }, { path: 'relay', component: RelayComponent }, diff --git a/src/app/documentation-module/documentation/documentation.component.html b/src/app/documentation-module/documentation/documentation.component.html index 1bbb7182..a51b36e1 100644 --- a/src/app/documentation-module/documentation/documentation.component.html +++ b/src/app/documentation-module/documentation/documentation.component.html @@ -29,6 +29,8 @@
  • diff --git a/src/assets/documentation/libgo.md b/src/assets/documentation/libgo.md new file mode 100644 index 00000000..6815a4e4 --- /dev/null +++ b/src/assets/documentation/libgo.md @@ -0,0 +1,506 @@ +*** + +
    +Switcher Client SDK
    +A Go SDK for Switcher API +
    + +*** + +### About + +The **Switcher Client SDK for Go** provides integration with [Switcher-API](https://github.com/switcherapi/switcher-api), enabling feature flag management in Go applications. + +#### Key Features + +- **Clean & Maintainable**: Simple package-level access with an instance-based core +- **Local Mode**: Offline execution using snapshot files from your Switcher-API domain +- **Silent Mode**: Hybrid configuration with automatic fallback for connectivity issues +- **Built-in Testing Helpers**: Test-oriented mocking support adapted for Go +- **Zero Latency**: Local snapshot execution for high-performance scenarios +- **Monitoring**: Execution logging, caching, and error notification hooks + +### Quick Start + +Get up and running in just a few lines of code: + +```go +package main + +import ( + "fmt" + + "github.com/switcherapi/switcher-client-go" +) + +func main() { + client.BuildContext(client.Context{ + Domain: "My Domain", + URL: "https://api.switcherapi.com", + APIKey: "[YOUR_API_KEY]", + Component: "MyApp", + Environment: "default", + }) + + switcher := client.GetSwitcher("FEATURE_TOGGLE") + enabled, err := switcher.IsOn() + if err != nil { + panic(err) + } + + if enabled { + fmt.Println("Feature is enabled!") + } +} +``` + +### Installation + +Install the Switcher Client SDK: + +```bash +go get github.com/switcherapi/switcher-client-go +``` + +#### System Requirements +- **Go**: 1.25+ (targeting 1.25.x and 1.26.x) +- **Operating System**: Cross-platform (Windows, macOS, Linux) + +### Configuration + +#### Basic Setup + +Initialize the Switcher Client with your domain configuration: + +```go +package main + +import ( + "github.com/switcherapi/switcher-client-go" +) + +func main() { + client.BuildContext(client.Context{ + Domain: "My Domain", // Your Switcher domain name + URL: "https://api.switcherapi.com", // Switcher-API endpoint (optional) + APIKey: "[YOUR_API_KEY]", // Your component's API key (optional) + Component: "MyApp", // Your application name (optional) + Environment: "default", // Environment ("default" for production) + }) + + switcher := client.GetSwitcher("FEATURE_LOGIN_V2") + _ = switcher +} +``` + +##### Configuration Parameters + +| Parameter | Required | Description | Default | +|-----------|----------|-------------|---------| +| `Domain` | ✅ | Your Switcher domain name | - | +| `URL` | | Switcher-API endpoint | `https://api.switcherapi.com` | +| `APIKey` | | API key for your component | - | +| `Component` | | Your application identifier | - | +| `Environment` | | Target environment | `default` | + +#### Advanced Configuration + +Enable additional features like local mode, silent mode, and transport options: + +```go +package main + +import ( + "time" + + "github.com/switcherapi/switcher-client-go" +) + +func main() { + client.BuildContext(client.Context{ + Domain: "My Domain", + URL: "https://api.switcherapi.com", + APIKey: "[YOUR_API_KEY]", + Component: "MyApp", + Environment: "default", + Options: client.ContextOptions{ + Local: true, + Logger: true, + Freeze: true, + SnapshotLocation: "./snapshot/", + SnapshotAutoUpdateInterval: 30 * time.Second, + SilentMode: 5 * time.Minute, + RestrictRelay: true, + ThrottleMaxWorkers: 2, + Remote: client.RemoteOptions{ + CertPath: "./certs/client.pem", + AutoRenewToken: true, + ConnectTimeout: 300 * time.Millisecond, + Timeout: 5 * time.Second, + }, + }, + }) + + switcher := client.GetSwitcher("FEATURE_LOGIN_V2") + _ = switcher +} +``` + +##### Advanced Options Reference + +| Option | Type | Description | Default | +|--------|------|-------------|---------| +| `Local` | `bool` | Use local snapshot files only (zero latency) | `false` | +| `Logger` | `bool` | Enable logging/caching of feature flag evaluations | `false` | +| `Freeze` | `bool` | Enable cache-immutability responses for consistent results | `false` | +| `SnapshotLocation` | `string` | Directory for snapshot files | `""` | +| `SnapshotAutoUpdateInterval` | `time.Duration` | Auto-update interval for snapshots | `0` | +| `SilentMode` | `time.Duration` | Silent mode retry time before returning to remote mode | `0` | +| `RestrictRelay` | `bool` | Enable relay restrictions in local mode | `true` | +| `ThrottleMaxWorkers` | `int` | Max workers for throttling refresh tasks | runtime-defined | +| `Remote` | `RemoteOptions` | Remote transport settings | `RemoteOptions{}` | + +`RemoteOptions` fields: + +| Option | Type | Description | Default | +|--------|------|-------------|---------| +| `CertPath` | `string` | Path to a PEM bundle containing the client certificate and private key for secure API connections | `""` | +| `AutoRenewToken` | `bool` | Proactively renew the auth token in the background shortly before it expires, avoiding synchronous re-auth latency on foreground requests | `false` | +| `ConnectTimeout` | `time.Duration` | Max time to establish a remote connection before failing fast | `300ms` | +| `Timeout` | `time.Duration` | Max time for remote request/response and idle connection reuse | `5s` | + +**Note:** lower remote connect timeouts help silent mode fall back faster when the upstream is unavailable. + +### Usage Examples + +#### Basic Feature Flag Checking + +The simplest way to check if a feature is enabled: + +```go +switcher := client.GetSwitcher("FEATURE_LOGIN_V2") + +enabled, err := switcher.IsOn() +if err != nil { + panic(err) +} + +if enabled { + newLogin() +} else { + legacyLogin() +} +``` + +#### Detailed Response Information + +Get comprehensive information about the feature flag evaluation: + +```go +response, err := client.GetSwitcher("FEATURE_LOGIN_V2").IsOnWithDetails() +if err != nil { + panic(err) +} + +fmt.Printf("Feature enabled: %v\n", response.Result) +fmt.Printf("Reason: %s\n", response.Reason) +fmt.Printf("Metadata: %#v\n", response.Metadata) +``` + +#### Must-variant with default response + +Simpified response handling with default values when errors occur: + +```go +feature := client.GetSwitcher("FEATURE_LOGIN_V2") + +enabled = feature.IsOnOrDefault(false) +response := feature.IsOnWithDetailsOrDefault(ResultDetail{ + Result: false, + Reason: "default", +}) +``` + +Use the async error channel for non-blocking error handling: + +```go +client.SubscribeNotifyError(func(err error) { + fmt.Printf("Switcher Error: %v\n", err) +}) +``` + +#### Strategy-Based Feature Flags + +##### Method 1: Prepare and Execute + +Load validation data separately, useful for complex applications: + +```go +prepared := client.GetSwitcher(""). + Check(client.StrategyValue, "USER_123") + +if err := prepared.Prepare("USER_FEATURE"); err != nil { + panic(err) +} + +enabled, err := prepared.IsOn() +if err != nil { + panic(err) +} + +if enabled { + enableUserFeature() +} +``` + +##### Method 2: All-in-One Execution + +Chain multiple validation strategies for comprehensive feature control: + +```go +isEnabled, err := client.GetSwitcher("PREMIUM_FEATURES"). + CheckValue("premium_user"). + CheckNumeric("42"). + CheckDate("2026-06-24"). + CheckTime("09:30"). + CheckPayload(`{"tier":"premium","account":{"region":"us"}}`). + CheckNetwork("192.168.1.0/24"). + CheckRegex(`premium_[a-z]+`). + Throttle(time.Second). + IsOn() + +if err != nil { + panic(err) +} + +if isEnabled { + showPremiumDashboard() +} +``` + +Supported convenience helpers map to the same generic entry-point: `CheckValue`, `CheckNumeric`, +`CheckDate`, `CheckTime`, `CheckPayload`, `CheckNetwork`, and `CheckRegex`. + +#### Error Handling + +Subscribe to error notifications for robust error management: + +```go +client.SubscribeNotifyError(func(err error) { + fmt.Printf("Switcher Error: %v\n", err) +}) +``` + +### Advanced Features + +#### Throttling + +Throttle implements Stale-While-Revalidate behavior for feature flag evaluations, returning cached results while refreshing in the background. This is ideal for high-traffic scenarios where you want to minimize latency and avoid overwhelming the API with requests. + +```go +_, err := client.GetSwitcher("FEATURE01").Throttle(time.Second).IsOn() +if err != nil { + panic(err) +} +``` + +Throttle reuses the latest cached execution for the same switcher key and inputs. It records that cached execution even when `ContextOptions.Logger` is `false`, and when `Freeze` is enabled the cached value stays in place until `client.ClearLogger()` is called. + +```go +switcher := client.GetSwitcher("FEATURE01").Throttle(time.Second) +_, _ = switcher.IsOnWithDetails() + +logged := client.GetExecution(switcher) +fmt.Println(logged.Response.Metadata["cached"]) +``` + +#### Hybrid Mode + +When `ContextOptions.Local` is enabled, evaluations are resolved against the local snapshot by default. Chain `.Remote()` on a specific Switcher to force that call to always use the remote API instead, without disabling Local Mode for the rest of the client. + +```go +_, err := client.GetSwitcher("FEATURE01").Remote().IsOn() +if err != nil { + panic(err) +} +``` + +`Remote()` requires `ContextOptions.Local` to be `true` — otherwise `Validate`/`IsOn`/`IsOnWithDetails` return an error. Pass `Remote(false)` to explicitly clear the override and fall back to the client's normal `Local`/Silent Mode behavior. + +#### Circuit Breaker: Silent Mode + +This feature allows you to specify how long the client SDK should attempt to restore connectivity in case of remote API failures. + +When the API is unavailable, the SDK will automatically operate in silent mode, evaluating Switchers using a local snapshot. It is important to note that any Switcher Key configured must be able to resolve without external dependencies (e.g., Switcher Relay). + +Make sure to configure the scheduled snapshot auto-update to keep the local snapshot up to date with the remote API. + +Here is an example - in-memory snapshot with auto-update every 30 seconds: + +```go +client.BuildContext(client.Context{ + Domain: "My Domain", + URL: "https://api.switcherapi.com", + APIKey: "[YOUR_API_KEY]", + Component: "MyApp", + Options: client.ContextOptions{ + SnapshotAutoUpdateInterval: 30 * time.Second, + SilentMode: 5 * time.Minute, + }, +}) +``` + +### Snapshot Management + +#### Loading Snapshots + +Load snapshots from the API or local files: + +```go +version, err := client.LoadSnapshot(nil) +if err != nil { + panic(err) +} + +fmt.Println(version) +``` + +```go +version, err := client.LoadSnapshot(&client.LoadSnapshotOptions{ + FetchRemote: true, +}) +if err != nil { + panic(err) +} + +fmt.Println(version) +``` + +```go +_, err := client.LoadSnapshot(&client.LoadSnapshotOptions{ + WatchSnapshot: true, +}) +if err != nil { + panic(err) +} +``` + +#### Version Management + +Check your current snapshot version: + +```go +updated, err := client.CheckSnapshot() +if err != nil { + panic(err) +} + +fmt.Printf("Snapshot updated: %v\n", updated) +fmt.Printf("Current snapshot version: %d\n", client.SnapshotVersion()) +``` + +#### Automated Updates + +Schedule automatic snapshot updates for zero-latency local mode: + +```go +client.ScheduleSnapshotAutoUpdate(time.Minute, func(err error, updated bool) { + if err != nil { + fmt.Printf("snapshot update error: %v\n", err) + return + } + + if updated { + fmt.Printf("Snapshot updated to version: %d\n", client.SnapshotVersion()) + } +}) +``` + +#### Snapshot Monitoring + +```go +err := client.WatchSnapshot(client.WatchSnapshotCallback{ + Success: func() { + fmt.Println("snapshot loaded successfully") + }, + Reject: func(err error) { + fmt.Printf("error loading snapshot: %v\n", err) + }, +}) +if err != nil { + panic(err) +} +``` + +### Testing & Development + +#### Built-in Mocking + +The Go SDK provides client-scoped test mocking adapted to Go idioms and safer state ownership. + +```go +sdk := client.NewClient(ctx) +sdk.Assume("FEATURE01").True() + +enabled, err := sdk.GetSwitcher("FEATURE01").IsOn() +assert.NoError(t, err) +assert.True(t, enabled) +``` + +```go +sdk.Assume("FEATURE01").True().Cleanup(t) +``` + +```go +sdk.Assume("FEATURE01").True(). + When(client.StrategyValue, []string{"guest", "admin"}). + When(client.StrategyNetwork, "10.0.0.3") + +enabled, err := sdk.GetSwitcher("FEATURE01"). + CheckValue("guest"). + CheckNetwork("10.0.0.3"). + IsOn() +assert.NoError(t, err) +assert.True(t, enabled) +``` + +```go +sdk.Forget("FEATURE01") +``` + +```go +sdk.Assume("FEATURE01").False().WithMetadata(map[string]any{ + "message": "Feature is disabled", +}) + +response, err := sdk.GetSwitcher("FEATURE01").IsOnWithDetails() +assert.NoError(t, err) +assert.Equal(t, false, response.Result) +assert.Equal(t, "Feature is disabled", response.Metadata["message"]) +``` + +Mocks stay scoped to the `sdk` instance. Remove them explicitly with `sdk.Forget("FEATURE01")` or register automatic test cleanup with `.Cleanup(t)`. + +#### Configuration Validation + +Validate your feature flag configuration before deployment: + +```go +err := client.CheckSwitchers([]string{ + "FEATURE_LOGIN", + "FEATURE_DASHBOARD", + "FEATURE_PAYMENTS", +}) +if err != nil { + fmt.Printf("Configuration error: %v\n", err) +} +``` + +This validation helps prevent deployment issues by ensuring all required feature flags are properly set up in your Switcher domain. + +* * * + +*Did you find an error? Please, open an issue* + + + diff --git a/src/assets/documentation/libjava.md b/src/assets/documentation/libjava.md index efbb5474..cd0f9ae3 100644 --- a/src/assets/documentation/libjava.md +++ b/src/assets/documentation/libjava.md @@ -7,7 +7,7 @@ A Java SDK for Switcher API *** -### Overview +### About The Switcher Client SDK is a comprehensive Java library for integrating with [Switcher API](https://github.com/switcherapi/switcher-api), a cloud-based feature flag management system. This SDK enables you to control feature toggles, A/B testing, and configuration management in your Java applications. @@ -85,14 +85,14 @@ This approach automatically loads configuration from a properties file, ideal fo Create `src/main/resources/switcherapi.properties`: ```properties -### Required Configuration +# Required Configuration switcher.context=com.example.MyAppFeatures switcher.url=https://api.switcherapi.com -switcher.apikey=YOUR_API_KEY -switcher.component=my-application -switcher.domain=MY_DOMAIN +switcher.apikey=[API_KEY] +switcher.component=[COMPONENT_NAME] +switcher.domain=[DOMAIN_NAME} -### Optional Configuration +# Optional Configuration switcher.environment=default switcher.timeout=3000 switcher.poolsize=2 @@ -110,6 +110,7 @@ switcher.poolsize=2 | `switcher.environment` | ❌ | default | Environment name (dev, staging, default) | | `switcher.local` | ❌ | false | Enable local-only mode | | `switcher.check` | ❌ | false | Validate switcher keys on startup | +| `switcher.auth.autorefresh` | ❌ | false | Automatically refresh API token before expiration | | `switcher.relay.restrict` | ❌ | true | Defines if client will trigger local snapshot relay verification | | `switcher.snapshot.location` | ❌ | - | Directory for snapshot files | | `switcher.snapshot.auto` | ❌ | false | Auto-load snapshots on startup | @@ -152,10 +153,10 @@ public class MyAppFeatures extends SwitcherContextBase { static { configure(ContextBuilder.builder() .context(MyAppFeatures.class.getName()) - .apiKey("YOUR_API_KEY") + .apiKey("[API_KEY]") .url("https://api.switcherapi.com") - .domain("MY_DOMAIN") - .component("my-application") + .domain("[DOMAIN_NAME]") + .component("[COMPONENT_NAME]") .environment("default")); initializeClient(); @@ -301,9 +302,9 @@ Default mode that communicates directly with Switcher API. ```java MyAppFeatures.configure(ContextBuilder.builder() .url("https://api.switcherapi.com") - .apiKey("YOUR_API_KEY") - .domain("MY_DOMAIN") - .component("my-app")); + .apiKey("[API_KEY]") + .domain("[DOMAIN_NAME]") + .component("[COMPONENT_NAME]")); MyAppFeatures.initializeClient(); ``` @@ -346,12 +347,12 @@ switcher.forceRemote().isItOn(); ```java MyAppFeatures.configure(ContextBuilder.builder() .url("https://api.switcherapi.com") - .apiKey("YOUR_API_KEY") - .domain("MY_DOMAIN") + .apiKey("[API_KEY]") + .domain("[DOMAIN_NAME]") .local(true) .snapshotAutoLoad(true) .snapshotAutoUpdateInterval("30s") // Check for updates every 30 seconds - .component("my-app")); + .component("[COMPONENT_NAME]")); MyAppFeatures.initializeClient(); @@ -369,6 +370,28 @@ MyAppFeatures.scheduleSnapshotAutoUpdate("30s", new SnapshotCallback() { }); ``` +#### Circuit Breaker: Silent Mode + +This feature allows you to specify how long the client SDK should attempt to restore connectivity in case of remote API failures. + +When the API is unavailable, the SDK will automatically operate in silent mode, evaluating Switchers using a local snapshot. It is important to note that any Switcher Key configured must be able to resolve without external dependencies (e.g., Switcher Relay). + +Make sure to configure the scheduled snapshot auto-update to keep the local snapshot up to date with the remote API. + +Here is an example - in-memory snapshot with auto-update every 30 seconds: + +```java +MyAppFeatures.configure(ContextBuilder.builder() + .context(MyAppFeatures.class.getName()) + .apiKey("[API_KEY]") + .url("https://api.switcherapi.com") + .domain("[DOMAIN_NAME") + .component("[COMPONENT_NAME]") + .silentMode("5m") + .snapshotAutoUpdateInterval("30s") +); +``` + ### Advanced Features #### Real-time Snapshot Management @@ -413,23 +436,6 @@ MyAppFeatures.configure(ContextBuilder.builder() #### Performance Optimization -##### Silent Mode (Resilience) - -Automatically fall back to cached results when API is unavailable: - -```java -MyAppFeatures.configure(ContextBuilder.builder() - .silentMode("30s") // Retry API calls every 30 seconds when failing - .url("https://api.switcherapi.com") - // ... other config -); -``` - -**Time formats supported:** -- `5s` - 5 seconds -- `2m` - 2 minutes -- `1h` - 1 hour - ##### Connection Pooling ```java @@ -471,7 +477,7 @@ void testWithConditions() { } ``` -##### JUnit 5 Integration +##### JUnit Jupiter Integration ###### Single Switcher Test diff --git a/src/assets/documentation/libjavascript.md b/src/assets/documentation/libjavascript.md index 062e6764..a20aea99 100644 --- a/src/assets/documentation/libjavascript.md +++ b/src/assets/documentation/libjavascript.md @@ -7,7 +7,7 @@ A JavaScript SDK for Switcher API *** -### Overview +### About **Switcher Client JS** is a feature-rich SDK for integrating [Switcher API](https://github.com/switcherapi/switcher-api) into your JS-based applications (Web, Node.js, Bun, Cloudflare Workers). It provides robust feature flag management with enterprise-grade capabilities. @@ -42,10 +42,10 @@ Client.buildContext({ }); // 2. Get a switcher instance -const switcher = Client.getSwitcher(); +const switcher = Client.getSwitcher('FEATURE01'); // 3. Check if a feature is enabled -const isFeatureEnabled = await switcher.isItOn('FEATURE01'); +const isFeatureEnabled = await switcher.isItOn(); console.log('Feature enabled:', isFeatureEnabled); ``` @@ -101,12 +101,13 @@ Client.buildContext({ freeze: false, // Prevent background updates logger: true, // Enable request logging snapshotLocation: './snapshot/', // Snapshot files directory - snapshotAutoUpdateInterval: 300, // Auto-update interval (seconds) + snapshotAutoUpdateInterval: 30, // Auto-update interval (seconds) snapshotWatcher: true, // Monitor snapshot changes silentMode: '5m', // Fallback timeout restrictRelay: true, // Relay restrictions in local mode regexSafe: true, // Prevent reDOS attacks - certPath: './certs/ca.pem' // SSL certificate path + certPath: './certs/ca.pem', // SSL certificate path + autoRefreshToken: true // Automatically refresh API token }); ``` @@ -126,6 +127,7 @@ Client.buildContext({ | `regexMaxBlackList` | number | Max cached regex failures | | `regexMaxTimeLimit` | number | Regex timeout in milliseconds | | `certPath` | string | Path to SSL certificate file | +| `autoRefreshToken` | boolean | Automatically refresh API token | > **Security Note:** `regexSafe` prevents ReDoS attacks. Keep this enabled in production. @@ -138,19 +140,22 @@ Client.buildContext({ Multiple ways to check if a feature is enabled: ```js +// Non-persisted switcher instance const switcher = Client.getSwitcher(); - -// Synchronous (local mode only) -const isEnabled = switcher.isItOn('FEATURE01'); // Returns: boolean -const isEnabledBool = switcher.isItOnBool('FEATURE01'); // Returns: boolean -const detailResult = switcher.detail().isItOn('FEATURE01'); // Returns: { result, reason, metadata } -const detailDirect = switcher.isItOnDetail('FEATURE01'); // Returns: { result, reason, metadata } - -// Asynchronous (remote/hybrid mode) -const isEnabledAsync = await switcher.isItOn('FEATURE01'); // Returns: Promise -const isEnabledBoolAsync = await switcher.isItOnBool('FEATURE01', true); // Returns: Promise -const detailResultAsync = await switcher.detail().isItOn('FEATURE01'); // Returns: Promise -const detailDirectAsync = await switcher.isItOnDetail('FEATURE01', true); // Returns: Promise +// Persisted switcher instance +const switcher = Client.getSwitcher('FEATURE01'); + +// 🚀 Synchronous (local mode only) +const isEnabled = switcher.isItOn(); // Returns: boolean +const isEnabledBool = switcher.isItOnBool(); // Returns: boolean +const detailResult = switcher.detail().isItOn(); // Returns: { result, reason, metadata } +const detailDirect = switcher.isItOnDetail(); // Returns: { result, reason, metadata } + +// 🌐 Asynchronous (remote/hybrid mode) +const isEnabledAsync = await switcher.isItOn(); // Returns: Promise +const isEnabledBoolAsync = await switcher.isItOnBool(true); // Returns: Promise +const detailResultAsync = await switcher.detail().isItOn(); // Returns: Promise +const detailDirectAsync = await switcher.isItOnDetail(true); // Returns: Promise ``` #### Strategy Validation @@ -173,10 +178,10 @@ Fast method that includes everything in a single call: ```js const result = await switcher - .defaultResult(true) // Fallback result if API is unavailable - .throttle(1000) // Cache result for 1 second - .checkValue('User 1') // User-based strategy - .checkNetwork('192.168.0.1') // Network-based strategy + .defaultResult(true) // 🛡️ Fallback result if API is unavailable + .throttle(1000) // ⚡ Cache result for 1 second + .checkValue('User 1') // 👤 User-based strategy + .checkNetwork('192.168.0.1') // 🌐 Network-based strategy .isItOn('FEATURE01'); ``` @@ -203,6 +208,15 @@ Client.subscribeNotifyError((error) => { }); ``` +##### Flush cached results from throttling + +When using throttling, you can clear cached results for a specific switcher: + +```js +// Clear cached results for a specific switcher +Client.getSwitcher('FEATURE01').flushExecutions(); +``` + #### Hybrid Mode Force specific switchers to resolve remotely while running in local mode. Ideal for features requiring remote validation (e.g., Relay Strategies): @@ -214,6 +228,25 @@ const switcher = Client.getSwitcher(); const result = await switcher.remote().isItOn('FEATURE01'); ``` +#### Circuit Breaker: Silent Mode + +This feature allows you to specify how long the client SDK should attempt to restore connectivity in case of remote API failures. + +When the API is unavailable, the SDK will automatically operate in silent mode, evaluating Switchers using a local snapshot. It is important to note that any Switcher Key configured must be able to resolve without external dependencies (e.g., Switcher Relay). + +Make sure to configure the scheduled snapshot auto-update to keep the local snapshot up to date with the remote API. + +Here is an example - in-memory snapshot with auto-update every 30 seconds: + +```js +Client.buildContext({ + url, apiKey, domain, component, environment +}, { + snapshotAutoUpdateInterval: 30, + silentMode: '5m', +}); +``` + --- ### Testing Features @@ -360,15 +393,15 @@ try { } ``` -> **Use Case:** Perfect for external processes that manage snapshot files independently. +> **💡 Use Case:** Perfect for external processes that manage snapshot files independently. #### Auto-Update Scheduler Run the SDK in local mode (zero latency) while keeping snapshots automatically updated: ```js -// Update every 3 seconds (3000 milliseconds) -Client.scheduleSnapshotAutoUpdate(3000, { +// Update every 3 seconds +Client.scheduleSnapshotAutoUpdate(3, { success: (updated) => console.log('Snapshot updated', updated), reject: (err: Error) => console.log(err) }); diff --git a/src/assets/documentation/libpython.md b/src/assets/documentation/libpython.md new file mode 100644 index 00000000..ab46de9e --- /dev/null +++ b/src/assets/documentation/libpython.md @@ -0,0 +1,453 @@ +*** + +
    +Switcher Client SDK
    +A Python SDK for Switcher API +
    + +*** + +### About + +The **Switcher Client SDK for Python** provides seamless integration with [Switcher-API](https://github.com/switcherapi/switcher-api), enabling powerful feature flag management in your Python applications. + +#### Key Features + +- **Clean & Maintainable**: Flexible and robust functions that keep your code organized +- **Local Mode**: Work offline using snapshot files from your Switcher-API Domain +- **Silent Mode**: Hybrid configuration with automatic fallback for connectivity issues +- **Built-in Mocking**: Manual and decorator-based test mocking with scoped mock isolation for concurrent execution +- **Zero Latency**: Local snapshot execution for high-performance scenarios +- **Secure**: Built-in protection against ReDoS attacks with regex safety features +- **Monitoring**: Comprehensive logging and error handling capabilities + +### Quick Start + +Get up and running in just a few lines of code: + +```python +from switcher_client import Client + +# Initialize the client +Client.build_context( + domain='My Domain', + url='https://api.switcherapi.com', + api_key='[YOUR_API_KEY]', + component='MyApp', + environment='default' +) + +# Use feature flags +switcher = Client.get_switcher() +if switcher.is_on('FEATURE_TOGGLE'): + print("Feature is enabled!") +``` + +### Installation + +Install the Switcher Client SDK: + +```bash +# Pip +pip install switcher-client +``` + +```bash +# Conda +conda install switcherapi::switcher-client +``` + +#### System Requirements +- **Python**: 3.9+ (supports 3.9, 3.10, 3.11, 3.12, 3.13, 3.14) +- **Operating System**: Cross-platform (Windows, macOS, Linux) + +### Configuration + +#### Basic Setup + +Initialize the Switcher Client with your domain configuration: + +```python +from switcher_client import Client + +Client.build_context( + domain='My Domain', # Your Switcher domain name + url='https://api.switcherapi.com', # Switcher-API endpoint (optional) + api_key='[YOUR_API_KEY]', # Your component's API key (optional) + component='MyApp', # Your application name (optional) + environment='default' # Environment ('default' for production) +) + +switcher = Client.get_switcher() +``` + +##### Configuration Parameters + +| Parameter | Required | Description | Default | +|-----------|----------|-------------|---------| +| `domain` | ✅ | Your Switcher domain name | - | +| `url` | | Switcher-API endpoint | `https://api.switcherapi.com` | +| `api_key` | | API key for your component | - | +| `component` | | Your application identifier | - | +| `environment` | | Target environment | `default` | + +#### Advanced Configuration + +Enable additional features like local mode, silent mode, and security options: + +```python +from switcher_client import Client, ContextOptions, RemoteOptions + +Client.build_context( + domain='My Domain', + url='https://api.switcherapi.com', + api_key='[YOUR_API_KEY]', + component='MyApp', + environment='default', + options=ContextOptions( + local=True, + logger=True, + freeze=True, + snapshot_location='./snapshot/', + snapshot_auto_update_interval=3, + silent_mode='5m', + restrict_relay=True, + throttle_max_workers=2, + regex_max_black_list=10, + regex_max_time_limit=100, + remote=RemoteOptions( + cert_path='./certs/ca.pem', + auto_renew_token=True, + connect_timeout=0.3, + read_timeout=5.0, + write_timeout=5.0, + pool_timeout=5.0, + max_keepalive_connections=20, + max_connections=100, + keepalive_expiry=30.0 + ) + ) +) + +switcher = Client.get_switcher() +``` + +##### Advanced Options Reference + +| Option | Type | Description | Default | +|--------|------|-------------|---------| +| `local` | `bool` | Use local snapshot files only (zero latency) | `False` | +| `logger` | `bool` | Enable logging/caching of feature flag evaluations | `False` | +| `freeze` | `bool` | Enable cache-immutability responses for consistent results | `False` | +| `snapshot_location` | `str` | Directory for snapshot files | `'./snapshot/'` | +| `snapshot_auto_update_interval` | `int` | Auto-update interval in seconds (0 = disabled) | `0` | +| `silent_mode` | `str` | Silent mode retry time (e.g., '5m' for 5 minutes) | `None` | +| `restrict_relay` | `bool` | Enable relay restrictions in local mode | `True` | +| `throttle_max_workers` | `int` | Max workers for throttling feature checks | `None` | +| `regex_max_black_list` | `int` | Max cached entries for failed regex | `100` | +| `regex_max_time_limit` | `int` | Regex execution time limit (ms) | `3000` | +| `remote` | `RemoteOptions` | Remote transport settings for certificate path, connect/read/write/pool timeouts | `RemoteOptions()` | + +`RemoteOptions` fields: + +| Option | Type | Description | Default | +|--------|------|-------------|---------| +| `cert_path` | `str` | Path to custom certificate for secure API connections | `None` | +| `auto_renew_token` | `bool` | Automatically renew the auth token in the background before it expires | `False` | +| `connect_timeout` | `float` | Max seconds to establish a remote connection before failing fast | `0.3` | +| `read_timeout` | `float` | Max seconds to wait for remote response data | `5.0` | +| `write_timeout` | `float` | Max seconds to send remote request data | `5.0` | +| `pool_timeout` | `float` | Max seconds to wait for a pooled HTTP connection | `5.0` | +| `max_keepalive_connections` | `int` | Max number of idle keep-alive connections to maintain | `20` | +| `max_connections` | `int` | Max number of concurrent connections allowed | `100` | +| `keepalive_expiry` | `float` | Max seconds a keep-alive connection can remain idle | `30.0` | + +`response.status_code` is only available when the upstream returns an HTTP response such as `503`. +When the upstream is unavailable, the client raises a transport error instead and silent mode now +uses the configured remote timeouts to fail fast and switch back to local evaluation. + +#### Security Features + +- **ReDoS Protection**: Built-in ReDoS attack prevention with regex safety features +- **Time Limits**: Configurable timeouts prevent long-running regex operations +- **Certificate Support**: Use custom certificates for secure API connections + +### Usage Examples + +#### Basic Feature Flag Checking + +The simplest way to check if a feature is enabled: + +```python +switcher = Client.get_switcher() + +# Simple boolean check +if switcher.is_on('FEATURE_LOGIN_V2'): + # Use new login system + new_login() +else: + # Use legacy login + legacy_login() +``` + +#### Detailed Response Information + +Get comprehensive information about the feature flag evaluation: + +```python +response = switcher.is_on_with_details('FEATURE_LOGIN_V2') + +print(f"Feature enabled: {response.result}") # True or False +print(f"Reason: {response.reason}") # Evaluation reason +print(f"Metadata: {response.metadata}") # Additional context +``` + +#### Strategy-Based Feature Flags + +##### Method 1: Prepare and Execute + +Load validation data separately, useful for complex applications: + +```python +# Prepare the validation context +switcher.check_value('USER_123').prepare('USER_FEATURE') + +# Execute when ready +if switcher.is_on(): + enable_user_feature() +``` + +##### Method 2: All-in-One Execution + +Chain multiple validation strategies for comprehensive feature control: + +```python +is_enabled = switcher \ + # VALUE strategy + .check_value('premium_user') \ + # NETWORK strategy + .check_network('192.168.1.0/24') \ + # Fallback value if API fails + .default_result(True) \ + # Cache result for 1 second + .throttle(1000) \ + .is_on('PREMIUM_FEATURES') + +if is_enabled: + show_premium_dashboard() +``` + +#### Error Handling + +Subscribe to error notifications for robust error management: + +```python +# Set up error handling +Client.subscribe_notify_error(lambda error: print(f"Switcher Error: {error}")) +``` + +### Advanced Features + +#### Throttling + +```python +# Zero-latency async execution +switcher.throttle(1000).is_on('FEATURE01') +``` + +#### Hybrid Mode + +```python +# Force remote resolution for specific features +switcher.remote().is_on('FEATURE01') +``` + +#### Circuit Breaker: Silent Mode + +This feature allows you to specify how long the client SDK should attempt to restore connectivity in case of remote API failures. + +When the API is unavailable, the SDK will automatically operate in silent mode, evaluating Switchers using a local snapshot. It is important to note that any Switcher Key configured must be able to resolve without external dependencies (e.g., Switcher Relay). + +Make sure to configure the scheduled snapshot auto-update to keep the local snapshot up to date with the remote API. + +Here is an example - in-memory snapshot with auto-update every 30 seconds: + +```python +Client.build_context( + domain='My Domain', + url='https://api.switcherapi.com', + api_key='[YOUR_API_KEY]', + component='MyApp', + options=ContextOptions( + snapshot_auto_update_interval=30, + silent_mode='5m', + ) +) +``` + +### Snapshot Management + +#### Loading Snapshots + +Load snapshots from the API or local files: + +```python +# Load snapshot from local file +Client.load_snapshot() +``` + +```python +# Load snapshot from API with fetch_remote option +Client.load_snapshot(LoadSnapshotOptions(fetch_remote=True)) +``` + +```python +# Load snapshot with watch option to update the client in real-time when file changes +Client.load_snapshot(LoadSnapshotOptions(watch_snapshot=True)) +``` + +#### Version Management + +Check your current snapshot version: + +```python +# Verify snapshot version +version_info = Client.check_snapshot() +print(f"Current snapshot version: {Client.snapshot_version()}") +``` + +#### Automated Updates + +Schedule automatic snapshot updates for zero-latency local mode: + +```python +Client.schedule_snapshot_auto_update( + interval=60, + callback=lambda error, updated: ( + print(f"Snapshot updated to version: {Client.snapshot_version()}") if updated else None + ) +) +``` + +#### Snapshot Monitoring + +```python +# Watch for snapshot file changes +Client.watch_snapshot(WatchSnapshotCallback( + success=lambda: print("✅ Snapshot loaded successfully"), + reject=lambda e: print(f"❌ Error loading snapshot: {e}") +)) +``` + +### Testing & Development + +#### Built-in Mocking + +The SDK includes powerful mocking capabilities for testing. Forced values are scoped to the current execution context, which adds a safe-net for concurrent test runs in the same process by reducing mock leakage between overlapping test executions while keeping the mocking API unchanged. + +```python +# Mock feature states for testing +Client.assume('FEATURE01').true() +assert switcher.is_on('FEATURE01') == True +``` + +```python +# Conditional mocking based on input criteria +Client.assume('FEATURE01').true() \ + # value can be either 'guest' or 'admin' + .when(StrategiesType.VALUE.value, ['guest', 'admin']) \ + .when(StrategiesType.NETWORK.value, '10.0.0.3') + +assert switcher \ + .check_value('guest') \ + .check_network('10.0.0.3') \ + .is_on('FEATURE01') == True +``` + +```python +# Reset to normal behavior +Client.forget('FEATURE01') +``` + +```python +# Mock with metadata +Client.assume('FEATURE01').false().with_metadata({ + 'message': 'Feature is disabled' +}) +response = switcher.is_on_with_details('FEATURE01') +assert response.result == False +assert response.metadata['message'] == 'Feature is disabled' +``` + +#### Decorator-Based Testing + +Decorator-based tests can use the same fluent mocking rules while automatically cleaning up mocked flags after the test finishes: + +```python +@switcher_test(assume_test('FEATURE01').true()) +def test_feature_flag(): + assert switcher.is_on('FEATURE01') == True +``` + +```python +@switcher_test( + assume_test('FEATURE01').true() + .when(StrategiesType.VALUE.value, 'guest') + .with_metadata({'message': 'Decorated mock'}) +) +def test_feature_flag_with_rules(): + response = switcher.check_value('guest').is_on_with_details('FEATURE01') + assert response.result == True + assert response.metadata['message'] == 'Decorated mock' +``` + +```python +@switcher_test( + assume_test('FEATURE01').true(), + assume_test('FEATURE02').false() +) +def test_multiple_flags(): + assert switcher.is_on('FEATURE01') == True + assert switcher.is_on('FEATURE02') == False +``` + +Decorator behavior: + +- `assume_test('FEATURE')` builds a single mocked flag assumption +- `switcher_test(...)` accepts one or more assumptions +- fluent mock rules are preserved, including `.true()`, `.false()`, `.when(...)`, and `.with_metadata(...)` +- mocked flags are always cleaned up with `Client.forget(...)` after the test finishes, even when the test raises an error +- both regular `def` tests and `async def` tests are supported + +This decorator API is intended as a test convenience and mock-isolation improvement. It improves the safety of mocked flags in concurrent execution within the same process, but should not be treated as full SDK-wide parallel execution support. + +#### Test Mode Configuration + +Convenient functionality to prevent subprocess locking of snapshot files during testing. + +```python +# Enable test mode to prevent snapshot file locking when running tests +Client.test_mode() +``` + +#### Configuration Validation + +Validate your feature flag configuration before deployment: + +```python +# Verify that all required switchers are configured +try: + Client.check_switchers(['FEATURE_LOGIN', 'FEATURE_DASHBOARD', 'FEATURE_PAYMENTS']) + print("✅ All switchers are properly configured") +except Exception as e: + print(f"❌ Configuration error: {e}") +``` + +This validation helps prevent deployment issues by ensuring all required feature flags are properly set up in your Switcher domain. + +* * * + +*Did you find an error? Please, open an issue* + + + diff --git a/src/libs/ng2-charts/src/lib/ng-charts.provider.ts b/src/libs/ng2-charts/src/lib/ng-charts.provider.ts index a59f9b32..cdecdaeb 100644 --- a/src/libs/ng2-charts/src/lib/ng-charts.provider.ts +++ b/src/libs/ng2-charts/src/lib/ng-charts.provider.ts @@ -38,6 +38,9 @@ export function withDefaultRegisterables( export function provideCharts( ...configurations: readonly NgChartsConfiguration[] ) { - const config: NgChartsConfiguration = configurations.reduce((acc, conf) => merge(acc, conf), {}); + const config: NgChartsConfiguration = configurations.reduce( + (acc, conf) => merge(acc, conf) as NgChartsConfiguration, + {} as NgChartsConfiguration, + ); return { provide: NG_CHARTS_CONFIGURATION, useValue: config }; } diff --git a/tsconfig.json b/tsconfig.json index 0f93bfc5..d92e3c03 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,7 @@ "typeRoots": ["node_modules/@types"], "lib": [ "ES2022", + "esnext.disposable", "dom" ] },