From 9ad80f865f1ac8d52222a73052e574fd86915c0d Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Wed, 21 May 2025 15:31:25 +0100 Subject: [PATCH 01/15] examples/annotations: add base application --- examples/package.json | 2 + .../javascript/.gitignore | 36 + .../javascript/README.md | 47 ++ .../javascript/index.html | 19 + .../javascript/package.json | 11 + .../javascript/src/script.ts | 17 + .../javascript/src/styles.css | 108 +++ .../javascript/tailwind.config.ts | 9 + .../javascript/tsconfig.json | 8 + .../javascript/vite-env.d.ts | 8 + .../javascript/vite.config.ts | 7 + examples/yarn.lock | 788 +++++++++--------- 12 files changed, 660 insertions(+), 400 deletions(-) create mode 100644 examples/pub-sub-message-annotations/javascript/.gitignore create mode 100644 examples/pub-sub-message-annotations/javascript/README.md create mode 100644 examples/pub-sub-message-annotations/javascript/index.html create mode 100644 examples/pub-sub-message-annotations/javascript/package.json create mode 100644 examples/pub-sub-message-annotations/javascript/src/script.ts create mode 100644 examples/pub-sub-message-annotations/javascript/src/styles.css create mode 100644 examples/pub-sub-message-annotations/javascript/tailwind.config.ts create mode 100644 examples/pub-sub-message-annotations/javascript/tsconfig.json create mode 100644 examples/pub-sub-message-annotations/javascript/vite-env.d.ts create mode 100644 examples/pub-sub-message-annotations/javascript/vite.config.ts diff --git a/examples/package.json b/examples/package.json index 77101c4a2e..f6474fef3e 100644 --- a/examples/package.json +++ b/examples/package.json @@ -43,6 +43,7 @@ "pub-sub-presence/javascript", "pub-sub-rewind/react", "pub-sub-rewind/javascript", + "pub-sub-message-annotations/javascript", "spaces-avatar-stack/react", "spaces-avatar-stack/javascript", "spaces-component-locking/react", @@ -90,6 +91,7 @@ "pub-sub-presence-react": "yarn workspace pub-sub-presence-react dev", "pub-sub-rewind-javascript": "yarn workspace pub-sub-rewind-javascript dev", "pub-sub-rewind-react": "yarn workspace pub-sub-rewind-react dev", + "pub-sub-message-annotations-javascript": "yarn workspace pub-sub-message-annotations-javascript dev", "spaces-avatar-stack-javascript": "yarn workspace spaces-avatar-stack-javascript dev", "spaces-avatar-stack-react": "yarn workspace spaces-avatar-stack-react dev", "spaces-component-locking-javascript": "yarn workspace spaces-component-locking-javascript dev", diff --git a/examples/pub-sub-message-annotations/javascript/.gitignore b/examples/pub-sub-message-annotations/javascript/.gitignore new file mode 100644 index 0000000000..fd3dbb571a --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/examples/pub-sub-message-annotations/javascript/README.md b/examples/pub-sub-message-annotations/javascript/README.md new file mode 100644 index 0000000000..88d41842c3 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/README.md @@ -0,0 +1,47 @@ +# Using message annotations with Pub/Sub + +TODO + +## Resources + +TODO + +## Getting started + +1. Clone the [Ably docs](https://github.com/ably/docs) repository where this example can be found: + + ```sh + git clone git@github.com:ably/docs.git + ``` + +2. Change directory: + + ```sh + cd /examples/ + ``` + +3. Rename the environment file: + + ```sh + mv .env.example .env.local + ``` + +4. In `.env.local` update the value of `VITE_ABLY_KEY` to be your Ably API key. + +5. Install dependencies: + + ```sh + yarn install + ``` + +6. Run the server: + + ```sh + yarn run pub-sub-message-annotations-javascript + ``` + +7. Try it out by opening two tabs to [http://localhost:5173/](http://localhost:5173/) with your browser to see the result. + +## Open in CodeSandbox + +In CodeSandbox, rename the `.env.example` file to `.env.local` and update the value of your `VITE_ABLY_KEY` variable to use your Ably API key. diff --git a/examples/pub-sub-message-annotations/javascript/index.html b/examples/pub-sub-message-annotations/javascript/index.html new file mode 100644 index 0000000000..ab773209b4 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/index.html @@ -0,0 +1,19 @@ + + + + + + + + + Pub/Sub message annotations + + + +
+ Hello world +
+ + + + \ No newline at end of file diff --git a/examples/pub-sub-message-annotations/javascript/package.json b/examples/pub-sub-message-annotations/javascript/package.json new file mode 100644 index 0000000000..66b618545f --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/package.json @@ -0,0 +1,11 @@ +{ + "name": "pub-sub-message-annotations-javascript", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + } +} diff --git a/examples/pub-sub-message-annotations/javascript/src/script.ts b/examples/pub-sub-message-annotations/javascript/src/script.ts new file mode 100644 index 0000000000..0bd322cdc3 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/script.ts @@ -0,0 +1,17 @@ +import * as Ably from 'ably'; +import { nanoid } from 'nanoid'; +import './styles.css'; + +const client = new Ably.Realtime({ + clientId: nanoid(), + key: import.meta.env.VITE_ABLY_KEY as string, +}); + +const urlParams = new URLSearchParams(window.location.search); + +const channelName = urlParams.get('name') || 'pub-sub-message-annotations'; +const channel = client.channels.get(channelName); + +channel.subscribe((message) => { + console.log(message); +}); diff --git a/examples/pub-sub-message-annotations/javascript/src/styles.css b/examples/pub-sub-message-annotations/javascript/src/styles.css new file mode 100644 index 0000000000..562e9ac776 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/styles.css @@ -0,0 +1,108 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 20 14.3% 4.1%; + --card: 0 0% 100%; + --card-foreground: 20 14.3% 4.1%; + --popover: 0 0% 100%; + --popover-foreground: 20 14.3% 4.1%; + --primary: 220 13% 33%; + --primary-foreground: 60 9.1% 97.8%; + --secondary: 209 100% 43%; + --secondary-foreground: 60 9.1% 97.8%; + --muted: 60 4.8% 95.9%; + --muted-foreground: 25 5.3% 44.7%; + --accent: 60 4.8% 95.9%; + --accent-foreground: 24 9.8% 10%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 60 9.1% 97.8%; + --border: 20 5.9% 90%; + --input: 20 5.9% 90%; + --ring: 24.6 95% 53.1%; + --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + } + + .dark { + --background: 20 14.3% 4.1%; + --foreground: 60 9.1% 97.8%; + --card: 20 14.3% 4.1%; + --card-foreground: 60 9.1% 97.8%; + --popover: 20 14.3% 4.1%; + --popover-foreground: 60 9.1% 97.8%; + --primary: 220 13% 33%; + --primary-foreground: 60 9.1% 97.8%; + --secondary: 209 100% 43%; + --secondary-foreground: 60 9.1% 97.8%; + --muted: 12 6.5% 15.1%; + --muted-foreground: 24 5.4% 63.9%; + --accent: 12 6.5% 15.1%; + --accent-foreground: 60 9.1% 97.8%; + --destructive: 0 72.2% 50.6%; + --destructive-foreground: 60 9.1% 97.8%; + --border: 12 6.5% 15.1%; + --input: 12 6.5% 15.1%; + --ring: 20.5 90.2% 48.2%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } +} + +.container { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + position: relative; + background-color: #f4f8fb; + height: 100vh; +} + +.inner { + width: 100%; + max-width: 320px; + padding: 1rem 0.5rem; +} + +/* InputCell */ +.input-cell-container { + width: 100%; + display: flex; + flex-direction: column; + margin-bottom: 1rem; +} + +.input-cell-container:last-child { + display: none; +} + +@media (min-height: 400px) { + .input-cell-container:last-child { + display: flex; + } +} + +input { + padding: 0.5rem; + width: 100%; + height: 2.5rem; + font-size: 0.875rem; + border-radius: 0.375rem; + outline: none; + transition: all 0.2s ease-in-out; +} + +.uk-text-primary { + color: hsl(var(--primary)); +} diff --git a/examples/pub-sub-message-annotations/javascript/tailwind.config.ts b/examples/pub-sub-message-annotations/javascript/tailwind.config.ts new file mode 100644 index 0000000000..1c86e1c371 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/tailwind.config.ts @@ -0,0 +1,9 @@ +import baseConfig from '../../tailwind.config'; +import type { Config } from 'tailwindcss'; + +const config: Config = { + ...baseConfig, + content: ['./src/**/*.{js,ts,tsx}', './index.html'], +}; + +export default config; diff --git a/examples/pub-sub-message-annotations/javascript/tsconfig.json b/examples/pub-sub-message-annotations/javascript/tsconfig.json new file mode 100644 index 0000000000..91c07db93c --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["./src/**/*.ts", "./src/**/*.tsx"], + "exclude": ["../../node_modules", "../../dist", "../../lib"], + "compilerOptions": { + "types": ["vite/client"] + } +} diff --git a/examples/pub-sub-message-annotations/javascript/vite-env.d.ts b/examples/pub-sub-message-annotations/javascript/vite-env.d.ts new file mode 100644 index 0000000000..449e61aa75 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/vite-env.d.ts @@ -0,0 +1,8 @@ +interface ImportMetaEnv { + readonly VITE_ABLY_KEY: string; + // Add other environment variables here if needed +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/examples/pub-sub-message-annotations/javascript/vite.config.ts b/examples/pub-sub-message-annotations/javascript/vite.config.ts new file mode 100644 index 0000000000..3b1cf13b4f --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite'; +import baseConfig from '../../vite.config'; + +export default defineConfig({ + ...baseConfig, + envDir: '../../', +}); diff --git a/examples/yarn.lock b/examples/yarn.lock index fba2f5486a..7772151a8d 100644 --- a/examples/yarn.lock +++ b/examples/yarn.lock @@ -23,26 +23,26 @@ "@ably/msgpack-js@^0.4.0": version "0.4.0" - resolved "https://registry.yarnpkg.com/@ably/msgpack-js/-/msgpack-js-0.4.0.tgz#aaaf5d8dffacf7aa253effd8c3488aa09130e6a2" + resolved "https://registry.npmjs.org/@ably/msgpack-js/-/msgpack-js-0.4.0.tgz" integrity sha512-IPt/BoiQwCWubqoNik1aw/6M/DleMdrxJOUpSja6xmMRbT2p1TA8oqKWgfZabqzrq8emRNeSl/+4XABPNnW5pQ== dependencies: bops "^1.0.1" "@ably/spaces@^0.4.0": version "0.4.0" - resolved "https://registry.yarnpkg.com/@ably/spaces/-/spaces-0.4.0.tgz#766d748d79f3de3cd82939431daea99479150bbf" + resolved "https://registry.npmjs.org/@ably/spaces/-/spaces-0.4.0.tgz" integrity sha512-yehNgkv9DOHUBR1c46/5Q4BhkF3TJkKb00kLDhZFWTVJpFSW0Mkw0PUgHLkzAg9Bt9LJPcA0mgZq3mFeLQCrIg== dependencies: nanoid "^3.3.7" "@alloc/quick-lru@^5.2.0": version "5.2.0" - resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== "@ampproject/remapping@^2.2.0": version "2.3.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: "@jridgewell/gen-mapping" "^0.3.5" @@ -50,7 +50,7 @@ "@babel/code-frame@^7.26.2": version "7.26.2" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz" integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== dependencies: "@babel/helper-validator-identifier" "^7.25.9" @@ -59,12 +59,12 @@ "@babel/compat-data@^7.26.8": version "7.26.8" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.8.tgz#821c1d35641c355284d4a870b8a4a7b0c141e367" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz" integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ== "@babel/core@^7.20.12": version "7.26.10" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.10.tgz#5c876f83c8c4dcb233ee4b670c0606f2ac3000f9" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz" integrity sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ== dependencies: "@ampproject/remapping" "^2.2.0" @@ -85,7 +85,7 @@ "@babel/generator@^7.26.10", "@babel/generator@^7.27.0": version "7.27.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.27.0.tgz#764382b5392e5b9aff93cadb190d0745866cbc2c" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz" integrity sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw== dependencies: "@babel/parser" "^7.27.0" @@ -96,7 +96,7 @@ "@babel/helper-compilation-targets@^7.26.5": version "7.27.0" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz#de0c753b1cd1d9ab55d473c5a5cf7170f0a81880" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz" integrity sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA== dependencies: "@babel/compat-data" "^7.26.8" @@ -107,7 +107,7 @@ "@babel/helper-module-imports@^7.25.9": version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz" integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== dependencies: "@babel/traverse" "^7.25.9" @@ -115,7 +115,7 @@ "@babel/helper-module-transforms@^7.26.0": version "7.26.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz" integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== dependencies: "@babel/helper-module-imports" "^7.25.9" @@ -124,27 +124,27 @@ "@babel/helper-plugin-utils@^7.25.9": version "7.26.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz" integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== "@babel/helper-string-parser@^7.25.9": version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz" integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== "@babel/helper-validator-identifier@^7.25.9": version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz" integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== "@babel/helper-validator-option@^7.25.9": version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz" integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== "@babel/helpers@^7.26.10": version "7.27.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.0.tgz#53d156098defa8243eab0f32fa17589075a1b808" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz" integrity sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg== dependencies: "@babel/template" "^7.27.0" @@ -152,28 +152,28 @@ "@babel/parser@^7.26.10", "@babel/parser@^7.27.0": version "7.27.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.0.tgz#3d7d6ee268e41d2600091cbd4e145ffee85a44ec" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz" integrity sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg== dependencies: "@babel/types" "^7.27.0" "@babel/plugin-transform-react-jsx-self@^7.18.6": version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz#c0b6cae9c1b73967f7f9eb2fca9536ba2fad2858" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz" integrity sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg== dependencies: "@babel/helper-plugin-utils" "^7.25.9" "@babel/plugin-transform-react-jsx-source@^7.19.6": version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz#4c6b8daa520b5f155b5fb55547d7c9fa91417503" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz" integrity sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg== dependencies: "@babel/helper-plugin-utils" "^7.25.9" "@babel/template@^7.26.9", "@babel/template@^7.27.0": version "7.27.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.0.tgz#b253e5406cc1df1c57dcd18f11760c2dbf40c0b4" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz" integrity sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA== dependencies: "@babel/code-frame" "^7.26.2" @@ -182,7 +182,7 @@ "@babel/traverse@^7.25.9", "@babel/traverse@^7.26.10": version "7.27.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.27.0.tgz#11d7e644779e166c0442f9a07274d02cd91d4a70" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz" integrity sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA== dependencies: "@babel/code-frame" "^7.26.2" @@ -195,7 +195,7 @@ "@babel/types@^7.25.9", "@babel/types@^7.26.10", "@babel/types@^7.27.0": version "7.27.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.27.0.tgz#ef9acb6b06c3173f6632d993ecb6d4ae470b4559" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz" integrity sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg== dependencies: "@babel/helper-string-parser" "^7.25.9" @@ -278,7 +278,7 @@ "@esbuild/linux-x64@0.18.20": version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz" integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== "@esbuild/netbsd-x64@0.18.20": @@ -313,19 +313,19 @@ "@eslint-community/eslint-utils@^4.2.0": version "4.5.1" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz#b0fc7e06d0c94f801537fd4237edc2706d3b8e4c" + resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz" integrity sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w== dependencies: eslint-visitor-keys "^3.4.3" "@eslint-community/regexpp@^4.6.1": version "4.12.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz" integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== "@eslint/eslintrc@^2.1.4": version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz" integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" @@ -340,12 +340,12 @@ "@eslint/js@8.57.1": version "8.57.1" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== "@humanwhocodes/config-array@^0.13.0": version "0.13.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz" integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== dependencies: "@humanwhocodes/object-schema" "^2.0.3" @@ -354,17 +354,17 @@ "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== "@humanwhocodes/object-schema@^2.0.3": version "2.0.3" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@isaacs/cliui@^8.0.2": version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== dependencies: string-width "^5.1.2" @@ -376,7 +376,7 @@ "@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": version "0.3.8" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz" integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== dependencies: "@jridgewell/set-array" "^1.2.1" @@ -385,22 +385,22 @@ "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/set-array@^1.2.1": version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14": version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== dependencies: "@jridgewell/resolve-uri" "^3.1.0" @@ -408,7 +408,7 @@ "@nodelib/fs.scandir@2.1.5": version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: "@nodelib/fs.stat" "2.0.5" @@ -416,12 +416,12 @@ "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: "@nodelib/fs.scandir" "2.1.5" @@ -429,39 +429,39 @@ "@pkgjs/parseargs@^0.11.0": version "0.11.0" - resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@remix-run/router@1.23.0": version "1.23.0" - resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.23.0.tgz#35390d0e7779626c026b11376da6789eb8389242" + resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz" integrity sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA== "@rollup/rollup-darwin-arm64@^4.18": - version "4.39.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.39.0.tgz#830d07794d6a407c12b484b8cf71affd4d3800a6" - integrity sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q== + version "4.41.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz#45d9d71d941117c98e7a5e77f60f0bc682d27e82" + integrity sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw== "@rollup/rollup-linux-x64-gnu@^4.18": version "4.39.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.39.0.tgz#00825b3458094d5c27cb4ed66e88bfe9f1e65f90" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.39.0.tgz" integrity sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA== "@sindresorhus/is@^4.0.0": version "4.6.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== "@szmarczak/http-timer@^4.0.5": version "4.0.6" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz" integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== dependencies: defer-to-connect "^2.0.0" "@tailwindcss/node@4.1.3": version "4.1.3" - resolved "https://registry.yarnpkg.com/@tailwindcss/node/-/node-4.1.3.tgz#f290886582ce8eb1978853d07ca4da45f2d43fdb" + resolved "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.3.tgz" integrity sha512-H/6r6IPFJkCfBJZ2dKZiPJ7Ueb2wbL592+9bQEl2r73qbX6yGnmQVIfiUvDRB2YI0a3PWDrzUwkvQx1XW1bNkA== dependencies: enhanced-resolve "^5.18.1" @@ -506,12 +506,12 @@ "@tailwindcss/oxide-linux-x64-gnu@4.1.3": version "4.1.3" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.3.tgz#66477a71fbaad552be882e8b7a56bb7519b47838" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.3.tgz" integrity sha512-LMdTmGe/NPtGOaOfV2HuO7w07jI3cflPrVq5CXl+2O93DCewADK0uW1ORNAcfu2YxDUS035eY2W38TxrsqngxA== "@tailwindcss/oxide-linux-x64-musl@4.1.3": version "4.1.3" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.3.tgz#403145ce43361e7d63886c878fdb09cd868920da" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.3.tgz" integrity sha512-aalNWwIi54bbFEizwl1/XpmdDrOaCjRFQRgtbv9slWjmNPuJJTIKPHf5/XXDARc9CneW9FkSTqTbyvNecYAEGw== "@tailwindcss/oxide-win32-arm64-msvc@4.1.3": @@ -526,7 +526,7 @@ "@tailwindcss/oxide@4.1.3": version "4.1.3" - resolved "https://registry.yarnpkg.com/@tailwindcss/oxide/-/oxide-4.1.3.tgz#d01162137fcefe7d4c2a34500b9ed5c142388352" + resolved "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.3.tgz" integrity sha512-t16lpHCU7LBxDe/8dCj9ntyNpXaSTAgxWm1u2XQP5NiIu4KGSyrDJJRlK9hJ4U9yJxx0UKCVI67MJWFNll5mOQ== optionalDependencies: "@tailwindcss/oxide-android-arm64" "4.1.3" @@ -543,7 +543,7 @@ "@tailwindcss/postcss@^4.0.14": version "4.1.3" - resolved "https://registry.yarnpkg.com/@tailwindcss/postcss/-/postcss-4.1.3.tgz#82bf8b90c134f89f70d8d0293b5b14f234918faf" + resolved "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.3.tgz" integrity sha512-6s5nJODm98F++QT49qn8xJKHQRamhYHfMi3X7/ltxiSQ9dyRsaFSfFkfaMsanWzf+TMYQtbk8mt5f6cCVXJwfg== dependencies: "@alloc/quick-lru" "^5.2.0" @@ -554,7 +554,7 @@ "@types/body-parser@*": version "1.19.5" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz" integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== dependencies: "@types/connect" "*" @@ -562,7 +562,7 @@ "@types/cacheable-request@^6.0.1": version "6.0.3" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + resolved "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz" integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== dependencies: "@types/http-cache-semantics" "*" @@ -572,14 +572,14 @@ "@types/connect@*": version "3.4.38" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== dependencies: "@types/node" "*" "@types/express-serve-static-core@^5.0.0": version "5.0.6" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz#41fec4ea20e9c7b22f024ab88a95c6bb288f51b8" + resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz" integrity sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA== dependencies: "@types/node" "*" @@ -589,7 +589,7 @@ "@types/express@^5.0.0": version "5.0.1" - resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.1.tgz#138d741c6e5db8cc273bec5285cd6e9d0779fc9f" + resolved "https://registry.npmjs.org/@types/express/-/express-5.0.1.tgz" integrity sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ== dependencies: "@types/body-parser" "*" @@ -598,63 +598,56 @@ "@types/http-cache-semantics@*": version "4.0.4" - resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" + resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz" integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== "@types/http-errors@*": version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== "@types/keyv@^3.1.4": version "3.1.4" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + resolved "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz" integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== dependencies: "@types/node" "*" "@types/mime@^1": version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz" integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== -"@types/node@*": - version "22.14.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.14.0.tgz#d3bfa3936fef0dbacd79ea3eb17d521c628bb47e" - integrity sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA== - dependencies: - undici-types "~6.21.0" - -"@types/node@^20": +"@types/node@*", "@types/node@^20": version "20.17.30" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.30.tgz#1d93f656d3b869dbef7b796568ac457606ba58d0" + resolved "https://registry.npmjs.org/@types/node/-/node-20.17.30.tgz" integrity sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg== dependencies: undici-types "~6.19.2" "@types/prop-types@*": version "15.7.14" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.14.tgz#1433419d73b2a7ebfc6918dcefd2ec0d5cd698f2" + resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz" integrity sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ== "@types/qs@*": version "6.9.18" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.18.tgz#877292caa91f7c1b213032b34626505b746624c2" + resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz" integrity sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA== "@types/range-parser@*": version "1.2.7" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz" integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== "@types/react-dom@^18": version "18.3.6" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.6.tgz#fa59a5e9a33499a792af6c1130f55921ef49d268" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.6.tgz" integrity sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw== "@types/react@^18": version "18.3.20" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.20.tgz#b0dccda9d2f1bc24d2a04b1d0cb5d0b9a3576ad3" + resolved "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz" integrity sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg== dependencies: "@types/prop-types" "*" @@ -662,14 +655,14 @@ "@types/responselike@^1.0.0": version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" + resolved "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz" integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw== dependencies: "@types/node" "*" "@types/send@*": version "0.17.4" - resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz" integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== dependencies: "@types/mime" "^1" @@ -677,7 +670,7 @@ "@types/serve-static@*": version "1.15.7" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz" integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: "@types/http-errors" "*" @@ -686,22 +679,22 @@ "@types/uikit@^3.7.0": version "3.14.5" - resolved "https://registry.yarnpkg.com/@types/uikit/-/uikit-3.14.5.tgz#a9e250fa71968c3e145bfda7c99f6d9680db2d3e" + resolved "https://registry.npmjs.org/@types/uikit/-/uikit-3.14.5.tgz" integrity sha512-3Q1CRzoAVLm+XNCP/2P5DbLuX98fkNLYxGQ1qUdV6cdzDTBbyVeH+est0LTZPtro9FUwXTNu8WfxfwLymFbZvQ== "@types/uuid@^8.3.4": version "8.3.4" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== "@ungap/structured-clone@^1.2.0": version "1.3.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz" integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== "@vitejs/plugin-react@^3.0.0": version "3.1.0" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-3.1.0.tgz#d1091f535eab8b83d6e74034d01e27d73c773240" + resolved "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-3.1.0.tgz" integrity sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g== dependencies: "@babel/core" "^7.20.12" @@ -712,7 +705,7 @@ ably@^2.9.0: version "2.9.0" - resolved "https://registry.yarnpkg.com/ably/-/ably-2.9.0.tgz#e6e34d72f22082b6242ed23f1d649fc44eb82e1f" + resolved "https://registry.npmjs.org/ably/-/ably-2.9.0.tgz" integrity sha512-ddaurgvYHGmVVZkd5U2xJgLrbVdtAIw1RunfuZroE/ZTsmK2+vUnAZ7aKhR20cwOFP3QyLFYs6IfvwaijnIPlA== dependencies: "@ably/msgpack-js" "^0.4.0" @@ -724,7 +717,7 @@ ably@^2.9.0: accepts@~1.3.8: version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: mime-types "~2.1.34" @@ -732,17 +725,17 @@ accepts@~1.3.8: acorn-jsx@^5.3.2: version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn@^8.9.0: version "8.14.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz" integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== ajv@^6.12.4: version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" @@ -752,34 +745,34 @@ ajv@^6.12.4: ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: version "6.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz" integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" ansi-styles@^6.1.0: version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== any-promise@^1.0.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== anymatch@~3.1.2: version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" @@ -787,29 +780,29 @@ anymatch@~3.1.2: arg@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" + resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== argparse@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== async-mutex@^0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.5.0.tgz#353c69a0b9e75250971a64ac203b0ebfddd75482" + resolved "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz" integrity sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA== dependencies: tslib "^2.4.0" autoprefixer@^10.4.21: version "10.4.21" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.21.tgz#77189468e7a8ad1d9a37fbc08efc9f480cf0a95d" + resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz" integrity sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ== dependencies: browserslist "^4.24.4" @@ -821,22 +814,22 @@ autoprefixer@^10.4.21: balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-js@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.0.2.tgz#474211c95e6cf2a547db461e4f6778b51d08fa65" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.0.2.tgz" integrity sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg== binary-extensions@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== body-parser@1.20.3: version "1.20.3" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz" integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" @@ -854,7 +847,7 @@ body-parser@1.20.3: bops@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/bops/-/bops-1.0.1.tgz#502aaf00ee119db1dbae088e3df4bea2e241dbcc" + resolved "https://registry.npmjs.org/bops/-/bops-1.0.1.tgz" integrity sha512-qCMBuZKP36tELrrgXpAfM+gHzqa0nLsWZ+L37ncsb8txYlnAoxOPpVp+g7fK0sGkMXfA0wl8uQkESqw3v4HNag== dependencies: base64-js "1.0.2" @@ -862,7 +855,7 @@ bops@^1.0.1: brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -870,21 +863,21 @@ brace-expansion@^1.1.7: brace-expansion@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" braces@^3.0.3, braces@~3.0.2: version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: fill-range "^7.1.1" browserslist@^4.24.0, browserslist@^4.24.4: version "4.24.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz" integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== dependencies: caniuse-lite "^1.0.30001688" @@ -894,17 +887,17 @@ browserslist@^4.24.0, browserslist@^4.24.4: bytes@3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== cacheable-lookup@^5.0.3: version "5.0.4" - resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz" integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== cacheable-request@^7.0.2: version "7.0.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz" integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== dependencies: clone-response "^1.0.2" @@ -917,7 +910,7 @@ cacheable-request@^7.0.2: call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz" integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== dependencies: es-errors "^1.3.0" @@ -925,7 +918,7 @@ call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: call-bound@^1.0.2: version "1.0.4" - resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + resolved "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz" integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== dependencies: call-bind-apply-helpers "^1.0.2" @@ -933,22 +926,22 @@ call-bound@^1.0.2: callsites@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== camelcase-css@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz" integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== caniuse-lite@^1.0.30001688, caniuse-lite@^1.0.30001702: version "1.0.30001713" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001713.tgz#6b33a8857e6c7dcb41a0caa2dd0f0489c823a52d" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001713.tgz" integrity sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q== chalk@^4.0.0: version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -956,7 +949,7 @@ chalk@^4.0.0: chokidar@^3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" @@ -971,7 +964,7 @@ chokidar@^3.6.0: clone-response@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" + resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz" integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== dependencies: mimic-response "^1.0.0" @@ -983,56 +976,56 @@ clsx@^2.1.1: color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== commander@^4.0.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== content-disposition@0.5.4: version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== dependencies: safe-buffer "5.2.1" content-type@~1.0.4, content-type@~1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== convert-source-map@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== cookie@0.7.1: version "0.7.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz" integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== cors@^2.8.5: version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== dependencies: object-assign "^4" @@ -1040,7 +1033,7 @@ cors@^2.8.5: cross-spawn@^7.0.2, cross-spawn@^7.0.6: version "7.0.6" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" @@ -1049,90 +1042,90 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.6: cssesc@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== csstype@^3.0.2: version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== debug@2.6.9: version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" debug@^4.1.0, debug@^4.3.1, debug@^4.3.2: version "4.4.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== dependencies: ms "^2.1.3" decompress-response@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz" integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== dependencies: mimic-response "^3.1.0" deep-is@^0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== defer-to-connect@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== depd@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== dequal@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + resolved "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== destroy@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== detect-libc@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz" integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== didyoumean@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz" integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== dlv@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + resolved "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz" integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== doctrine@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== dependencies: esutils "^2.0.2" dotenv@^16.4.5: version "16.4.7" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz" integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ== dunder-proto@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== dependencies: call-bind-apply-helpers "^1.0.1" @@ -1141,49 +1134,49 @@ dunder-proto@^1.0.1: eastasianwidth@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== ee-first@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.5.73: version "1.5.135" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.135.tgz#6d835020fa0c7f02f30d7608c2f3c0a764236699" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.135.tgz" integrity sha512-8gXUdEmvb+WCaYUhA0Svr08uSeRjM2w3x5uHOc1QbaEVzJXB8rgm5eptieXzyKoVEtinLvW6MtTcurA65PeS1Q== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== emoji-regex@^9.2.2: version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== encodeurl@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== encodeurl@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== end-of-stream@^1.1.0: version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" enhanced-resolve@^5.18.1: version "5.18.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz#728ab082f8b7b6836de51f1637aab5d3b9568faf" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz" integrity sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg== dependencies: graceful-fs "^4.2.4" @@ -1191,24 +1184,24 @@ enhanced-resolve@^5.18.1: es-define-property@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== es-errors@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz" integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== dependencies: es-errors "^1.3.0" esbuild@^0.18.10: version "0.18.20" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz" integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== optionalDependencies: "@esbuild/android-arm" "0.18.20" @@ -1236,22 +1229,22 @@ esbuild@^0.18.10: escalade@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== escape-string-regexp@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== eslint-scope@^7.2.2: version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz" integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" @@ -1259,12 +1252,12 @@ eslint-scope@^7.2.2: eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8: version "8.57.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz" integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" @@ -1308,7 +1301,7 @@ eslint@^8: espree@^9.6.0, espree@^9.6.1: version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: acorn "^8.9.0" @@ -1317,36 +1310,36 @@ espree@^9.6.0, espree@^9.6.1: esquery@^1.4.2: version "1.6.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz" integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: estraverse "^5.2.0" estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== etag@~1.8.1: version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== express@^4.21.1: version "4.21.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" + resolved "https://registry.npmjs.org/express/-/express-4.21.2.tgz" integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== dependencies: accepts "~1.3.8" @@ -1383,12 +1376,12 @@ express@^4.21.1: fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-glob@^3.3.2: version "3.3.3" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz" integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== dependencies: "@nodelib/fs.stat" "^2.0.2" @@ -1399,43 +1392,43 @@ fast-glob@^3.3.2: fast-json-stable-stringify@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastestsmallesttextencoderdecoder@^1.0.22: version "1.0.22" - resolved "https://registry.yarnpkg.com/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz#59b47e7b965f45258629cc6c127bf783281c5e93" + resolved "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz" integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== fastq@^1.6.0: version "1.19.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz" integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== dependencies: reusify "^1.0.4" file-entry-cache@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: flat-cache "^3.0.4" fill-range@^7.1.1: version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" finalhandler@1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz" integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" @@ -1448,7 +1441,7 @@ finalhandler@1.3.1: find-up@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: locate-path "^6.0.0" @@ -1456,7 +1449,7 @@ find-up@^5.0.0: flat-cache@^3.0.4: version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: flatted "^3.2.9" @@ -1465,12 +1458,12 @@ flat-cache@^3.0.4: flatted@^3.2.9: version "3.3.3" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz" integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== foreground-child@^3.1.0: version "3.3.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz" integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== dependencies: cross-spawn "^7.0.6" @@ -1478,27 +1471,27 @@ foreground-child@^3.1.0: forwarded@0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fraction.js@^4.3.7: version "4.3.7" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" + resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz" integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== franken-ui@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/franken-ui/-/franken-ui-2.0.0.tgz#c6139119e7d8929a955324274651971fa8d8e551" + resolved "https://registry.npmjs.org/franken-ui/-/franken-ui-2.0.0.tgz" integrity sha512-MbmGsR2ADh5BonDTCUoUg4BAqcvObQPR4g45FWore6eiVtr0qofhelxyVuSEmcSKBqIeI/d6DpMEFdRu2e4Dow== fresh@0.5.2: version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@~2.3.2: @@ -1508,17 +1501,17 @@ fsevents@~2.3.2: function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== gensync@^1.0.0-beta.2: version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== dependencies: call-bind-apply-helpers "^1.0.2" @@ -1534,7 +1527,7 @@ get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: get-proto@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== dependencies: dunder-proto "^1.0.1" @@ -1542,28 +1535,28 @@ get-proto@^1.0.1: get-stream@^5.1.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz" integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== dependencies: pump "^3.0.0" glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" glob-parent@^6.0.2: version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== dependencies: is-glob "^4.0.3" glob@^10.3.10: version "10.4.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + resolved "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz" integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== dependencies: foreground-child "^3.1.0" @@ -1575,7 +1568,7 @@ glob@^10.3.10: glob@^7.1.3: version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -1587,24 +1580,24 @@ glob@^7.1.3: globals@^11.1.0: version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.19.0: version "13.24.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz" integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" gopd@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== got@^11.8.5: version "11.8.6" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + resolved "https://registry.npmjs.org/got/-/got-11.8.6.tgz" integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== dependencies: "@sindresorhus/is" "^4.0.0" @@ -1621,39 +1614,39 @@ got@^11.8.5: graceful-fs@^4.2.4: version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== graphemer@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-symbols@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== hasown@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" http-cache-semantics@^4.0.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== http-errors@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: depd "2.0.0" @@ -1664,7 +1657,7 @@ http-errors@2.0.0: http2-wrapper@^1.0.0-beta.5.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz" integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== dependencies: quick-lru "^5.1.1" @@ -1672,19 +1665,19 @@ http2-wrapper@^1.0.0-beta.5.2: iconv-lite@0.4.24: version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" ignore@^5.2.0: version "5.3.2" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== import-fresh@^3.2.1: version "3.3.1" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz" integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== dependencies: parent-module "^1.0.0" @@ -1692,12 +1685,12 @@ import-fresh@^3.2.1: imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" @@ -1705,63 +1698,63 @@ inflight@^1.0.4: inherits@2, inherits@2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== ipaddr.js@1.9.1: version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" is-core-module@^2.16.0: version "2.16.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz" integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== dependencies: hasown "^2.0.2" is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" is-number@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== is-path-inside@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== jackspeak@^3.1.2: version "3.4.3" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz" integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: "@isaacs/cliui" "^8.0.2" @@ -1770,61 +1763,61 @@ jackspeak@^3.1.2: jiti@^1.21.6: version "1.21.7" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.7.tgz#9dd81043424a3d28458b193d965f0d18a2300ba9" + resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz" integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A== jiti@^2.4.2: version "2.4.2" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + resolved "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz" integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" jsesc@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz" integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== json-buffer@3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== json5@^2.2.3: version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== keyv@^4.0.0, keyv@^4.5.3: version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" levn@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" @@ -1862,12 +1855,12 @@ lightningcss-linux-arm64-musl@1.29.2: lightningcss-linux-x64-gnu@1.29.2: version "1.29.2" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz#551ca07e565394928642edee92acc042e546cb78" + resolved "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz" integrity sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg== lightningcss-linux-x64-musl@1.29.2: version "1.29.2" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz#2fd164554340831bce50285b57101817850dd258" + resolved "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz" integrity sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w== lightningcss-win32-arm64-msvc@1.29.2: @@ -1882,7 +1875,7 @@ lightningcss-win32-x64-msvc@1.29.2: lightningcss@1.29.2: version "1.29.2" - resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.29.2.tgz#f5f0fd6e63292a232697e6fe709da5b47624def3" + resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz" integrity sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA== dependencies: detect-libc "^2.0.3" @@ -1900,95 +1893,95 @@ lightningcss@1.29.2: lilconfig@^3.0.0, lilconfig@^3.1.1, lilconfig@^3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" + resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz" integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== lines-and-columns@^1.1.6: version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== locate-path@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: p-locate "^5.0.0" lodash.clonedeep@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== lodash.debounce@^4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== lodash.merge@^4.6.2: version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== loose-envify@^1.1.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" lowercase-keys@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== lru-cache@^10.2.0: version "10.4.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lru-cache@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: yallist "^3.0.2" magic-string@^0.27.0: version "0.27.0" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz" integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA== dependencies: "@jridgewell/sourcemap-codec" "^1.4.13" math-intrinsics@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== media-typer@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== merge-descriptors@1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz" integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge2@^1.3.0: version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== methods@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== micromatch@^4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: braces "^3.0.3" @@ -1996,34 +1989,34 @@ micromatch@^4.0.8: mime-db@1.52.0: version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" mime@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mimic-response@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== mimic-response@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== minifaker@^1.34.1: version "1.34.1" - resolved "https://registry.yarnpkg.com/minifaker/-/minifaker-1.34.1.tgz#38d96a1aeebd99b950a9c420eb34d2638147ebf2" + resolved "https://registry.npmjs.org/minifaker/-/minifaker-1.34.1.tgz" integrity sha512-O9+c6GaUETgtKe65bJkpDTJxGcAALiUPqJtDv97dT3o0uP2HmyUVEguEGm6PLKuoSzZUmHqSTZ4cS7m8xKFEAg== dependencies: "@types/uuid" "^8.3.4" @@ -2032,36 +2025,36 @@ minifaker@^1.34.1: minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" minimatch@^9.0.4: version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" "minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== ms@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== ms@2.1.3, ms@^2.1.3: version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== mz@^2.7.0: version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz" integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== dependencies: any-promise "^1.0.0" @@ -2070,76 +2063,76 @@ mz@^2.7.0: nanoid@^3.2.0, nanoid@^3.3.7, nanoid@^3.3.8: version "3.3.11" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz" integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== nanoid@^5.0.7: version "5.1.5" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.1.5.tgz#f7597f9d9054eb4da9548cdd53ca70f1790e87de" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz" integrity sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw== natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== negotiator@0.6.3: version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== node-releases@^2.0.19: version "2.0.19" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz" integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== normalize-range@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== normalize-url@^6.0.1: version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== object-assign@^4, object-assign@^4.0.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-hash@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== object-inspect@^1.13.3: version "1.13.4" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz" integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== on-finished@2.4.1: version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== dependencies: ee-first "1.1.1" once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" optionator@^0.9.3: version "0.9.4" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz" integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" @@ -2151,63 +2144,63 @@ optionator@^0.9.3: p-cancelable@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz" integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== p-limit@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" p-locate@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: p-limit "^3.0.2" package-json-from-dist@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz" integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== parent-module@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" parseurl@~1.3.3: version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-scurry@^1.11.1: version "1.11.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz" integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: lru-cache "^10.2.0" @@ -2215,39 +2208,39 @@ path-scurry@^1.11.1: path-to-regexp@0.1.12: version "0.1.12" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz" integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== picocolors@^1.0.0, picocolors@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== pirates@^4.0.1: version "4.0.7" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz" integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== postcss-combine-duplicated-selectors@^10.0.3: version "10.0.3" - resolved "https://registry.yarnpkg.com/postcss-combine-duplicated-selectors/-/postcss-combine-duplicated-selectors-10.0.3.tgz#71e8b6783e99cd560cf08ba7b896ad0db318c11c" + resolved "https://registry.npmjs.org/postcss-combine-duplicated-selectors/-/postcss-combine-duplicated-selectors-10.0.3.tgz" integrity sha512-IP0BmwFloCskv7DV7xqvzDXqMHpwdczJa6ZvIW8abgHdcIHs9mCJX2ltFhu3EwA51ozp13DByng30+Ke+eIExA== dependencies: postcss-selector-parser "^6.0.4" postcss-import@^15.1.0: version "15.1.0" - resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" + resolved "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz" integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== dependencies: postcss-value-parser "^4.0.0" @@ -2256,14 +2249,14 @@ postcss-import@^15.1.0: postcss-js@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" + resolved "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz" integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== dependencies: camelcase-css "^2.0.1" postcss-load-config@^4.0.2: version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" + resolved "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz" integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== dependencies: lilconfig "^3.0.0" @@ -2271,21 +2264,21 @@ postcss-load-config@^4.0.2: postcss-load-config@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz#6fd7dcd8ae89badcf1b2d644489cbabf83aa8096" + resolved "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz" integrity sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g== dependencies: lilconfig "^3.1.1" postcss-nested@^6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131" + resolved "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz" integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ== dependencies: postcss-selector-parser "^6.1.1" postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.1.1, postcss-selector-parser@^6.1.2: version "6.1.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" + resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz" integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== dependencies: cssesc "^3.0.0" @@ -2293,12 +2286,12 @@ postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.1.1, postcss-selector postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== postcss@^8.4.27, postcss@^8.4.41, postcss@^8.4.47, postcss@^8.5.3: version "8.5.3" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz" integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== dependencies: nanoid "^3.3.8" @@ -2307,12 +2300,12 @@ postcss@^8.4.27, postcss@^8.4.41, postcss@^8.4.47, postcss@^8.5.3: prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== proxy-addr@~2.0.7: version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: forwarded "0.2.0" @@ -2320,7 +2313,7 @@ proxy-addr@~2.0.7: pump@^3.0.0: version "3.0.2" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz" integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== dependencies: end-of-stream "^1.1.0" @@ -2328,34 +2321,34 @@ pump@^3.0.0: punycode@^2.1.0: version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== qs@6.13.0: version "6.13.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + resolved "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz" integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: side-channel "^1.0.6" queue-microtask@^1.2.2: version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== quick-lru@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== range-parser@~1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== raw-body@2.5.2: version "2.5.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz" integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" @@ -2365,7 +2358,7 @@ raw-body@2.5.2: react-dom@^18: version "18.3.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== dependencies: loose-envify "^1.1.0" @@ -2373,17 +2366,17 @@ react-dom@^18: react-icons@^5.4.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.5.0.tgz#8aa25d3543ff84231685d3331164c00299cdfaf2" + resolved "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz" integrity sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw== react-refresh@^0.14.0: version "0.14.2" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" + resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz" integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== react-router-dom@^6.22.2: version "6.30.0" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.30.0.tgz#a64774104508bff56b1affc2796daa3f7e76b7df" + resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.0.tgz" integrity sha512-x30B78HV5tFk8ex0ITwzC9TTZMua4jGyA9IUlH1JLQYQTFyxr/ZxwOJq7evg1JX1qGVUcvhsmQSKdPncQrjTgA== dependencies: "@remix-run/router" "1.23.0" @@ -2391,45 +2384,45 @@ react-router-dom@^6.22.2: react-router@6.30.0: version "6.30.0" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.30.0.tgz#9789d775e63bc0df60f39ced77c8c41f1e01ff90" + resolved "https://registry.npmjs.org/react-router/-/react-router-6.30.0.tgz" integrity sha512-D3X8FyH9nBcTSHGdEKurK7r8OYE1kKFn3d/CF+CoxbSHkxU7o37+Uh7eAHRXr6k2tSExXYO++07PeXJtA/dEhQ== dependencies: "@remix-run/router" "1.23.0" react@^18: version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== dependencies: loose-envify "^1.1.0" read-cache@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + resolved "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz" integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== dependencies: pify "^2.3.0" readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" resolve-alpn@^1.0.0: version "1.2.1" - resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz" integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== resolve-from@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve@^1.1.7, resolve@^1.22.8: version "1.22.10" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz" integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== dependencies: is-core-module "^2.16.0" @@ -2438,62 +2431,62 @@ resolve@^1.1.7, resolve@^1.22.8: responselike@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" + resolved "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz" integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== dependencies: lowercase-keys "^2.0.0" reusify@^1.0.4: version "1.1.0" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz" integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== rimraf@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" rollup@^3.27.1: version "3.29.5" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.5.tgz#8a2e477a758b520fb78daf04bca4c522c1da8a54" + resolved "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz" integrity sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w== optionalDependencies: fsevents "~2.3.2" run-parallel@^1.1.9: version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: queue-microtask "^1.2.2" safe-buffer@5.2.1: version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== "safer-buffer@>= 2.1.2 < 3": version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== scheduler@^0.23.2: version "0.23.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz" integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== dependencies: loose-envify "^1.1.0" semver@^6.3.1: version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== send@0.19.0: version "0.19.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz" integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" @@ -2512,7 +2505,7 @@ send@0.19.0: serve-static@1.16.2: version "1.16.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz" integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: encodeurl "~2.0.0" @@ -2522,24 +2515,24 @@ serve-static@1.16.2: setprototypeof@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== side-channel-list@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz" integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== dependencies: es-errors "^1.3.0" @@ -2547,7 +2540,7 @@ side-channel-list@^1.0.0: side-channel-map@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + resolved "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz" integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== dependencies: call-bound "^1.0.2" @@ -2557,7 +2550,7 @@ side-channel-map@^1.0.1: side-channel-weakmap@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + resolved "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz" integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== dependencies: call-bound "^1.0.2" @@ -2568,7 +2561,7 @@ side-channel-weakmap@^1.0.2: side-channel@^1.0.6: version "1.1.0" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz" integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== dependencies: es-errors "^1.3.0" @@ -2579,23 +2572,23 @@ side-channel@^1.0.6: signal-exit@^4.0.1: version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== source-map-js@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== statuses@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: name string-width-cjs version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" @@ -2604,7 +2597,7 @@ statuses@2.0.1: string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: eastasianwidth "^0.2.0" @@ -2613,26 +2606,26 @@ string-width@^5.0.1, string-width@^5.1.2: "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" strip-ansi@^7.0.1: version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: ansi-regex "^6.0.1" strip-json-comments@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== sucrase@^3.35.0: version "3.35.0" - resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz" integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== dependencies: "@jridgewell/gen-mapping" "^0.3.2" @@ -2645,19 +2638,19 @@ sucrase@^3.35.0: supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== tailwindcss@3: version "3.4.17" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.17.tgz#ae8406c0f96696a631c790768ff319d46d5e5a63" + resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz" integrity sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og== dependencies: "@alloc/quick-lru" "^5.2.0" @@ -2685,75 +2678,75 @@ tailwindcss@3: tailwindcss@4.1.3: version "4.1.3" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.1.3.tgz#f5a6b4451295c06e213013697f7193be1630fa46" + resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.3.tgz" integrity sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g== tapable@^2.2.0: version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== text-table@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== thenify-all@^1.0.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz" integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== dependencies: thenify ">= 3.1.0 < 4" "thenify@>= 3.1.0 < 4": version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz" integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== dependencies: any-promise "^1.0.0" to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" to-utf8@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + resolved "https://registry.npmjs.org/to-utf8/-/to-utf8-0.0.1.tgz" integrity sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ== toidentifier@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== ts-interface-checker@^0.1.9: version "0.1.13" - resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== tslib@^2.4.0: version "2.8.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: prelude-ls "^1.2.1" type-fest@^0.20.2: version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== type-is@~1.6.18: version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: media-typer "0.3.0" @@ -2761,37 +2754,32 @@ type-is@~1.6.18: typescript@^5: version "5.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz" integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== uikit@^3.7.0: version "3.23.6" - resolved "https://registry.yarnpkg.com/uikit/-/uikit-3.23.6.tgz#92398eb8d9ac74c7ae7b2f85fde1b6e4ae1bde70" + resolved "https://registry.npmjs.org/uikit/-/uikit-3.23.6.tgz" integrity sha512-7VuR+q+gKo6MQK0lJMte6gtyvk22kSrLHV1rgGpB9UvVjkzpQyJb5qEMKvGpokZA3vG6czTOvD88iwTleQLmKA== ulid@^2.3.0: version "2.4.0" - resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.4.0.tgz#9d9ee22e63f4390ee1bcd9ad09fca39d8ae0afed" + resolved "https://registry.npmjs.org/ulid/-/ulid-2.4.0.tgz" integrity sha512-fIRiVTJNcSRmXKPZtGzFQv9WRrZ3M9eoptl/teFJvjOzmpU+/K/JH6HZ8deBfb5vMEpicJcLn7JmvdknlMq7Zg== undici-types@~6.19.2: version "6.19.8" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== -undici-types@~6.21.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" - integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== - unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== update-browserslist-db@^1.1.1: version "1.1.3" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz" integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== dependencies: escalade "^3.2.0" @@ -2799,42 +2787,42 @@ update-browserslist-db@^1.1.1: uri-js@^4.2.2: version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" usehooks-ts@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/usehooks-ts/-/usehooks-ts-3.1.1.tgz#0bb7f38f36f8219ee4509cc5e944ae610fb97656" + resolved "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.1.tgz" integrity sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA== dependencies: lodash.debounce "^4.0.8" util-deprecate@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== utils-merge@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== uuid@^8.3.2: version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== vary@^1, vary@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== vite@4: - version "4.5.14" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.14.tgz#2e652bc1d898265d987d6543ce866ecd65fa4086" - integrity sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g== + version "4.5.13" + resolved "https://registry.npmjs.org/vite/-/vite-4.5.13.tgz" + integrity sha512-Hgp8IF/yZDzKsN1hQWOuQZbrKiaFsbQud+07jJ8h9m9PaHWkpvZ5u55Xw5yYjWRXwRQ4jwFlJvY7T7FUJG9MCA== dependencies: esbuild "^0.18.10" postcss "^8.4.27" @@ -2844,19 +2832,19 @@ vite@4: which@^2.0.1: version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" word-wrap@^1.2.5: version "1.2.5" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -2865,7 +2853,7 @@ word-wrap@^1.2.5: wrap-ansi@^8.1.0: version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: ansi-styles "^6.1.0" @@ -2874,25 +2862,25 @@ wrap-ansi@^8.1.0: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== ws@^8.17.1: version "8.18.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" + resolved "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz" integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== yallist@^3.0.2: version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yaml@^2.3.4: version "2.7.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.1.tgz#44a247d1b88523855679ac7fa7cda6ed7e135cf6" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz" integrity sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ== yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From 7553d211be0a80f074eb6c5db86dea07104e7a90 Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Thu, 22 May 2025 15:03:16 +0100 Subject: [PATCH 02/15] examples/annotations: expose in examples index Uses a double-pane view to show the example side by side for two different clients. --- .../javascript/src/script.ts | 3 +++ src/components/Examples/ExamplesRenderer.tsx | 1 + src/data/examples/index.ts | 10 ++++++++++ src/templates/examples.tsx | 8 ++++++-- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/examples/pub-sub-message-annotations/javascript/src/script.ts b/examples/pub-sub-message-annotations/javascript/src/script.ts index 0bd322cdc3..5266b15070 100644 --- a/examples/pub-sub-message-annotations/javascript/src/script.ts +++ b/examples/pub-sub-message-annotations/javascript/src/script.ts @@ -12,6 +12,9 @@ const urlParams = new URLSearchParams(window.location.search); const channelName = urlParams.get('name') || 'pub-sub-message-annotations'; const channel = client.channels.get(channelName); +const clientId = urlParams.get('clientId') || 'user2'; +console.log(`Client ID: ${clientId}`); + channel.subscribe((message) => { console.log(message); }); diff --git a/src/components/Examples/ExamplesRenderer.tsx b/src/components/Examples/ExamplesRenderer.tsx index 39a50a65fb..c925540124 100644 --- a/src/components/Examples/ExamplesRenderer.tsx +++ b/src/components/Examples/ExamplesRenderer.tsx @@ -185,6 +185,7 @@ const ExamplesRenderer = ({ showOpenInCodeSandbox={false} showRefreshButton {...(id === 'pub-sub-message-encryption' && { startRoute: '?encrypted=true' })} + {...(id === 'pub-sub-message-annotations' && { startRoute: '?clientId=user1' })} /> diff --git a/src/data/examples/index.ts b/src/data/examples/index.ts index b3414951bc..5b9422f95d 100644 --- a/src/data/examples/index.ts +++ b/src/data/examples/index.ts @@ -188,6 +188,16 @@ export const examples: Example[] = [ metaTitle: `Implement message rewind with the Ably Pub/Sub SDK`, metaDescription: `Use the Ably Pub/Sub SDK to implement message rewind. Automatically retrieve recent messages on subscribe to improve app state continuity.`, }, + { + id: 'pub-sub-message-annotations', + name: 'Message Annotations', + description: 'Annotate pub/sub messages with additional data.', + products: ['pubsub'], + layout: 'double-horizontal', + visibleFiles: ['src/script.ts'], + metaTitle: `Implement message annotations with the Ably Pub/Sub SDK`, + metaDescription: `Use the Ably Pub/Sub JavaScript SDK to implement message annotations. Annotate messages with additional data and view summaries of the annotations.`, + }, { id: 'spaces-avatar-stack', name: 'Avatar stack', diff --git a/src/templates/examples.tsx b/src/templates/examples.tsx index b932375276..c6a26452cd 100644 --- a/src/templates/examples.tsx +++ b/src/templates/examples.tsx @@ -89,14 +89,18 @@ const Examples = ({ pageContext }: { pageContext: { example: ExampleWithContent window.history.replaceState({}, '', window.location.pathname + '?' + urlParams.toString()); // There is a bug in Sandpack where startRoute is lost on re-renders. This is a workaround to reintroduce it post-language change. - if (example.id === 'pub-sub-message-encryption') { + if (example.id === 'pub-sub-message-encryption' || example.id === 'pub-sub-message-annotations') { if (isFirstRender.current) { isFirstRender.current = false; } else { setTimeout(() => { const iframe = document.querySelector('.sp-preview-iframe') as HTMLIFrameElement; if (iframe) { - iframe.setAttribute('src', iframe.getAttribute('src') + '?encrypted=true'); + let queryParams = 'encrypted=true'; // for pub-sub-message-encryption + if (example.id === 'pub-sub-message-annotations') { + queryParams = 'clientId=user1'; + } + iframe.setAttribute('src', iframe.getAttribute('src') + '?' + queryParams); } }, 100); } From 7fdf2d8581c9bf74e7ae305a80795876a4f2243f Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Thu, 22 May 2025 16:53:54 +0100 Subject: [PATCH 03/15] examples/annotations: message publish subscribe --- .../javascript/index.html | 10 +++- .../javascript/src/script.ts | 50 ++++++++++++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/examples/pub-sub-message-annotations/javascript/index.html b/examples/pub-sub-message-annotations/javascript/index.html index ab773209b4..8866475c6c 100644 --- a/examples/pub-sub-message-annotations/javascript/index.html +++ b/examples/pub-sub-message-annotations/javascript/index.html @@ -10,8 +10,14 @@ -
- Hello world +
+
+
+ + +
+
+
diff --git a/examples/pub-sub-message-annotations/javascript/src/script.ts b/examples/pub-sub-message-annotations/javascript/src/script.ts index 5266b15070..a3630e73df 100644 --- a/examples/pub-sub-message-annotations/javascript/src/script.ts +++ b/examples/pub-sub-message-annotations/javascript/src/script.ts @@ -1,4 +1,5 @@ import * as Ably from 'ably'; +import type { RealtimeChannel, Message } from 'ably'; import { nanoid } from 'nanoid'; import './styles.css'; @@ -15,6 +16,51 @@ const channel = client.channels.get(channelName); const clientId = urlParams.get('clientId') || 'user2'; console.log(`Client ID: ${clientId}`); -channel.subscribe((message) => { - console.log(message); +function createMessageElement(message: Message) { + // Create the container for the message + const messageContainer = document.createElement('div'); + messageContainer.className = 'message-container mb-4'; + messageContainer.dataset.messageId = message.id; + + // Create the message element + const messageElement = document.createElement('div'); + messageElement.className = 'message p-4 border rounded-lg bg-white shadow-lg cursor-pointer hover:bg-gray-50'; + + // Add the message content + if (message.data instanceof ArrayBuffer) { + const decoder = new TextDecoder('utf-8'); + messageElement.textContent = decoder.decode(message.data as ArrayBuffer); + } else { + messageElement.textContent = message.data; + } + + // Add elements to the container + messageContainer.appendChild(messageElement); + + return messageContainer; +} + +async function subscribeToChannel(channel: RealtimeChannel) { + channel.subscribe((message: Message) => { + const messageElement = createMessageElement(message); + document.getElementById('messages')?.appendChild(messageElement); + }); +} + +const publishButton = document.getElementById('publish-button'); + +publishButton?.addEventListener('click', () => { + const messageInput = document.getElementById('message-input') as HTMLInputElement; + const message = messageInput.value.trim(); + + if (message) { + channel.publish('message', message); + messageInput.value = ''; + } }); + +async function main() { + await subscribeToChannel(channel); +} + +main(); From 8b3a3fc8dbc46e5211baa230e696e18ec9dbc339 Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Fri, 23 May 2025 10:58:27 +0100 Subject: [PATCH 04/15] examples/annotations: add message details pane Shown in an expandable pane when the message is clicked. --- .../javascript/src/script.ts | 77 ++++++++++++++++--- 1 file changed, 66 insertions(+), 11 deletions(-) diff --git a/examples/pub-sub-message-annotations/javascript/src/script.ts b/examples/pub-sub-message-annotations/javascript/src/script.ts index a3630e73df..4804afccdb 100644 --- a/examples/pub-sub-message-annotations/javascript/src/script.ts +++ b/examples/pub-sub-message-annotations/javascript/src/script.ts @@ -16,26 +16,81 @@ const channel = client.channels.get(channelName); const clientId = urlParams.get('clientId') || 'user2'; console.log(`Client ID: ${clientId}`); +let selectedMessageId: string | undefined; + +function createMessageDetailsElement(message: Message) { + const messageDetails = document.createElement('div'); + messageDetails.className = `grid grid-cols-2 gap-4`; + messageDetails.innerHTML = ` +
+

Message Info

+

ID: ${message.id}

+

Client ID: ${message.clientId}

+

Action: ${message.action}

+
+ `; + return messageDetails; +} + +function createDetailsPane(message: Message) { + // Create the details pane (initially hidden) + const detailsPane = document.createElement('div'); + detailsPane.className = 'mt-2 p-4 border rounded-lg bg-gray-50 hidden'; + detailsPane.id = `details-${message.id}`; + + const messageDetails = createMessageDetailsElement(message); + detailsPane.appendChild(messageDetails); + + return detailsPane; +} + function createMessageElement(message: Message) { // Create the container for the message const messageContainer = document.createElement('div'); - messageContainer.className = 'message-container mb-4'; - messageContainer.dataset.messageId = message.id; + messageContainer.className = 'mb-4'; // Create the message element const messageElement = document.createElement('div'); - messageElement.className = 'message p-4 border rounded-lg bg-white shadow-lg cursor-pointer hover:bg-gray-50'; - - // Add the message content - if (message.data instanceof ArrayBuffer) { - const decoder = new TextDecoder('utf-8'); - messageElement.textContent = decoder.decode(message.data as ArrayBuffer); - } else { - messageElement.textContent = message.data; - } + messageElement.className = `p-4 border rounded-lg bg-white shadow-md cursor-pointer hover:shadow-lg transition-shadow duration-200`; + messageElement.id = `message-${message.id}`; + messageElement.textContent = message.data; + + // Create the details pane + const detailsPane = createDetailsPane(message); + + // Add event listener to toggle details pane + messageElement.addEventListener('click', () => { + // If this message is already selected, hide details and deselect + if (selectedMessageId === message.id) { + detailsPane.classList.add('hidden'); + selectedMessageId = undefined; + messageElement.classList.remove('border-primary'); + return; + } + + // Hide any currently visible details pane + if (selectedMessageId) { + const currentDetailsPane = document.getElementById(`details-${selectedMessageId}`); + if (currentDetailsPane) { + currentDetailsPane.classList.add('hidden'); + } + + // Remove highlight from previously selected message + const prevSelected = document.getElementById(`message-${selectedMessageId}`); + if (prevSelected) { + prevSelected.classList.remove('border-primary'); + } + } + + // Show this message's details and set as selected + detailsPane.classList.remove('hidden'); + selectedMessageId = message.id; + messageElement.classList.add('border-primary'); + }); // Add elements to the container messageContainer.appendChild(messageElement); + messageContainer.appendChild(detailsPane); return messageContainer; } From f3aa3c175a43d83bab577458c876c8707dce5059 Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Fri, 23 May 2025 11:00:16 +0100 Subject: [PATCH 05/15] examples/annotations: use client ID in Ably client --- .../javascript/src/script.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/examples/pub-sub-message-annotations/javascript/src/script.ts b/examples/pub-sub-message-annotations/javascript/src/script.ts index 4804afccdb..a1c2c5ab1f 100644 --- a/examples/pub-sub-message-annotations/javascript/src/script.ts +++ b/examples/pub-sub-message-annotations/javascript/src/script.ts @@ -1,21 +1,18 @@ import * as Ably from 'ably'; import type { RealtimeChannel, Message } from 'ably'; -import { nanoid } from 'nanoid'; import './styles.css'; +const urlParams = new URLSearchParams(window.location.search); +const clientId = urlParams.get('clientId') || 'user2'; +const channelName = urlParams.get('name') || 'pub-sub-message-annotations'; + const client = new Ably.Realtime({ - clientId: nanoid(), + clientId, key: import.meta.env.VITE_ABLY_KEY as string, }); -const urlParams = new URLSearchParams(window.location.search); - -const channelName = urlParams.get('name') || 'pub-sub-message-annotations'; const channel = client.channels.get(channelName); -const clientId = urlParams.get('clientId') || 'user2'; -console.log(`Client ID: ${clientId}`); - let selectedMessageId: string | undefined; function createMessageDetailsElement(message: Message) { From 9a32b340d145e45693b74da7ecef8204ab505138 Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Fri, 23 May 2025 12:07:29 +0100 Subject: [PATCH 06/15] example/annotations: add annotation publishing Publish an annotation, specifying the annotation type. Summaries are received as a message in the subscribe listener. --- .../javascript/index.html | 2 +- .../javascript/src/script.ts | 70 +++++++++++++++++-- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/examples/pub-sub-message-annotations/javascript/index.html b/examples/pub-sub-message-annotations/javascript/index.html index 8866475c6c..fcb67a3b58 100644 --- a/examples/pub-sub-message-annotations/javascript/index.html +++ b/examples/pub-sub-message-annotations/javascript/index.html @@ -13,7 +13,7 @@
- +
diff --git a/examples/pub-sub-message-annotations/javascript/src/script.ts b/examples/pub-sub-message-annotations/javascript/src/script.ts index a1c2c5ab1f..725d43b53a 100644 --- a/examples/pub-sub-message-annotations/javascript/src/script.ts +++ b/examples/pub-sub-message-annotations/javascript/src/script.ts @@ -4,28 +4,72 @@ import './styles.css'; const urlParams = new URLSearchParams(window.location.search); const clientId = urlParams.get('clientId') || 'user2'; -const channelName = urlParams.get('name') || 'pub-sub-message-annotations'; +const channelName = urlParams.get('name') || 'mutable:pub-sub-message-annotations'; const client = new Ably.Realtime({ clientId, key: import.meta.env.VITE_ABLY_KEY as string, }); -const channel = client.channels.get(channelName); +const channel = client.channels.get(channelName, { + modes: ['PUBLISH', 'SUBSCRIBE', 'ANNOTATION_PUBLISH', 'ANNOTATION_SUBSCRIBE'], +}); +const annotationNamespace = 'my-annotations'; let selectedMessageId: string | undefined; +function createPublishAnnotationElement(message: Message) { + const publishAnnotation = document.createElement('div'); + publishAnnotation.className = 'md:col-span-2 mb-4'; + publishAnnotation.innerHTML = ` +

Annotations

+
+
+
+ +
+
+ + +
+ `; + const publishButton = publishAnnotation.querySelector('button'); + publishButton?.addEventListener('click', () => { + const selectInput = publishAnnotation.querySelector('select') as HTMLSelectElement; + const annotationType = selectInput.options[selectInput.selectedIndex].value; + const dataInput = publishAnnotation.querySelector('input') as HTMLInputElement; + const data = dataInput.value.trim(); + if (data) { + channel.annotations.publish(message, { + type: `${annotationNamespace}:${annotationType}`, + data: data, + }); + dataInput.value = ''; + } + }); + return publishAnnotation; +} + function createMessageDetailsElement(message: Message) { const messageDetails = document.createElement('div'); - messageDetails.className = `grid grid-cols-2 gap-4`; + messageDetails.className = `grid grid-cols-1 md:grid-cols-3 gap-4`; messageDetails.innerHTML = ` -
+

Message Info

ID: ${message.id}

+

Serial: ${message.serial}

Client ID: ${message.clientId}

Action: ${message.action}

`; + const publishAnnotation = createPublishAnnotationElement(message); + messageDetails.appendChild(publishAnnotation); return messageDetails; } @@ -48,9 +92,23 @@ function createMessageElement(message: Message) { // Create the message element const messageElement = document.createElement('div'); - messageElement.className = `p-4 border rounded-lg bg-white shadow-md cursor-pointer hover:shadow-lg transition-shadow duration-200`; + messageElement.className = `flex space-x-2 p-4 border rounded-lg bg-white shadow-md cursor-pointer hover:shadow-lg transition-shadow duration-200`; messageElement.id = `message-${message.id}`; - messageElement.textContent = message.data; + let badgeColor = 'bg-gray-300 text-gray-800'; + let title = message.name; + if (message.action === 'message.create') { + badgeColor = 'bg-green-100 text-green-800'; + title = message.data; + } else if (message.action === 'message.summary') { + badgeColor = 'bg-blue-100 text-blue-800'; + title = message.serial; + } + messageElement.innerHTML = ` + + ${message.action} + +
${title}
+ `; // Create the details pane const detailsPane = createDetailsPane(message); From aab0fd9001c8f3c7228b293cd233c27291f2635c Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Fri, 23 May 2025 13:32:14 +0100 Subject: [PATCH 07/15] examples/annotations: add annotation summaries Listens for annotation summaries received in realtime and renders their information for each summary type in a set of expandable summary components in the message details. --- .../javascript/README.md | 36 ++- .../javascript/src/ably.ts | 25 ++ .../javascript/src/components/arrow.ts | 32 +++ .../javascript/src/components/badge.ts | 55 ++++ .../javascript/src/components/details.ts | 67 +++++ .../javascript/src/components/message.ts | 40 +++ .../javascript/src/components/summary.ts | 245 ++++++++++++++++++ .../javascript/src/config.ts | 16 ++ .../javascript/src/script.ts | 189 ++------------ .../javascript/src/types.ts | 10 + .../javascript/tailwind.config.ts | 5 + 11 files changed, 552 insertions(+), 168 deletions(-) create mode 100644 examples/pub-sub-message-annotations/javascript/src/ably.ts create mode 100644 examples/pub-sub-message-annotations/javascript/src/components/arrow.ts create mode 100644 examples/pub-sub-message-annotations/javascript/src/components/badge.ts create mode 100644 examples/pub-sub-message-annotations/javascript/src/components/details.ts create mode 100644 examples/pub-sub-message-annotations/javascript/src/components/message.ts create mode 100644 examples/pub-sub-message-annotations/javascript/src/components/summary.ts create mode 100644 examples/pub-sub-message-annotations/javascript/src/config.ts create mode 100644 examples/pub-sub-message-annotations/javascript/src/types.ts diff --git a/examples/pub-sub-message-annotations/javascript/README.md b/examples/pub-sub-message-annotations/javascript/README.md index 88d41842c3..c9832a9fe4 100644 --- a/examples/pub-sub-message-annotations/javascript/README.md +++ b/examples/pub-sub-message-annotations/javascript/README.md @@ -1,10 +1,31 @@ # Using message annotations with Pub/Sub -TODO +This example demonstrates how to use Ably's message annotations feature to add additional metadata to messages in a pub/sub system. Message annotations allow clients to add reactions, flags, or other metadata to messages without modifying the original message content. ## Resources -TODO +- [Ably Documentation](https://ably.com/docs) +- [Message Annotations Documentation](https://ably.com/docs/messages/annotations) + +The channel name must be in a mutable message namespace, which is why we're using `mutable:pub-sub-message-annotations` in this example. + +## Features + +In this example, you can: + +1. Publish messages to a channel +2. Add annotations to messages using different annotation types: + - **distinct.v1**: Track different values with client IDs that created them + - **unique.v1**: Similar to distinct, but only the first client ID is recorded + - **multiple.v1**: Track counts of values by different clients + - **flag.v1**: Simple flags with client IDs + - **total.v1**: Count the total annotations + +3. View annotation summaries showing: + - How many of each annotation type exist + - Which clients contributed annotations + - The values of annotations + - Expandable/collapsible sections for detailed information ## Getting started @@ -42,6 +63,17 @@ TODO 7. Try it out by opening two tabs to [http://localhost:5173/](http://localhost:5173/) with your browser to see the result. +## How to use this example + +1. Enter a message in the input field and click "Publish" to send it to the channel. +2. After publishing a message, you'll see it appear in the message list with an expandable annotation interface. +3. To add an annotation, select an annotation type from the dropdown menu, enter a value, and click "Publish". +4. Open the example in multiple browser tabs with different URL parameters (e.g., `?clientId=user1` and `?clientId=user2`) to see how annotations from different clients are handled. +5. Experiment with different annotation types: + - For reactions, try using the "multiple.v1" type with values like "👍" or "❤️" + - For flagging content, use the "flag.v1" type + - For tracking unique entries, use "distinct.v1" or "unique.v1" + ## Open in CodeSandbox In CodeSandbox, rename the `.env.example` file to `.env.local` and update the value of your `VITE_ABLY_KEY` variable to use your Ably API key. diff --git a/examples/pub-sub-message-annotations/javascript/src/ably.ts b/examples/pub-sub-message-annotations/javascript/src/ably.ts new file mode 100644 index 0000000000..dd9a8d7bf8 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/ably.ts @@ -0,0 +1,25 @@ +import * as Ably from 'ably'; +import { clientId, channelName } from './config'; +import { MessageCreate } from './types'; + +let client: Ably.Realtime | null = null; + +function getClient(): Ably.Realtime { + if (!client) { + client = new Ably.Realtime({ + clientId, + key: import.meta.env.VITE_ABLY_KEY as string, + }); + } + return client; +} + +export function getChannel() { + return getClient().channels.get(channelName, { + modes: ['PUBLISH', 'SUBSCRIBE', 'ANNOTATION_PUBLISH', 'ANNOTATION_SUBSCRIBE'], + }); +} + +export function publishAnnotation(message: MessageCreate, annotation: Ably.OutboundAnnotation) { + return getChannel().annotations.publish(message, annotation); +} diff --git a/examples/pub-sub-message-annotations/javascript/src/components/arrow.ts b/examples/pub-sub-message-annotations/javascript/src/components/arrow.ts new file mode 100644 index 0000000000..43f663965a --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/components/arrow.ts @@ -0,0 +1,32 @@ +// Creates and manages SVG arrow icons for dropdown interactions + +export function createDropdownArrow(color: string) { + const svgNS = 'http://www.w3.org/2000/svg'; + const svg = document.createElementNS(svgNS, 'svg'); + svg.setAttribute('class', `h-4 w-4 text-${color}-500 transform transition-transform duration-200`); + svg.setAttribute('fill', 'none'); + svg.setAttribute('viewBox', '0 0 24 24'); + svg.setAttribute('stroke', 'currentColor'); + + const path = document.createElementNS(svgNS, 'path'); + path.setAttribute('stroke-linecap', 'round'); + path.setAttribute('stroke-linejoin', 'round'); + path.setAttribute('stroke-width', '2'); + path.setAttribute('d', 'M19 9l-7 7-7-7'); + + svg.appendChild(path); + return svg; +} + +export function rotateArrow(arrow: SVGElement, expanded: boolean) { + if (expanded) { + arrow.classList.add('rotate-180'); + } else { + arrow.classList.remove('rotate-180'); + } +} + +export function toggleArrowRotation(arrow: SVGElement) { + arrow.classList.toggle('rotate-180'); + return arrow.classList.contains('rotate-180'); +} diff --git a/examples/pub-sub-message-annotations/javascript/src/components/badge.ts b/examples/pub-sub-message-annotations/javascript/src/components/badge.ts new file mode 100644 index 0000000000..3508a8b2c5 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/components/badge.ts @@ -0,0 +1,55 @@ +// Components for displaying client IDs and counts from annotation summaries + +export function createCountBadge(count: number, color: string, isRounded = true) { + const badge = document.createElement('span'); + badge.className = `ml-2 inline-flex items-center px-2 py-0.5 text-xs font-medium bg-${color}-100 text-${color}-800`; + badge.textContent = `${count}`; + badge.classList.add(isRounded ? 'rounded-full' : 'rounded'); + return badge; +} + +export function createClientBadge(clientId: string, color: string) { + const badge = document.createElement('span'); + badge.className = `inline-flex items-center px-2 py-0.5 rounded-full text-xs bg-${color}-100 text-${color}-800`; + badge.textContent = clientId; + return badge; +} + +export function createClientBadgeWithCount(clientId: string, count: number, color: string) { + const badgeGroup = document.createElement('div'); + badgeGroup.className = 'inline-flex rounded-full overflow-hidden text-xs font-medium shadow-sm'; + + const clientIdPart = document.createElement('span'); + clientIdPart.className = `px-2 py-0.5 bg-${color}-100 text-${color}-800`; + clientIdPart.textContent = clientId; + + const countPart = document.createElement('span'); + countPart.className = `px-1.5 py-0.5 bg-${color}-400 text-white`; + countPart.textContent = `${count}`; + + badgeGroup.appendChild(clientIdPart); + badgeGroup.appendChild(countPart); + return badgeGroup; +} + +export function createClientBadges(clients: string[], color: string) { + const badges = document.createElement('div'); + badges.className = `mt-2 flex flex-wrap gap-1`; + for (const id of clients) { + const badge = createClientBadge(id, color); + badges.appendChild(badge); + } + return badges; +} + +export function createClientBadgesWithCounts(clientIds: Record, color: string) { + const container = document.createElement('div'); + container.className = 'flex flex-wrap gap-2 mt-2'; + + for (const [clientId, count] of Object.entries(clientIds)) { + const badge = createClientBadgeWithCount(clientId, count, color); + container.appendChild(badge); + } + + return container; +} diff --git a/examples/pub-sub-message-annotations/javascript/src/components/details.ts b/examples/pub-sub-message-annotations/javascript/src/components/details.ts new file mode 100644 index 0000000000..370e60b989 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/components/details.ts @@ -0,0 +1,67 @@ +// Expandable details panel for messages that supports publishing +// annotations and viewing annotation summaries. + +import { MessageCreate } from '../types'; +import { annotationNamespace } from '../config'; +import { publishAnnotation } from '../ably'; +import { createAnnotationSummaryElement } from './summary'; + +export function createPublishAnnotationElement(message: MessageCreate) { + const publisher = document.createElement('div'); + publisher.className = 'md:col-span-2 mb-4'; + publisher.innerHTML = ` +
+
+
+ +
+
+ + +
+ `; + + const publishButton = publisher.querySelector('button'); + publishButton?.addEventListener('click', () => { + const selectInput = publisher.querySelector('select') as HTMLSelectElement; + const annotationType = selectInput.options[selectInput.selectedIndex].value; + const nameInput = publisher.querySelector('input') as HTMLInputElement; + const name = nameInput.value.trim(); + if (name) { + publishAnnotation(message, { + type: `${annotationNamespace}:${annotationType}`, + name, + }); + nameInput.value = ''; + } + }); + + return publisher; +} + +export function createMessageDetailsElement(message: MessageCreate) { + const messageDetails = document.createElement('div'); + messageDetails.className = `grid grid-cols-1 gap-4`; + const publishAnnotation = createPublishAnnotationElement(message); + const annotationSummary = createAnnotationSummaryElement(message); + messageDetails.appendChild(publishAnnotation); + messageDetails.appendChild(annotationSummary); + return messageDetails; +} + +export function createDetailsPane(message: MessageCreate) { + const detailsPane = document.createElement('div'); + detailsPane.className = 'mt-2 p-4 border rounded-lg bg-gray-50'; + detailsPane.id = `details-${message.id}`; + + const messageDetails = createMessageDetailsElement(message); + detailsPane.appendChild(messageDetails); + + return detailsPane; +} diff --git a/examples/pub-sub-message-annotations/javascript/src/components/message.ts b/examples/pub-sub-message-annotations/javascript/src/components/message.ts new file mode 100644 index 0000000000..36a3b5a444 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/components/message.ts @@ -0,0 +1,40 @@ +// Components for displaying messages received on the channel + +import { MessageCreate } from '../types'; +import { createDropdownArrow, toggleArrowRotation } from './arrow'; +import { createDetailsPane } from './details'; + +function createMessageElement(message: MessageCreate) { + const messageContainer = document.createElement('div'); + messageContainer.className = 'mb-4'; + messageContainer.setAttribute('data-serial', message.serial); + + const messageElement = document.createElement('div'); + messageElement.className = `flex justify-between items-center p-4 border rounded-lg bg-white shadow-md cursor-pointer`; + messageElement.id = `message-${message.id}`; + + const textContent = document.createElement('span'); + textContent.textContent = message.data; + messageElement.appendChild(textContent); + + const arrow = createDropdownArrow('gray'); + messageElement.appendChild(arrow); + + const detailsPane = createDetailsPane(message); + detailsPane.classList.add('hidden'); + + messageElement.addEventListener('click', () => { + detailsPane.classList.toggle('hidden'); + toggleArrowRotation(arrow); + }); + + messageContainer.appendChild(messageElement); + messageContainer.appendChild(detailsPane); + + return messageContainer; +} + +export function addMessage(message: MessageCreate) { + const messageElement = createMessageElement(message); + document.getElementById('messages')?.appendChild(messageElement); +} diff --git a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts new file mode 100644 index 0000000000..24aa3d35c6 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts @@ -0,0 +1,245 @@ +// Handles the display and management of message annotation summaries + +import * as Ably from 'ably'; +import { MessageCreate, MessageSummary } from '../types'; +import { annotationTypes, findAnnotationType, annotationNamespace } from '../config'; +import { createDropdownArrow, rotateArrow, toggleArrowRotation } from './arrow'; +import { + createCountBadge, + createClientBadges, + createClientBadgesWithCounts, + createClientBadgeWithCount, +} from './badge'; + +function createEmptyAnnotationSummaryContentElement() { + const emptyState = document.createElement('div'); + emptyState.className = 'text-center p-4 text-gray-500 text-sm'; + emptyState.textContent = 'Publish an annotation to view summaries.'; + return emptyState; +} + +export function createAnnotationSummaryElement(message: MessageCreate) { + const annotationSummary = document.createElement('div'); + annotationSummary.className = 'bg-white shadow-sm rounded-lg p-4 mb-4'; + annotationSummary.id = `summary-container-${message.serial}`; + annotationSummary.setAttribute('data-serial', message.serial); + + const header = document.createElement('div'); + header.className = 'mb-3'; + header.innerHTML = `

Annotation Summary

`; + annotationSummary.appendChild(header); + + const sectionsContainer = document.createElement('div'); + sectionsContainer.className = 'space-y-2'; + sectionsContainer.id = `sections-${message.serial}`; + sectionsContainer.appendChild(createEmptyAnnotationSummaryContentElement()); + + annotationSummary.appendChild(sectionsContainer); + return annotationSummary; +} + +function createLabelContainer(label: string, color: string) { + const container = document.createElement('div'); + container.className = 'flex items-center'; + + const labelSpan = document.createElement('span'); + labelSpan.className = `text-xs font-medium text-${color}-800`; + labelSpan.textContent = label; + + container.appendChild(labelSpan); + return container; +} + +function createSectionHeader(key: string, entry: Ably.SummaryEntry) { + const { color, label } = findAnnotationType(key); + const sectionHeader = document.createElement('div'); + sectionHeader.className = `bg-${color}-50 px-3 py-2${key.endsWith('total.v1') ? '' : ' cursor-pointer'}`; + + const wrapper = document.createElement('div'); + wrapper.className = 'flex justify-between items-center'; + + const labelContainer = createLabelContainer(label, color); + + if (key.endsWith('total.v1')) { + const total = (entry as Ably.SummaryTotal).total; + labelContainer.appendChild(createCountBadge(total, color, false)); + wrapper.appendChild(labelContainer); + } else if (key.endsWith('flag.v1')) { + const total = (entry as Ably.SummaryClientIdList).total; + labelContainer.appendChild(createCountBadge(total, color)); + wrapper.appendChild(labelContainer); + wrapper.appendChild(createDropdownArrow(color)); + } else { + const count = Object.keys(entry).length; + labelContainer.appendChild(createCountBadge(count, color)); + + const valueLabel = document.createElement('span'); + valueLabel.className = `ml-1 text-xs text-${color}-600`; + valueLabel.textContent = `value${count !== 1 ? 's' : ''}`; + labelContainer.appendChild(valueLabel); + + wrapper.appendChild(labelContainer); + wrapper.appendChild(createDropdownArrow(color)); + } + + sectionHeader.appendChild(wrapper); + return sectionHeader; +} + +function createFlagCard(entry: Ably.SummaryClientIdList, color: string) { + const content = document.createElement('div'); + content.className = `p-3 bg-white border-t border-${color}-200`; + content.appendChild(createClientBadges(entry.clientIds, color)); + return content; +} + +function createDistinctUniqueCard(value: string, entry: Ably.SummaryClientIdList, color: string) { + const card = document.createElement('div'); + card.className = `p-3 border-t border-${color}-200`; + + const header = document.createElement('div'); + header.className = 'flex justify-between items-center'; + + const valueLabel = document.createElement('span'); + valueLabel.className = `text-sm font-medium text-${color}-800`; + valueLabel.textContent = value; + + header.appendChild(valueLabel); + header.appendChild(createCountBadge(entry.total, color)); + + card.appendChild(header); + card.appendChild(createClientBadges(entry.clientIds, color)); + + return card; +} + +function createMultipleCard(value: string, entry: Ably.SummaryMultipleValues[string], color: string) { + const card = document.createElement('div'); + card.className = `p-3 border-t border-${color}-200`; + + const header = document.createElement('div'); + header.className = 'flex justify-between items-center'; + + const valueLabel = document.createElement('span'); + valueLabel.className = `text-sm font-medium text-${color}-800`; + valueLabel.textContent = value; + + header.appendChild(valueLabel); + header.appendChild(createCountBadge(entry.total, color)); + card.appendChild(header); + + const clientBadgesContainer = document.createElement('div'); + clientBadgesContainer.className = 'mt-2'; + clientBadgesContainer.appendChild(createClientBadgesWithCounts(entry.clientIds || {}, color)); + card.appendChild(clientBadgesContainer); + + if (entry.totalUnidentified > 0) { + const unidentifiedContainer = document.createElement('div'); + unidentifiedContainer.className = 'mt-2'; + unidentifiedContainer.appendChild(createClientBadgeWithCount('Unidentified', entry.totalUnidentified, color)); + card.appendChild(unidentifiedContainer); + } + + return card; +} + +function createSectionContent(typeKey: string, entry: Ably.SummaryEntry) { + const { color } = findAnnotationType(typeKey); + const sectionContent = document.createElement('div'); + sectionContent.className = 'bg-white'; + + if (typeKey.endsWith('flag.v1')) { + sectionContent.appendChild(createFlagCard(entry as Ably.SummaryClientIdList, color)); + } else if (typeKey.endsWith('distinct.v1') || typeKey.endsWith('unique.v1')) { + for (const [value, info] of Object.entries(entry as Ably.SummaryUniqueValues | Ably.SummaryDistinctValues)) { + sectionContent.appendChild(createDistinctUniqueCard(value, info, color)); + } + } else if (typeKey.endsWith('multiple.v1')) { + for (const [value, info] of Object.entries(entry as Ably.SummaryMultipleValues)) { + sectionContent.appendChild(createMultipleCard(value, info, color)); + } + } + + return sectionContent; +} + +export function createSection(key: string, entry: Ably.SummaryEntry, wasExpanded: boolean) { + const { color } = findAnnotationType(key); + + const section = document.createElement('div'); + section.className = `border border-${color}-200 rounded-md overflow-hidden`; + section.setAttribute('data-type', key); + + const sectionHeader = createSectionHeader(key, entry); + section.appendChild(sectionHeader); + + if (key.endsWith('total.v1')) { + return section; + } + + const sectionContent = createSectionContent(key, entry); + section.appendChild(sectionContent); + + const shouldExpand = wasExpanded !== false; + section.setAttribute('data-expanded', `${shouldExpand}`); + + if (!shouldExpand) { + sectionContent.classList.add('hidden'); + } + + const arrow = sectionHeader.querySelector('svg'); + if (arrow instanceof SVGElement) { + rotateArrow(arrow, shouldExpand); + } + + sectionHeader.addEventListener('click', () => { + sectionContent.classList.toggle('hidden'); + + if (arrow instanceof SVGElement) { + const isExpanded = toggleArrowRotation(arrow); + section.setAttribute('data-expanded', `${isExpanded}`); + } + }); + + return section; +} + +export function updateAnnotationSummary(message: MessageSummary) { + const summaryContainer = document.getElementById(`summary-container-${message.serial}`); + if (!summaryContainer) { + return; + } + + const sectionsContainer = document.getElementById(`sections-${message.serial}`); + if (!sectionsContainer) { + return; + } + + // Preserve expansion states before rebuilding + const expandedStates: Record = {}; + for (const section of sectionsContainer.querySelectorAll('[data-type]')) { + const type = section.getAttribute('data-type'); + if (type) { + expandedStates[type] = section.getAttribute('data-expanded') === 'true'; + } + } + + sectionsContainer.innerHTML = ''; + + const hasAnnotations = annotationTypes.some((type) => message.summary[`${annotationNamespace}:${type.key}`]); + + if (!hasAnnotations) { + sectionsContainer.appendChild(createEmptyAnnotationSummaryContentElement()); + return; + } + + for (const { key } of annotationTypes) { + const entry = message.summary[`${annotationNamespace}:${key}`]; + if (!entry) { + continue; + } + + const section = createSection(key, entry, expandedStates[key]); + sectionsContainer.appendChild(section); + } +} diff --git a/examples/pub-sub-message-annotations/javascript/src/config.ts b/examples/pub-sub-message-annotations/javascript/src/config.ts new file mode 100644 index 0000000000..59b9cfc28b --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/config.ts @@ -0,0 +1,16 @@ +export const urlParams = new URLSearchParams(window.location.search); +export const clientId = urlParams.get('clientId') || 'user2'; +export const channelName = urlParams.get('name') || 'mutable:pub-sub-message-annotations'; +export const annotationNamespace = 'my-annotations'; + +export const annotationTypes = [ + { key: 'total.v1', color: 'blue', label: 'Total' }, + { key: 'distinct.v1', color: 'green', label: 'Distinct' }, + { key: 'unique.v1', color: 'purple', label: 'Unique' }, + { key: 'multiple.v1', color: 'amber', label: 'Multiple' }, + { key: 'flag.v1', color: 'red', label: 'Flag' }, +]; + +export function findAnnotationType(key: string) { + return annotationTypes.find((type) => type.key === key) || { key, color: 'gray', label: 'Unknown' }; +} diff --git a/examples/pub-sub-message-annotations/javascript/src/script.ts b/examples/pub-sub-message-annotations/javascript/src/script.ts index 725d43b53a..a8f0bc077e 100644 --- a/examples/pub-sub-message-annotations/javascript/src/script.ts +++ b/examples/pub-sub-message-annotations/javascript/src/script.ts @@ -1,176 +1,33 @@ -import * as Ably from 'ably'; -import type { RealtimeChannel, Message } from 'ably'; import './styles.css'; +import * as Ably from 'ably'; +import { getChannel } from './ably'; +import { MessageSummary, MessageCreate } from './types'; +import { addMessage } from './components/message'; +import { updateAnnotationSummary } from './components/summary'; -const urlParams = new URLSearchParams(window.location.search); -const clientId = urlParams.get('clientId') || 'user2'; -const channelName = urlParams.get('name') || 'mutable:pub-sub-message-annotations'; - -const client = new Ably.Realtime({ - clientId, - key: import.meta.env.VITE_ABLY_KEY as string, -}); - -const channel = client.channels.get(channelName, { - modes: ['PUBLISH', 'SUBSCRIBE', 'ANNOTATION_PUBLISH', 'ANNOTATION_SUBSCRIBE'], -}); -const annotationNamespace = 'my-annotations'; - -let selectedMessageId: string | undefined; - -function createPublishAnnotationElement(message: Message) { - const publishAnnotation = document.createElement('div'); - publishAnnotation.className = 'md:col-span-2 mb-4'; - publishAnnotation.innerHTML = ` -

Annotations

-
-
-
- -
-
- - -
- `; - const publishButton = publishAnnotation.querySelector('button'); +async function main() { + // Publish regular messages that can be annotated. + const publishButton = document.getElementById('publish-button'); publishButton?.addEventListener('click', () => { - const selectInput = publishAnnotation.querySelector('select') as HTMLSelectElement; - const annotationType = selectInput.options[selectInput.selectedIndex].value; - const dataInput = publishAnnotation.querySelector('input') as HTMLInputElement; - const data = dataInput.value.trim(); - if (data) { - channel.annotations.publish(message, { - type: `${annotationNamespace}:${annotationType}`, - data: data, - }); - dataInput.value = ''; + const messageInput = document.getElementById('message-input') as HTMLInputElement; + const message = messageInput.value.trim(); + if (message) { + getChannel().publish('message', message); + messageInput.value = ''; } }); - return publishAnnotation; -} - -function createMessageDetailsElement(message: Message) { - const messageDetails = document.createElement('div'); - messageDetails.className = `grid grid-cols-1 md:grid-cols-3 gap-4`; - messageDetails.innerHTML = ` -
-

Message Info

-

ID: ${message.id}

-

Serial: ${message.serial}

-

Client ID: ${message.clientId}

-

Action: ${message.action}

-
- `; - const publishAnnotation = createPublishAnnotationElement(message); - messageDetails.appendChild(publishAnnotation); - return messageDetails; -} - -function createDetailsPane(message: Message) { - // Create the details pane (initially hidden) - const detailsPane = document.createElement('div'); - detailsPane.className = 'mt-2 p-4 border rounded-lg bg-gray-50 hidden'; - detailsPane.id = `details-${message.id}`; - - const messageDetails = createMessageDetailsElement(message); - detailsPane.appendChild(messageDetails); - - return detailsPane; -} - -function createMessageElement(message: Message) { - // Create the container for the message - const messageContainer = document.createElement('div'); - messageContainer.className = 'mb-4'; - - // Create the message element - const messageElement = document.createElement('div'); - messageElement.className = `flex space-x-2 p-4 border rounded-lg bg-white shadow-md cursor-pointer hover:shadow-lg transition-shadow duration-200`; - messageElement.id = `message-${message.id}`; - let badgeColor = 'bg-gray-300 text-gray-800'; - let title = message.name; - if (message.action === 'message.create') { - badgeColor = 'bg-green-100 text-green-800'; - title = message.data; - } else if (message.action === 'message.summary') { - badgeColor = 'bg-blue-100 text-blue-800'; - title = message.serial; - } - messageElement.innerHTML = ` - - ${message.action} - -
${title}
- `; - // Create the details pane - const detailsPane = createDetailsPane(message); - - // Add event listener to toggle details pane - messageElement.addEventListener('click', () => { - // If this message is already selected, hide details and deselect - if (selectedMessageId === message.id) { - detailsPane.classList.add('hidden'); - selectedMessageId = undefined; - messageElement.classList.remove('border-primary'); - return; - } - - // Hide any currently visible details pane - if (selectedMessageId) { - const currentDetailsPane = document.getElementById(`details-${selectedMessageId}`); - if (currentDetailsPane) { - currentDetailsPane.classList.add('hidden'); - } - - // Remove highlight from previously selected message - const prevSelected = document.getElementById(`message-${selectedMessageId}`); - if (prevSelected) { - prevSelected.classList.remove('border-primary'); - } + // Subscribe to messages. + // We will receive a message.summary event when an annotation is published + // and a new summary is available. + // Regular messages will be received as message.create events. + getChannel().subscribe((message: Ably.Message) => { + if (message.action === 'message.summary') { + updateAnnotationSummary(message as MessageSummary); + } else if (message.action === 'message.create') { + addMessage(message as MessageCreate); } - - // Show this message's details and set as selected - detailsPane.classList.remove('hidden'); - selectedMessageId = message.id; - messageElement.classList.add('border-primary'); - }); - - // Add elements to the container - messageContainer.appendChild(messageElement); - messageContainer.appendChild(detailsPane); - - return messageContainer; -} - -async function subscribeToChannel(channel: RealtimeChannel) { - channel.subscribe((message: Message) => { - const messageElement = createMessageElement(message); - document.getElementById('messages')?.appendChild(messageElement); }); } -const publishButton = document.getElementById('publish-button'); - -publishButton?.addEventListener('click', () => { - const messageInput = document.getElementById('message-input') as HTMLInputElement; - const message = messageInput.value.trim(); - - if (message) { - channel.publish('message', message); - messageInput.value = ''; - } -}); - -async function main() { - await subscribeToChannel(channel); -} - -main(); +main().catch(console.error); diff --git a/examples/pub-sub-message-annotations/javascript/src/types.ts b/examples/pub-sub-message-annotations/javascript/src/types.ts new file mode 100644 index 0000000000..04930464d5 --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/types.ts @@ -0,0 +1,10 @@ +import type { Message } from 'ably'; + +export type MessageSummary = Message & Required>; +export type MessageCreate = Message & Required>; + +export type AnnotationType = { + key: string; + color: string; + label: string; +}; diff --git a/examples/pub-sub-message-annotations/javascript/tailwind.config.ts b/examples/pub-sub-message-annotations/javascript/tailwind.config.ts index 1c86e1c371..a80a6b7000 100644 --- a/examples/pub-sub-message-annotations/javascript/tailwind.config.ts +++ b/examples/pub-sub-message-annotations/javascript/tailwind.config.ts @@ -4,6 +4,11 @@ import type { Config } from 'tailwindcss'; const config: Config = { ...baseConfig, content: ['./src/**/*.{js,ts,tsx}', './index.html'], + safelist: [ + { + pattern: /(bg|text|border)-(blue|green|purple|amber|red|gray)-(50|100|200|300|400|500|600|700|800|900)/, // allow dynamic classes for colors + }, + ], }; export default config; From 789d7bcde400daeba9dae3cec16d1d13ca31551d Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Tue, 27 May 2025 17:55:46 +0100 Subject: [PATCH 08/15] examples/annotations: view raw annotations Separates the annotations summary from the raw annotations messages displayed in separate tabs. --- .../javascript/src/components/annotations.ts | 130 ++++++++++++++++++ .../javascript/src/components/details.ts | 69 +++++++++- .../javascript/src/components/message.ts | 7 +- .../javascript/src/components/summary.ts | 5 - .../javascript/src/script.ts | 11 +- 5 files changed, 204 insertions(+), 18 deletions(-) create mode 100644 examples/pub-sub-message-annotations/javascript/src/components/annotations.ts diff --git a/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts b/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts new file mode 100644 index 0000000000..cfb2eb6c9e --- /dev/null +++ b/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts @@ -0,0 +1,130 @@ +// Display of raw annotation messages + +import type { Annotation } from 'ably'; +import { findAnnotationType } from '../config'; +import { createClientBadge } from './badge'; + +function formatTimestamp(timestamp: number): string { + const date = new Date(timestamp); + return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }); +} + +function getAnnotationTypeKey(fullType: string): string { + const parts = fullType.split(':'); + if (parts.length > 1) { + return parts[1]; + } + return fullType; +} + +function createAnnotationItem(annotation: Annotation) { + const typeKey = getAnnotationTypeKey(annotation.type); + const { color, label } = findAnnotationType(typeKey); + + const item = document.createElement('div'); + item.className = `mb-2 p-3 border border-${color}-200 rounded-md bg-white shadow-sm`; + item.setAttribute('data-id', annotation.id); + item.setAttribute('data-timestamp', annotation.timestamp.toString()); + + const header = document.createElement('div'); + header.className = 'flex justify-between items-center mb-2'; + + const typeLabel = document.createElement('div'); + typeLabel.className = `text-sm font-medium text-${color}-800`; + typeLabel.textContent = label; + + const timestamp = document.createElement('div'); + timestamp.className = 'text-xs text-gray-500'; + timestamp.textContent = formatTimestamp(annotation.timestamp); + + header.appendChild(typeLabel); + header.appendChild(timestamp); + item.appendChild(header); + + const value = document.createElement('div'); + value.className = 'mb-2'; + + const valueLabel = document.createElement('span'); + valueLabel.className = 'text-xs text-gray-500 mr-1'; + valueLabel.textContent = 'Value:'; + + const valueContent = document.createElement('span'); + valueContent.className = 'text-sm font-medium'; + valueContent.textContent = annotation.name || 'unknown'; + + value.appendChild(valueLabel); + value.appendChild(valueContent); + item.appendChild(value); + + const clientInfo = document.createElement('div'); + clientInfo.className = 'flex items-center mt-2'; + + const clientLabel = document.createElement('span'); + clientLabel.className = 'text-xs text-gray-500 mr-2'; + clientLabel.textContent = 'From:'; + + clientInfo.appendChild(clientLabel); + clientInfo.appendChild(createClientBadge(annotation.clientId || 'unknown', color)); + + item.appendChild(clientInfo); + + return item; +} + +export function createAnnotationsListElement(messageSerial: string) { + const container = document.createElement('div'); + container.className = 'bg-white shadow-sm rounded-lg p-4 mb-4'; + container.id = `annotations-container-${messageSerial}`; + + const annotationsList = document.createElement('div'); + annotationsList.className = 'space-y-2 max-h-80 overflow-y-auto'; + annotationsList.id = `annotations-list-${messageSerial}`; + annotationsList.setAttribute('data-message-serial', messageSerial); + + const emptyState = document.createElement('div'); + emptyState.className = 'text-center p-4 text-gray-500 text-sm'; + emptyState.textContent = 'No annotations received yet.'; + emptyState.id = `annotations-empty-${messageSerial}`; + + annotationsList.appendChild(emptyState); + container.appendChild(annotationsList); + + return container; +} + +export function addAnnotation(annotation: Annotation) { + const messageSerial = annotation.messageSerial; + const listContainer = document.getElementById(`annotations-list-${messageSerial}`); + + if (!listContainer) { + return; + } + + const existingAnnotation = document.querySelector(`[data-id="${annotation.id}"]`); + if (existingAnnotation) { + return; + } + + const emptyState = document.getElementById(`annotations-empty-${messageSerial}`); + if (emptyState) { + emptyState.remove(); + } + + const annotationItem = createAnnotationItem(annotation); + + let inserted = false; + const existingItems = listContainer.querySelectorAll('[data-timestamp]'); + + for (const item of existingItems) { + const itemTimestamp = parseInt(item.getAttribute('data-timestamp') || '0'); + if (annotation.timestamp > itemTimestamp) { + listContainer.insertBefore(annotationItem, item); + inserted = true; + break; + } + } + + if (!inserted) { + listContainer.appendChild(annotationItem); + } +} diff --git a/examples/pub-sub-message-annotations/javascript/src/components/details.ts b/examples/pub-sub-message-annotations/javascript/src/components/details.ts index 370e60b989..613b095564 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/details.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/details.ts @@ -1,10 +1,10 @@ -// Expandable details panel for messages that supports publishing -// annotations and viewing annotation summaries. +// Details panel with publishing controls and tabbed annotations view import { MessageCreate } from '../types'; import { annotationNamespace } from '../config'; import { publishAnnotation } from '../ably'; import { createAnnotationSummaryElement } from './summary'; +import { createAnnotationsListElement } from './annotations'; export function createPublishAnnotationElement(message: MessageCreate) { const publisher = document.createElement('div'); @@ -33,6 +33,7 @@ export function createPublishAnnotationElement(message: MessageCreate) { const annotationType = selectInput.options[selectInput.selectedIndex].value; const nameInput = publisher.querySelector('input') as HTMLInputElement; const name = nameInput.value.trim(); + if (name) { publishAnnotation(message, { type: `${annotationNamespace}:${annotationType}`, @@ -47,11 +48,69 @@ export function createPublishAnnotationElement(message: MessageCreate) { export function createMessageDetailsElement(message: MessageCreate) { const messageDetails = document.createElement('div'); - messageDetails.className = `grid grid-cols-1 gap-4`; + messageDetails.className = 'grid grid-cols-1 gap-4'; + const publishAnnotation = createPublishAnnotationElement(message); - const annotationSummary = createAnnotationSummaryElement(message); messageDetails.appendChild(publishAnnotation); - messageDetails.appendChild(annotationSummary); + + const tabContainer = document.createElement('div'); + tabContainer.className = 'bg-white shadow-sm rounded-lg mb-4 overflow-hidden'; + + const tabList = document.createElement('ul'); + tabList.className = 'uk-tab'; + tabList.setAttribute('data-uk-tab', ''); + + const summaryTabItem = document.createElement('li'); + summaryTabItem.className = 'uk-active'; + const summaryLink = document.createElement('a'); + summaryLink.href = '#'; + summaryLink.textContent = 'Summary'; + summaryTabItem.appendChild(summaryLink); + + const rawTabItem = document.createElement('li'); + const rawLink = document.createElement('a'); + rawLink.href = '#'; + rawLink.textContent = 'Raw Annotations'; + rawTabItem.appendChild(rawLink); + + tabList.appendChild(summaryTabItem); + tabList.appendChild(rawTabItem); + + const tabContent = document.createElement('div'); + tabContent.className = 'uk-switcher'; + + const summaryPanel = document.createElement('div'); + summaryPanel.className = 'uk-active p-4'; + summaryPanel.appendChild(createAnnotationSummaryElement(message)); + + const rawPanel = document.createElement('div'); + rawPanel.className = 'p-4'; + rawPanel.appendChild(createAnnotationsListElement(message.serial)); + + tabContent.appendChild(summaryPanel); + tabContent.appendChild(rawPanel); + + tabContainer.appendChild(tabList); + tabContainer.appendChild(tabContent); + + summaryLink.addEventListener('click', (e) => { + e.preventDefault(); + summaryTabItem.className = 'uk-active'; + rawTabItem.className = ''; + summaryPanel.className = 'uk-active p-4'; + rawPanel.className = 'p-4'; + }); + + rawLink.addEventListener('click', (e) => { + e.preventDefault(); + rawTabItem.className = 'uk-active'; + summaryTabItem.className = ''; + rawPanel.className = 'uk-active p-4'; + summaryPanel.className = 'p-4'; + }); + + messageDetails.appendChild(tabContainer); + return messageDetails; } diff --git a/examples/pub-sub-message-annotations/javascript/src/components/message.ts b/examples/pub-sub-message-annotations/javascript/src/components/message.ts index 36a3b5a444..e5bb680b25 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/message.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/message.ts @@ -4,7 +4,7 @@ import { MessageCreate } from '../types'; import { createDropdownArrow, toggleArrowRotation } from './arrow'; import { createDetailsPane } from './details'; -function createMessageElement(message: MessageCreate) { +export function createMessageElement(message: MessageCreate) { const messageContainer = document.createElement('div'); messageContainer.className = 'mb-4'; messageContainer.setAttribute('data-serial', message.serial); @@ -33,8 +33,3 @@ function createMessageElement(message: MessageCreate) { return messageContainer; } - -export function addMessage(message: MessageCreate) { - const messageElement = createMessageElement(message); - document.getElementById('messages')?.appendChild(messageElement); -} diff --git a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts index 24aa3d35c6..976c55a90e 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts @@ -24,11 +24,6 @@ export function createAnnotationSummaryElement(message: MessageCreate) { annotationSummary.id = `summary-container-${message.serial}`; annotationSummary.setAttribute('data-serial', message.serial); - const header = document.createElement('div'); - header.className = 'mb-3'; - header.innerHTML = `

Annotation Summary

`; - annotationSummary.appendChild(header); - const sectionsContainer = document.createElement('div'); sectionsContainer.className = 'space-y-2'; sectionsContainer.id = `sections-${message.serial}`; diff --git a/examples/pub-sub-message-annotations/javascript/src/script.ts b/examples/pub-sub-message-annotations/javascript/src/script.ts index a8f0bc077e..00e9f4197d 100644 --- a/examples/pub-sub-message-annotations/javascript/src/script.ts +++ b/examples/pub-sub-message-annotations/javascript/src/script.ts @@ -2,8 +2,9 @@ import './styles.css'; import * as Ably from 'ably'; import { getChannel } from './ably'; import { MessageSummary, MessageCreate } from './types'; -import { addMessage } from './components/message'; +import { createMessageElement } from './components/message'; import { updateAnnotationSummary } from './components/summary'; +import { addAnnotation } from './components/annotations'; async function main() { // Publish regular messages that can be annotated. @@ -25,9 +26,15 @@ async function main() { if (message.action === 'message.summary') { updateAnnotationSummary(message as MessageSummary); } else if (message.action === 'message.create') { - addMessage(message as MessageCreate); + const messageElement = createMessageElement(message as MessageCreate); + document.getElementById('messages')?.appendChild(messageElement); } }); + + // Subscribe to individual annotations and display them in the raw annotations view + getChannel().annotations.subscribe((annotation: Ably.Annotation) => { + addAnnotation(annotation); + }); } main().catch(console.error); From 22c822cddd3893889bd902525d2d68c381e2cb3b Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Tue, 27 May 2025 18:20:21 +0100 Subject: [PATCH 09/15] examples/annotations: misc styling fixes --- .../javascript/src/components/badge.ts | 4 +- .../javascript/src/components/message.ts | 73 ++++++++++- .../javascript/src/components/summary.ts | 121 +++++++++++++----- 3 files changed, 158 insertions(+), 40 deletions(-) diff --git a/examples/pub-sub-message-annotations/javascript/src/components/badge.ts b/examples/pub-sub-message-annotations/javascript/src/components/badge.ts index 3508a8b2c5..76ad8fdb12 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/badge.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/badge.ts @@ -34,7 +34,7 @@ export function createClientBadgeWithCount(clientId: string, count: number, colo export function createClientBadges(clients: string[], color: string) { const badges = document.createElement('div'); - badges.className = `mt-2 flex flex-wrap gap-1`; + badges.className = 'flex flex-wrap gap-1'; for (const id of clients) { const badge = createClientBadge(id, color); badges.appendChild(badge); @@ -44,7 +44,7 @@ export function createClientBadges(clients: string[], color: string) { export function createClientBadgesWithCounts(clientIds: Record, color: string) { const container = document.createElement('div'); - container.className = 'flex flex-wrap gap-2 mt-2'; + container.className = 'flex flex-wrap gap-2'; for (const [clientId, count] of Object.entries(clientIds)) { const badge = createClientBadgeWithCount(clientId, count, color); diff --git a/examples/pub-sub-message-annotations/javascript/src/components/message.ts b/examples/pub-sub-message-annotations/javascript/src/components/message.ts index e5bb680b25..57c816f18a 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/message.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/message.ts @@ -3,31 +3,96 @@ import { MessageCreate } from '../types'; import { createDropdownArrow, toggleArrowRotation } from './arrow'; import { createDetailsPane } from './details'; +import { createClientBadge } from './badge'; + +// Format timestamp for human-readable display +function formatTimestamp(timestamp: number): string { + const date = new Date(timestamp); + return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }); +} export function createMessageElement(message: MessageCreate) { const messageContainer = document.createElement('div'); messageContainer.className = 'mb-4'; messageContainer.setAttribute('data-serial', message.serial); + // Main message element that can be clicked to expand const messageElement = document.createElement('div'); - messageElement.className = `flex justify-between items-center p-4 border rounded-lg bg-white shadow-md cursor-pointer`; + messageElement.className = `flex flex-col p-4 border rounded-lg bg-white shadow-md cursor-pointer`; messageElement.id = `message-${message.id}`; + // Create header row with clientId and timestamp + const headerRow = document.createElement('div'); + headerRow.className = 'flex justify-between items-center mb-2'; + + // Client info with "From:" label + const clientContainer = document.createElement('div'); + clientContainer.className = 'flex items-center'; + + const clientLabel = document.createElement('span'); + clientLabel.className = 'text-xs text-gray-500 mr-2'; + clientLabel.textContent = 'From:'; + + clientContainer.appendChild(clientLabel); + clientContainer.appendChild(createClientBadge(message.clientId || 'unknown', 'blue')); + + // Timestamp with label + const timestampContainer = document.createElement('div'); + timestampContainer.className = 'flex items-center'; + + const timestampLabel = document.createElement('span'); + timestampLabel.className = 'text-xs text-gray-500 mr-1'; + timestampLabel.textContent = 'Time:'; + + const timestampValue = document.createElement('span'); + timestampValue.className = 'text-xs text-gray-600'; + timestampValue.textContent = formatTimestamp(message.timestamp); + + timestampContainer.appendChild(timestampLabel); + timestampContainer.appendChild(timestampValue); + + headerRow.appendChild(clientContainer); + headerRow.appendChild(timestampContainer); + messageElement.appendChild(headerRow); + + // Create content row with message text and dropdown arrow + const contentRow = document.createElement('div'); + contentRow.className = 'flex justify-between items-center'; + + // Message content with "Message:" label + const messageContentContainer = document.createElement('div'); + messageContentContainer.className = 'flex items-center'; + + const messageLabel = document.createElement('span'); + messageLabel.className = 'text-xs text-gray-500 mr-2'; + messageLabel.textContent = 'Message:'; + const textContent = document.createElement('span'); + textContent.className = 'text-sm font-medium'; textContent.textContent = message.data; - messageElement.appendChild(textContent); - + + messageContentContainer.appendChild(messageLabel); + messageContentContainer.appendChild(textContent); + + contentRow.appendChild(messageContentContainer); + + // Add dropdown arrow const arrow = createDropdownArrow('gray'); - messageElement.appendChild(arrow); + contentRow.appendChild(arrow); + + messageElement.appendChild(contentRow); + // Create the expandable details pane const detailsPane = createDetailsPane(message); detailsPane.classList.add('hidden'); + // Add click handler to toggle details messageElement.addEventListener('click', () => { detailsPane.classList.toggle('hidden'); toggleArrowRotation(arrow); }); + // Add all elements to the container messageContainer.appendChild(messageElement); messageContainer.appendChild(detailsPane); diff --git a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts index 976c55a90e..b3cdd76e29 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts @@ -20,16 +20,11 @@ function createEmptyAnnotationSummaryContentElement() { export function createAnnotationSummaryElement(message: MessageCreate) { const annotationSummary = document.createElement('div'); - annotationSummary.className = 'bg-white shadow-sm rounded-lg p-4 mb-4'; - annotationSummary.id = `summary-container-${message.serial}`; + annotationSummary.className = 'space-y-2 p-4'; + annotationSummary.id = `sections-${message.serial}`; annotationSummary.setAttribute('data-serial', message.serial); + annotationSummary.appendChild(createEmptyAnnotationSummaryContentElement()); - const sectionsContainer = document.createElement('div'); - sectionsContainer.className = 'space-y-2'; - sectionsContainer.id = `sections-${message.serial}`; - sectionsContainer.appendChild(createEmptyAnnotationSummaryContentElement()); - - annotationSummary.appendChild(sectionsContainer); return annotationSummary; } @@ -84,7 +79,20 @@ function createSectionHeader(key: string, entry: Ably.SummaryEntry) { function createFlagCard(entry: Ably.SummaryClientIdList, color: string) { const content = document.createElement('div'); content.className = `p-3 bg-white border-t border-${color}-200`; - content.appendChild(createClientBadges(entry.clientIds, color)); + + const fromContainer = document.createElement('div'); + fromContainer.className = 'flex items-center'; + + const fromLabel = document.createElement('span'); + fromLabel.className = 'text-xs text-gray-500 mr-2'; + fromLabel.textContent = 'From:'; + + fromContainer.appendChild(fromLabel); + + const badgesContainer = createClientBadges(entry.clientIds, color); + fromContainer.appendChild(badgesContainer); + + content.appendChild(fromContainer); return content; } @@ -92,18 +100,44 @@ function createDistinctUniqueCard(value: string, entry: Ably.SummaryClientIdList const card = document.createElement('div'); card.className = `p-3 border-t border-${color}-200`; - const header = document.createElement('div'); - header.className = 'flex justify-between items-center'; + const valueSection = document.createElement('div'); + valueSection.className = 'mb-2'; + + const valueHeaderRow = document.createElement('div'); + valueHeaderRow.className = 'flex justify-between items-center'; + + const valueContainer = document.createElement('div'); + valueContainer.className = 'flex items-center'; const valueLabel = document.createElement('span'); - valueLabel.className = `text-sm font-medium text-${color}-800`; - valueLabel.textContent = value; + valueLabel.className = 'text-xs text-gray-500 mr-1'; + valueLabel.textContent = 'Value:'; + + const valueContent = document.createElement('span'); + valueContent.className = `text-sm font-medium text-${color}-800`; + valueContent.textContent = value; + + valueContainer.appendChild(valueLabel); + valueContainer.appendChild(valueContent); + + valueHeaderRow.appendChild(valueContainer); + valueHeaderRow.appendChild(createCountBadge(entry.total, color)); + valueSection.appendChild(valueHeaderRow); + card.appendChild(valueSection); + + const fromContainer = document.createElement('div'); + fromContainer.className = 'flex items-center'; + + const fromLabel = document.createElement('span'); + fromLabel.className = 'text-xs text-gray-500 mr-2'; + fromLabel.textContent = 'From:'; - header.appendChild(valueLabel); - header.appendChild(createCountBadge(entry.total, color)); + fromContainer.appendChild(fromLabel); - card.appendChild(header); - card.appendChild(createClientBadges(entry.clientIds, color)); + const badgesContainer = createClientBadges(entry.clientIds, color); + fromContainer.appendChild(badgesContainer); + + card.appendChild(fromContainer); return card; } @@ -112,25 +146,49 @@ function createMultipleCard(value: string, entry: Ably.SummaryMultipleValues[str const card = document.createElement('div'); card.className = `p-3 border-t border-${color}-200`; - const header = document.createElement('div'); - header.className = 'flex justify-between items-center'; + const valueSection = document.createElement('div'); + valueSection.className = 'mb-3'; + + const valueHeaderRow = document.createElement('div'); + valueHeaderRow.className = 'flex justify-between items-center'; + + const valueContainer = document.createElement('div'); + valueContainer.className = 'flex items-center'; const valueLabel = document.createElement('span'); - valueLabel.className = `text-sm font-medium text-${color}-800`; - valueLabel.textContent = value; + valueLabel.className = 'text-xs text-gray-500 mr-1'; + valueLabel.textContent = 'Value:'; + + const valueContent = document.createElement('span'); + valueContent.className = `text-sm font-medium text-${color}-800`; + valueContent.textContent = value; + + valueContainer.appendChild(valueLabel); + valueContainer.appendChild(valueContent); + + valueHeaderRow.appendChild(valueContainer); + valueHeaderRow.appendChild(createCountBadge(entry.total, color)); + valueSection.appendChild(valueHeaderRow); + card.appendChild(valueSection); - header.appendChild(valueLabel); - header.appendChild(createCountBadge(entry.total, color)); - card.appendChild(header); + const fromContainer = document.createElement('div'); + fromContainer.className = 'flex items-start'; - const clientBadgesContainer = document.createElement('div'); - clientBadgesContainer.className = 'mt-2'; - clientBadgesContainer.appendChild(createClientBadgesWithCounts(entry.clientIds || {}, color)); - card.appendChild(clientBadgesContainer); + const fromLabel = document.createElement('span'); + fromLabel.className = 'text-xs text-gray-500 mr-2'; + fromLabel.textContent = 'From:'; + + fromContainer.appendChild(fromLabel); + + const badgesContainer = document.createElement('div'); + badgesContainer.className = 'flex-1'; + badgesContainer.appendChild(createClientBadgesWithCounts(entry.clientIds || {}, color)); + fromContainer.appendChild(badgesContainer); + + card.appendChild(fromContainer); if (entry.totalUnidentified > 0) { const unidentifiedContainer = document.createElement('div'); - unidentifiedContainer.className = 'mt-2'; unidentifiedContainer.appendChild(createClientBadgeWithCount('Unidentified', entry.totalUnidentified, color)); card.appendChild(unidentifiedContainer); } @@ -200,11 +258,6 @@ export function createSection(key: string, entry: Ably.SummaryEntry, wasExpanded } export function updateAnnotationSummary(message: MessageSummary) { - const summaryContainer = document.getElementById(`summary-container-${message.serial}`); - if (!summaryContainer) { - return; - } - const sectionsContainer = document.getElementById(`sections-${message.serial}`); if (!sectionsContainer) { return; From 2f474f0507868903e6af38f439d76c193b947433 Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Wed, 28 May 2025 11:43:25 +0100 Subject: [PATCH 10/15] examples/annotations: support delete annotations Adds a delete button to raw annotations to publish a delete annotation which removes the annotation from the summary. Refactors the raw annotation view to display in a more compact format. --- .../javascript/src/ably.ts | 4 + .../javascript/src/components/annotations.ts | 124 ++++++++++-------- .../javascript/src/components/badge.ts | 12 +- .../javascript/src/components/message.ts | 4 +- .../javascript/src/components/summary.ts | 7 +- .../javascript/src/script.ts | 2 + .../javascript/tailwind.config.ts | 6 +- 7 files changed, 88 insertions(+), 71 deletions(-) diff --git a/examples/pub-sub-message-annotations/javascript/src/ably.ts b/examples/pub-sub-message-annotations/javascript/src/ably.ts index dd9a8d7bf8..1c334e2220 100644 --- a/examples/pub-sub-message-annotations/javascript/src/ably.ts +++ b/examples/pub-sub-message-annotations/javascript/src/ably.ts @@ -23,3 +23,7 @@ export function getChannel() { export function publishAnnotation(message: MessageCreate, annotation: Ably.OutboundAnnotation) { return getChannel().annotations.publish(message, annotation); } + +export function deleteAnnotation(serial: string, annotation: Ably.OutboundAnnotation) { + return getChannel().annotations.delete(serial, annotation); +} diff --git a/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts b/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts index cfb2eb6c9e..8543d2cdc9 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts @@ -2,7 +2,8 @@ import type { Annotation } from 'ably'; import { findAnnotationType } from '../config'; -import { createClientBadge } from './badge'; +import { createBadge } from './badge'; +import { deleteAnnotation } from '../ably'; function formatTimestamp(timestamp: number): string { const date = new Date(timestamp); @@ -22,74 +23,89 @@ function createAnnotationItem(annotation: Annotation) { const { color, label } = findAnnotationType(typeKey); const item = document.createElement('div'); - item.className = `mb-2 p-3 border border-${color}-200 rounded-md bg-white shadow-sm`; + item.className = `mb-2 pl-3 pr-2 py-2 border-l-4 border-l-${color}-500 border-y border-r border-gray-200 rounded-r-md bg-white shadow-sm flex flex-wrap items-center`; item.setAttribute('data-id', annotation.id); item.setAttribute('data-timestamp', annotation.timestamp.toString()); - - const header = document.createElement('div'); - header.className = 'flex justify-between items-center mb-2'; - - const typeLabel = document.createElement('div'); + item.setAttribute('data-serial', annotation.messageSerial); + item.setAttribute('data-action', annotation.action || ''); + + // First row: type, value (left aligned) and delete button (right aligned) + const firstRow = document.createElement('div'); + firstRow.className = 'flex justify-between items-center w-full'; + + const leftContent = document.createElement('div'); + leftContent.className = 'flex items-center gap-2 min-w-0 flex-grow'; + + const typeLabel = document.createElement('span'); typeLabel.className = `text-sm font-medium text-${color}-800`; typeLabel.textContent = label; + leftContent.appendChild(typeLabel); + + const valueContent = document.createElement('span'); + valueContent.className = 'text-sm text-gray-700 overflow-hidden text-ellipsis'; + valueContent.textContent = annotation.name || 'unknown'; + leftContent.appendChild(valueContent); + + firstRow.appendChild(leftContent); + + if (annotation.action !== 'annotation.delete') { + const deleteIcon = document.createElement('div'); + deleteIcon.className = `size-4 text-red-500 hover:text-red-800 cursor-pointer shrink-0 ml-auto`; + deleteIcon.innerHTML = ``; + deleteIcon.addEventListener('click', () => { + deleteAnnotation(annotation.messageSerial, annotation); + }); + firstRow.appendChild(deleteIcon); + } - const timestamp = document.createElement('div'); - timestamp.className = 'text-xs text-gray-500'; - timestamp.textContent = formatTimestamp(annotation.timestamp); - - header.appendChild(typeLabel); - header.appendChild(timestamp); - item.appendChild(header); - - const value = document.createElement('div'); - value.className = 'mb-2'; + item.appendChild(firstRow); - const valueLabel = document.createElement('span'); - valueLabel.className = 'text-xs text-gray-500 mr-1'; - valueLabel.textContent = 'Value:'; + // Second row: action (left aligned) and client ID with timestamp (right aligned) + const secondRow = document.createElement('div'); + secondRow.className = 'flex justify-between items-center w-full mt-1'; - const valueContent = document.createElement('span'); - valueContent.className = 'text-sm font-medium'; - valueContent.textContent = annotation.name || 'unknown'; + let action = 'CREATE'; + let actionColor = 'green'; + if (annotation.action === 'annotation.delete') { + action = 'DELETE'; + actionColor = 'red'; + } + const actionBadge = createBadge(action, actionColor); + secondRow.appendChild(actionBadge); - value.appendChild(valueLabel); - value.appendChild(valueContent); - item.appendChild(value); + const rightContent = document.createElement('div'); + rightContent.className = 'flex items-center gap-2 ml-auto shrink-0'; - const clientInfo = document.createElement('div'); - clientInfo.className = 'flex items-center mt-2'; + const clientBadge = createBadge(annotation.clientId || 'unknown', color); + clientBadge.classList.add('shrink-0'); + rightContent.appendChild(clientBadge); - const clientLabel = document.createElement('span'); - clientLabel.className = 'text-xs text-gray-500 mr-2'; - clientLabel.textContent = 'From:'; + const timestamp = document.createElement('div'); + timestamp.className = 'text-xs text-gray-500'; + timestamp.textContent = formatTimestamp(annotation.timestamp); + rightContent.appendChild(timestamp); - clientInfo.appendChild(clientLabel); - clientInfo.appendChild(createClientBadge(annotation.clientId || 'unknown', color)); + secondRow.appendChild(rightContent); - item.appendChild(clientInfo); + item.appendChild(secondRow); return item; } export function createAnnotationsListElement(messageSerial: string) { - const container = document.createElement('div'); - container.className = 'bg-white shadow-sm rounded-lg p-4 mb-4'; - container.id = `annotations-container-${messageSerial}`; - const annotationsList = document.createElement('div'); - annotationsList.className = 'space-y-2 max-h-80 overflow-y-auto'; + annotationsList.className = 'space-y-1 max-h-80 overflow-y-auto'; annotationsList.id = `annotations-list-${messageSerial}`; annotationsList.setAttribute('data-message-serial', messageSerial); const emptyState = document.createElement('div'); - emptyState.className = 'text-center p-4 text-gray-500 text-sm'; + emptyState.className = 'text-center p-2 text-gray-500 text-sm'; emptyState.textContent = 'No annotations received yet.'; emptyState.id = `annotations-empty-${messageSerial}`; annotationsList.appendChild(emptyState); - container.appendChild(annotationsList); - return container; + return annotationsList; } export function addAnnotation(annotation: Annotation) { @@ -100,7 +116,8 @@ export function addAnnotation(annotation: Annotation) { return; } - const existingAnnotation = document.querySelector(`[data-id="${annotation.id}"]`); + // Check if we already have an annotation with the same ID and action + const existingAnnotation = document.querySelector(`[data-id="${annotation.id}"][data-action="${annotation.action || ''}"]`); if (existingAnnotation) { return; } @@ -111,20 +128,11 @@ export function addAnnotation(annotation: Annotation) { } const annotationItem = createAnnotationItem(annotation); - - let inserted = false; - const existingItems = listContainer.querySelectorAll('[data-timestamp]'); - - for (const item of existingItems) { - const itemTimestamp = parseInt(item.getAttribute('data-timestamp') || '0'); - if (annotation.timestamp > itemTimestamp) { - listContainer.insertBefore(annotationItem, item); - inserted = true; - break; - } - } - - if (!inserted) { - listContainer.appendChild(annotationItem); + + // Add at the beginning (newest first) + if (listContainer.firstChild) { + listContainer.insertBefore(annotationItem, listContainer.firstChild); + return; } + listContainer.appendChild(annotationItem); } diff --git a/examples/pub-sub-message-annotations/javascript/src/components/badge.ts b/examples/pub-sub-message-annotations/javascript/src/components/badge.ts index 76ad8fdb12..fac071d2d6 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/badge.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/badge.ts @@ -8,20 +8,20 @@ export function createCountBadge(count: number, color: string, isRounded = true) return badge; } -export function createClientBadge(clientId: string, color: string) { +export function createBadge(name: string, color: string) { const badge = document.createElement('span'); badge.className = `inline-flex items-center px-2 py-0.5 rounded-full text-xs bg-${color}-100 text-${color}-800`; - badge.textContent = clientId; + badge.textContent = name; return badge; } -export function createClientBadgeWithCount(clientId: string, count: number, color: string) { +export function createBadgeWithCount(name: string, count: number, color: string) { const badgeGroup = document.createElement('div'); badgeGroup.className = 'inline-flex rounded-full overflow-hidden text-xs font-medium shadow-sm'; const clientIdPart = document.createElement('span'); clientIdPart.className = `px-2 py-0.5 bg-${color}-100 text-${color}-800`; - clientIdPart.textContent = clientId; + clientIdPart.textContent = name; const countPart = document.createElement('span'); countPart.className = `px-1.5 py-0.5 bg-${color}-400 text-white`; @@ -36,7 +36,7 @@ export function createClientBadges(clients: string[], color: string) { const badges = document.createElement('div'); badges.className = 'flex flex-wrap gap-1'; for (const id of clients) { - const badge = createClientBadge(id, color); + const badge = createBadge(id, color); badges.appendChild(badge); } return badges; @@ -47,7 +47,7 @@ export function createClientBadgesWithCounts(clientIds: Record, container.className = 'flex flex-wrap gap-2'; for (const [clientId, count] of Object.entries(clientIds)) { - const badge = createClientBadgeWithCount(clientId, count, color); + const badge = createBadgeWithCount(clientId, count, color); container.appendChild(badge); } diff --git a/examples/pub-sub-message-annotations/javascript/src/components/message.ts b/examples/pub-sub-message-annotations/javascript/src/components/message.ts index 57c816f18a..4d781f902b 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/message.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/message.ts @@ -3,7 +3,7 @@ import { MessageCreate } from '../types'; import { createDropdownArrow, toggleArrowRotation } from './arrow'; import { createDetailsPane } from './details'; -import { createClientBadge } from './badge'; +import { createBadge } from './badge'; // Format timestamp for human-readable display function formatTimestamp(timestamp: number): string { @@ -34,7 +34,7 @@ export function createMessageElement(message: MessageCreate) { clientLabel.textContent = 'From:'; clientContainer.appendChild(clientLabel); - clientContainer.appendChild(createClientBadge(message.clientId || 'unknown', 'blue')); + clientContainer.appendChild(createBadge(message.clientId || 'unknown', 'blue')); // Timestamp with label const timestampContainer = document.createElement('div'); diff --git a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts index b3cdd76e29..cc878fb1be 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts @@ -8,7 +8,7 @@ import { createCountBadge, createClientBadges, createClientBadgesWithCounts, - createClientBadgeWithCount, + createBadgeWithCount, } from './badge'; function createEmptyAnnotationSummaryContentElement() { @@ -189,7 +189,7 @@ function createMultipleCard(value: string, entry: Ably.SummaryMultipleValues[str if (entry.totalUnidentified > 0) { const unidentifiedContainer = document.createElement('div'); - unidentifiedContainer.appendChild(createClientBadgeWithCount('Unidentified', entry.totalUnidentified, color)); + unidentifiedContainer.appendChild(createBadgeWithCount('Unidentified', entry.totalUnidentified, color)); card.appendChild(unidentifiedContainer); } @@ -273,8 +273,7 @@ export function updateAnnotationSummary(message: MessageSummary) { } sectionsContainer.innerHTML = ''; - - const hasAnnotations = annotationTypes.some((type) => message.summary[`${annotationNamespace}:${type.key}`]); + const hasAnnotations = annotationTypes.some((type) => message.summary && message.summary[`${annotationNamespace}:${type.key}`]); if (!hasAnnotations) { sectionsContainer.appendChild(createEmptyAnnotationSummaryContentElement()); diff --git a/examples/pub-sub-message-annotations/javascript/src/script.ts b/examples/pub-sub-message-annotations/javascript/src/script.ts index 00e9f4197d..cdf7f101e7 100644 --- a/examples/pub-sub-message-annotations/javascript/src/script.ts +++ b/examples/pub-sub-message-annotations/javascript/src/script.ts @@ -1,4 +1,6 @@ import './styles.css'; +import 'franken-ui/js/core.iife'; +import 'franken-ui/js/icon.iife'; import * as Ably from 'ably'; import { getChannel } from './ably'; import { MessageSummary, MessageCreate } from './types'; diff --git a/examples/pub-sub-message-annotations/javascript/tailwind.config.ts b/examples/pub-sub-message-annotations/javascript/tailwind.config.ts index a80a6b7000..3eb1ffa37d 100644 --- a/examples/pub-sub-message-annotations/javascript/tailwind.config.ts +++ b/examples/pub-sub-message-annotations/javascript/tailwind.config.ts @@ -5,8 +5,12 @@ const config: Config = { ...baseConfig, content: ['./src/**/*.{js,ts,tsx}', './index.html'], safelist: [ + // allow dynamic classes for colors { - pattern: /(bg|text|border)-(blue|green|purple|amber|red|gray)-(50|100|200|300|400|500|600|700|800|900)/, // allow dynamic classes for colors + pattern: /(bg|text|border)-(blue|green|purple|amber|red|gray)-(50|100|200|300|400|500|600|700|800|900)/, + }, + { + pattern: /border-(l|t|r|b)-(blue|green|purple|amber|red|gray)-(50|100|200|300|400|500|600|700|800|900)/, }, ], }; From 92bdac12729cbf43f788c21315160cc3ff421e28 Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Wed, 28 May 2025 11:59:58 +0100 Subject: [PATCH 11/15] examples/annotations: misc visual improvements Various improvements to the components and styling to create a more compact visual style. --- .../javascript/index.html | 2 +- .../javascript/src/ably.ts | 9 +- .../javascript/src/components/annotations.ts | 30 ++- .../javascript/src/components/details.ts | 35 ++- .../javascript/src/components/message.ts | 92 +++----- .../javascript/src/components/summary.ts | 207 ++++++++---------- .../javascript/src/config.ts | 5 +- .../javascript/src/script.ts | 6 +- .../javascript/src/types.ts | 1 + .../javascript/tailwind.config.ts | 4 +- 10 files changed, 173 insertions(+), 218 deletions(-) diff --git a/examples/pub-sub-message-annotations/javascript/index.html b/examples/pub-sub-message-annotations/javascript/index.html index fcb67a3b58..9dccae7e19 100644 --- a/examples/pub-sub-message-annotations/javascript/index.html +++ b/examples/pub-sub-message-annotations/javascript/index.html @@ -11,7 +11,7 @@
-
+
diff --git a/examples/pub-sub-message-annotations/javascript/src/ably.ts b/examples/pub-sub-message-annotations/javascript/src/ably.ts index 1c334e2220..0a2037335f 100644 --- a/examples/pub-sub-message-annotations/javascript/src/ably.ts +++ b/examples/pub-sub-message-annotations/javascript/src/ably.ts @@ -2,8 +2,10 @@ import * as Ably from 'ably'; import { clientId, channelName } from './config'; import { MessageCreate } from './types'; +// Singleton Ably client instance let client: Ably.Realtime | null = null; +// Lazily creates and returns the Ably client instance with configured clientId function getClient(): Ably.Realtime { if (!client) { client = new Ably.Realtime({ @@ -14,16 +16,19 @@ function getClient(): Ably.Realtime { return client; } +// Returns the configured channel with all annotation modes enabled export function getChannel() { return getClient().channels.get(channelName, { modes: ['PUBLISH', 'SUBSCRIBE', 'ANNOTATION_PUBLISH', 'ANNOTATION_SUBSCRIBE'], }); } +// Publishes a new annotation for a specific message export function publishAnnotation(message: MessageCreate, annotation: Ably.OutboundAnnotation) { return getChannel().annotations.publish(message, annotation); } -export function deleteAnnotation(serial: string, annotation: Ably.OutboundAnnotation) { - return getChannel().annotations.delete(serial, annotation); +// Deletes a specific annotation from a message +export function deleteAnnotation(messageSerial: string, annotation: Ably.OutboundAnnotation) { + return getChannel().annotations.delete(messageSerial, annotation); } diff --git a/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts b/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts index 8543d2cdc9..7283aa2d00 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/annotations.ts @@ -1,4 +1,4 @@ -// Display of raw annotation messages +// Components for displaying and managing raw annotation messages import type { Annotation } from 'ably'; import { findAnnotationType } from '../config'; @@ -10,7 +10,8 @@ function formatTimestamp(timestamp: number): string { return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }); } -function getAnnotationTypeKey(fullType: string): string { +// Extracts the type key from a namespaced annotation type string (e.g. "my-annotations:total.v1" → "total.v1") +export function getAnnotationTypeKey(fullType: string): string { const parts = fullType.split(':'); if (parts.length > 1) { return parts[1]; @@ -18,12 +19,15 @@ function getAnnotationTypeKey(fullType: string): string { return fullType; } +// Component to display a single annotation with all its details +// Includes the annotation type, value, action, client ID, timestamp, and +// a delete button for annotations with an annotation.create action function createAnnotationItem(annotation: Annotation) { const typeKey = getAnnotationTypeKey(annotation.type); const { color, label } = findAnnotationType(typeKey); const item = document.createElement('div'); - item.className = `mb-2 pl-3 pr-2 py-2 border-l-4 border-l-${color}-500 border-y border-r border-gray-200 rounded-r-md bg-white shadow-sm flex flex-wrap items-center`; + item.className = `pl-3 pr-2 py-2 border-l-4 border-l-${color}-500 border-y border-r border-gray-200 bg-white shadow-sm flex flex-wrap items-center`; item.setAttribute('data-id', annotation.id); item.setAttribute('data-timestamp', annotation.timestamp.toString()); item.setAttribute('data-serial', annotation.messageSerial); @@ -32,15 +36,15 @@ function createAnnotationItem(annotation: Annotation) { // First row: type, value (left aligned) and delete button (right aligned) const firstRow = document.createElement('div'); firstRow.className = 'flex justify-between items-center w-full'; - + const leftContent = document.createElement('div'); leftContent.className = 'flex items-center gap-2 min-w-0 flex-grow'; - + const typeLabel = document.createElement('span'); typeLabel.className = `text-sm font-medium text-${color}-800`; typeLabel.textContent = label; leftContent.appendChild(typeLabel); - + const valueContent = document.createElement('span'); valueContent.className = 'text-sm text-gray-700 overflow-hidden text-ellipsis'; valueContent.textContent = annotation.name || 'unknown'; @@ -50,9 +54,10 @@ function createAnnotationItem(annotation: Annotation) { if (annotation.action !== 'annotation.delete') { const deleteIcon = document.createElement('div'); - deleteIcon.className = `size-4 text-red-500 hover:text-red-800 cursor-pointer shrink-0 ml-auto`; - deleteIcon.innerHTML = ``; - deleteIcon.addEventListener('click', () => { + deleteIcon.className = 'size-4 text-red-500 hover:text-red-800 cursor-pointer shrink-0 ml-auto'; + deleteIcon.innerHTML = ''; + deleteIcon.addEventListener('click', (e) => { + e.preventDefault(); deleteAnnotation(annotation.messageSerial, annotation); }); firstRow.appendChild(deleteIcon); @@ -76,7 +81,7 @@ function createAnnotationItem(annotation: Annotation) { const rightContent = document.createElement('div'); rightContent.className = 'flex items-center gap-2 ml-auto shrink-0'; - const clientBadge = createBadge(annotation.clientId || 'unknown', color); + const clientBadge = createBadge(annotation.clientId || 'unknown', 'gray'); clientBadge.classList.add('shrink-0'); rightContent.appendChild(clientBadge); @@ -92,6 +97,8 @@ function createAnnotationItem(annotation: Annotation) { return item; } +// Component for listing annotations related to a specific message +// Includes an empty state message that will be removed when annotations are added export function createAnnotationsListElement(messageSerial: string) { const annotationsList = document.createElement('div'); annotationsList.className = 'space-y-1 max-h-80 overflow-y-auto'; @@ -108,6 +115,7 @@ export function createAnnotationsListElement(messageSerial: string) { return annotationsList; } +// Adds a new annotation to the appropriate message's annotation list export function addAnnotation(annotation: Annotation) { const messageSerial = annotation.messageSerial; const listContainer = document.getElementById(`annotations-list-${messageSerial}`); @@ -128,7 +136,7 @@ export function addAnnotation(annotation: Annotation) { } const annotationItem = createAnnotationItem(annotation); - + // Add at the beginning (newest first) if (listContainer.firstChild) { listContainer.insertBefore(annotationItem, listContainer.firstChild); diff --git a/examples/pub-sub-message-annotations/javascript/src/components/details.ts b/examples/pub-sub-message-annotations/javascript/src/components/details.ts index 613b095564..d75acbcebb 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/details.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/details.ts @@ -8,27 +8,24 @@ import { createAnnotationsListElement } from './annotations'; export function createPublishAnnotationElement(message: MessageCreate) { const publisher = document.createElement('div'); - publisher.className = 'md:col-span-2 mb-4'; + publisher.className = 'p-2 border-b border-gray-200 bg-gray-50'; publisher.innerHTML = ` -
-
-
- -
-
- - +
+ + +
`; const publishButton = publisher.querySelector('button'); - publishButton?.addEventListener('click', () => { + publishButton?.addEventListener('click', (e) => { + e.preventDefault(); const selectInput = publisher.querySelector('select') as HTMLSelectElement; const annotationType = selectInput.options[selectInput.selectedIndex].value; const nameInput = publisher.querySelector('input') as HTMLInputElement; @@ -48,13 +45,13 @@ export function createPublishAnnotationElement(message: MessageCreate) { export function createMessageDetailsElement(message: MessageCreate) { const messageDetails = document.createElement('div'); - messageDetails.className = 'grid grid-cols-1 gap-4'; + messageDetails.className = 'grid grid-cols-1'; const publishAnnotation = createPublishAnnotationElement(message); messageDetails.appendChild(publishAnnotation); const tabContainer = document.createElement('div'); - tabContainer.className = 'bg-white shadow-sm rounded-lg mb-4 overflow-hidden'; + tabContainer.className = 'overflow-hidden'; const tabList = document.createElement('ul'); tabList.className = 'uk-tab'; @@ -116,7 +113,7 @@ export function createMessageDetailsElement(message: MessageCreate) { export function createDetailsPane(message: MessageCreate) { const detailsPane = document.createElement('div'); - detailsPane.className = 'mt-2 p-4 border rounded-lg bg-gray-50'; + detailsPane.className = 'border-b border-l border-r border-gray-200 rounded-b-md overflow-hidden bg-white shadow-sm'; detailsPane.id = `details-${message.id}`; const messageDetails = createMessageDetailsElement(message); diff --git a/examples/pub-sub-message-annotations/javascript/src/components/message.ts b/examples/pub-sub-message-annotations/javascript/src/components/message.ts index 4d781f902b..c5a2bbd27f 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/message.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/message.ts @@ -18,76 +18,48 @@ export function createMessageElement(message: MessageCreate) { // Main message element that can be clicked to expand const messageElement = document.createElement('div'); - messageElement.className = `flex flex-col p-4 border rounded-lg bg-white shadow-md cursor-pointer`; + messageElement.className = `px-3 py-2 border-t border-l border-r border-gray-200 rounded-t-md bg-white shadow-sm cursor-pointer`; messageElement.id = `message-${message.id}`; - // Create header row with clientId and timestamp - const headerRow = document.createElement('div'); - headerRow.className = 'flex justify-between items-center mb-2'; - - // Client info with "From:" label - const clientContainer = document.createElement('div'); - clientContainer.className = 'flex items-center'; - - const clientLabel = document.createElement('span'); - clientLabel.className = 'text-xs text-gray-500 mr-2'; - clientLabel.textContent = 'From:'; - - clientContainer.appendChild(clientLabel); - clientContainer.appendChild(createBadge(message.clientId || 'unknown', 'blue')); - - // Timestamp with label - const timestampContainer = document.createElement('div'); - timestampContainer.className = 'flex items-center'; - - const timestampLabel = document.createElement('span'); - timestampLabel.className = 'text-xs text-gray-500 mr-1'; - timestampLabel.textContent = 'Time:'; - - const timestampValue = document.createElement('span'); - timestampValue.className = 'text-xs text-gray-600'; - timestampValue.textContent = formatTimestamp(message.timestamp); - - timestampContainer.appendChild(timestampLabel); - timestampContainer.appendChild(timestampValue); - - headerRow.appendChild(clientContainer); - headerRow.appendChild(timestampContainer); - messageElement.appendChild(headerRow); - - // Create content row with message text and dropdown arrow - const contentRow = document.createElement('div'); - contentRow.className = 'flex justify-between items-center'; - - // Message content with "Message:" label - const messageContentContainer = document.createElement('div'); - messageContentContainer.className = 'flex items-center'; - - const messageLabel = document.createElement('span'); - messageLabel.className = 'text-xs text-gray-500 mr-2'; - messageLabel.textContent = 'Message:'; - - const textContent = document.createElement('span'); - textContent.className = 'text-sm font-medium'; - textContent.textContent = message.data; - - messageContentContainer.appendChild(messageLabel); - messageContentContainer.appendChild(textContent); - - contentRow.appendChild(messageContentContainer); - + // First row: message text (left aligned) and dropdown arrow (right aligned) + const firstRow = document.createElement('div'); + firstRow.className = 'flex justify-between items-center w-full'; + + const messageContent = document.createElement('div'); + messageContent.className = 'flex-grow text-sm font-medium text-gray-700 overflow-hidden text-ellipsis'; + messageContent.textContent = message.data; + firstRow.appendChild(messageContent); + // Add dropdown arrow const arrow = createDropdownArrow('gray'); - contentRow.appendChild(arrow); - - messageElement.appendChild(contentRow); + arrow.classList.add('ml-2', 'shrink-0'); + firstRow.appendChild(arrow); + + messageElement.appendChild(firstRow); + + // Second row: client ID and timestamp (both right aligned) + const secondRow = document.createElement('div'); + secondRow.className = 'flex justify-end items-center w-full mt-1 gap-2'; + + const clientBadge = createBadge(message.clientId || 'unknown', 'gray'); + clientBadge.classList.add('shrink-0'); + + const timestamp = document.createElement('div'); + timestamp.className = 'text-xs text-gray-500'; + timestamp.textContent = formatTimestamp(message.timestamp || Date.now()); + + secondRow.appendChild(clientBadge); + secondRow.appendChild(timestamp); + + messageElement.appendChild(secondRow); // Create the expandable details pane const detailsPane = createDetailsPane(message); detailsPane.classList.add('hidden'); // Add click handler to toggle details - messageElement.addEventListener('click', () => { + messageElement.addEventListener('click', (e) => { + e.preventDefault(); detailsPane.classList.toggle('hidden'); toggleArrowRotation(arrow); }); diff --git a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts index cc878fb1be..899076c2c5 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts @@ -10,17 +10,18 @@ import { createClientBadgesWithCounts, createBadgeWithCount, } from './badge'; +import { getAnnotationTypeKey } from './annotations'; function createEmptyAnnotationSummaryContentElement() { const emptyState = document.createElement('div'); - emptyState.className = 'text-center p-4 text-gray-500 text-sm'; + emptyState.className = 'text-center py-2 text-gray-500 text-sm'; emptyState.textContent = 'Publish an annotation to view summaries.'; return emptyState; } export function createAnnotationSummaryElement(message: MessageCreate) { const annotationSummary = document.createElement('div'); - annotationSummary.className = 'space-y-2 p-4'; + annotationSummary.className = 'space-y-1'; annotationSummary.id = `sections-${message.serial}`; annotationSummary.setAttribute('data-serial', message.serial); annotationSummary.appendChild(createEmptyAnnotationSummaryContentElement()); @@ -33,7 +34,7 @@ function createLabelContainer(label: string, color: string) { container.className = 'flex items-center'; const labelSpan = document.createElement('span'); - labelSpan.className = `text-xs font-medium text-${color}-800`; + labelSpan.className = `text-sm font-medium text-${color}-800`; labelSpan.textContent = label; container.appendChild(labelSpan); @@ -41,35 +42,35 @@ function createLabelContainer(label: string, color: string) { } function createSectionHeader(key: string, entry: Ably.SummaryEntry) { - const { color, label } = findAnnotationType(key); + const typeKey = getAnnotationTypeKey(key); + const { color, label } = findAnnotationType(typeKey); const sectionHeader = document.createElement('div'); - sectionHeader.className = `bg-${color}-50 px-3 py-2${key.endsWith('total.v1') ? '' : ' cursor-pointer'}`; + sectionHeader.className = `border-l-4 border-l-${color}-500 border-t border-r border-gray-200 bg-white shadow-sm px-3 py-1.5 ${typeKey === 'total.v1' ? '' : 'cursor-pointer'}`; const wrapper = document.createElement('div'); wrapper.className = 'flex justify-between items-center'; const labelContainer = createLabelContainer(label, color); - if (key.endsWith('total.v1')) { + if (typeKey === 'total.v1') { const total = (entry as Ably.SummaryTotal).total; - labelContainer.appendChild(createCountBadge(total, color, false)); + labelContainer.appendChild(createCountBadge(total, color)); wrapper.appendChild(labelContainer); - } else if (key.endsWith('flag.v1')) { + } else if (typeKey === 'flag.v1') { const total = (entry as Ably.SummaryClientIdList).total; labelContainer.appendChild(createCountBadge(total, color)); wrapper.appendChild(labelContainer); - wrapper.appendChild(createDropdownArrow(color)); + wrapper.appendChild(createDropdownArrow('gray')); } else { const count = Object.keys(entry).length; labelContainer.appendChild(createCountBadge(count, color)); const valueLabel = document.createElement('span'); - valueLabel.className = `ml-1 text-xs text-${color}-600`; - valueLabel.textContent = `value${count !== 1 ? 's' : ''}`; + valueLabel.className = `ml-1 text-xs text-gray-600`; labelContainer.appendChild(valueLabel); wrapper.appendChild(labelContainer); - wrapper.appendChild(createDropdownArrow(color)); + wrapper.appendChild(createDropdownArrow('gray')); } sectionHeader.appendChild(wrapper); @@ -77,156 +78,123 @@ function createSectionHeader(key: string, entry: Ably.SummaryEntry) { } function createFlagCard(entry: Ably.SummaryClientIdList, color: string) { - const content = document.createElement('div'); - content.className = `p-3 bg-white border-t border-${color}-200`; - - const fromContainer = document.createElement('div'); - fromContainer.className = 'flex items-center'; + const card = document.createElement('div'); + card.className = 'p-3 bg-white flex items-center gap-2'; - const fromLabel = document.createElement('span'); - fromLabel.className = 'text-xs text-gray-500 mr-2'; - fromLabel.textContent = 'From:'; + // Add empty spacer for alignment + const spacer = document.createElement('span'); + spacer.className = 'flex-shrink-0 mr-auto'; + card.appendChild(spacer); - fromContainer.appendChild(fromLabel); + // Add client badges + const badgesContainer = createClientBadges(entry.clientIds, 'gray'); + badgesContainer.className = 'flex flex-wrap gap-1 items-center justify-end'; + card.appendChild(badgesContainer); - const badgesContainer = createClientBadges(entry.clientIds, color); - fromContainer.appendChild(badgesContainer); + // Add count badge + const countBadge = createCountBadge(entry.total, color); + countBadge.className = countBadge.className + ' ml-2 flex-shrink-0'; + card.appendChild(countBadge); - content.appendChild(fromContainer); - return content; + return card; } function createDistinctUniqueCard(value: string, entry: Ably.SummaryClientIdList, color: string) { const card = document.createElement('div'); - card.className = `p-3 border-t border-${color}-200`; - - const valueSection = document.createElement('div'); - valueSection.className = 'mb-2'; - - const valueHeaderRow = document.createElement('div'); - valueHeaderRow.className = 'flex justify-between items-center'; - - const valueContainer = document.createElement('div'); - valueContainer.className = 'flex items-center'; - - const valueLabel = document.createElement('span'); - valueLabel.className = 'text-xs text-gray-500 mr-1'; - valueLabel.textContent = 'Value:'; + card.className = 'p-3 bg-white flex items-center gap-2'; + // Add value text const valueContent = document.createElement('span'); - valueContent.className = `text-sm font-medium text-${color}-800`; + valueContent.className = 'text-sm text-gray-700 flex-shrink-0 mr-auto'; valueContent.textContent = value; + card.appendChild(valueContent); - valueContainer.appendChild(valueLabel); - valueContainer.appendChild(valueContent); + // Add client badges + const badgesContainer = createClientBadges(entry.clientIds, 'gray'); + badgesContainer.className = 'flex flex-wrap gap-1 items-center justify-end'; + card.appendChild(badgesContainer); - valueHeaderRow.appendChild(valueContainer); - valueHeaderRow.appendChild(createCountBadge(entry.total, color)); - valueSection.appendChild(valueHeaderRow); - card.appendChild(valueSection); - - const fromContainer = document.createElement('div'); - fromContainer.className = 'flex items-center'; - - const fromLabel = document.createElement('span'); - fromLabel.className = 'text-xs text-gray-500 mr-2'; - fromLabel.textContent = 'From:'; - - fromContainer.appendChild(fromLabel); - - const badgesContainer = createClientBadges(entry.clientIds, color); - fromContainer.appendChild(badgesContainer); - - card.appendChild(fromContainer); + // Add count badge + const countBadge = createCountBadge(entry.total, color); + countBadge.className = countBadge.className + ' ml-2 flex-shrink-0'; + card.appendChild(countBadge); return card; } function createMultipleCard(value: string, entry: Ably.SummaryMultipleValues[string], color: string) { const card = document.createElement('div'); - card.className = `p-3 border-t border-${color}-200`; - - const valueSection = document.createElement('div'); - valueSection.className = 'mb-3'; - - const valueHeaderRow = document.createElement('div'); - valueHeaderRow.className = 'flex justify-between items-center'; - - const valueContainer = document.createElement('div'); - valueContainer.className = 'flex items-center'; - - const valueLabel = document.createElement('span'); - valueLabel.className = 'text-xs text-gray-500 mr-1'; - valueLabel.textContent = 'Value:'; + card.className = 'p-3 bg-white flex items-center gap-2'; + // Add value text const valueContent = document.createElement('span'); - valueContent.className = `text-sm font-medium text-${color}-800`; + valueContent.className = 'text-sm text-gray-700 flex-shrink-0 mr-auto'; valueContent.textContent = value; + card.appendChild(valueContent); - valueContainer.appendChild(valueLabel); - valueContainer.appendChild(valueContent); - - valueHeaderRow.appendChild(valueContainer); - valueHeaderRow.appendChild(createCountBadge(entry.total, color)); - valueSection.appendChild(valueHeaderRow); - card.appendChild(valueSection); - - const fromContainer = document.createElement('div'); - fromContainer.className = 'flex items-start'; - - const fromLabel = document.createElement('span'); - fromLabel.className = 'text-xs text-gray-500 mr-2'; - fromLabel.textContent = 'From:'; - - fromContainer.appendChild(fromLabel); - - const badgesContainer = document.createElement('div'); - badgesContainer.className = 'flex-1'; - badgesContainer.appendChild(createClientBadgesWithCounts(entry.clientIds || {}, color)); - fromContainer.appendChild(badgesContainer); - - card.appendChild(fromContainer); + // Badge container for client badges + const badgeWrapper = document.createElement('div'); + badgeWrapper.className = 'flex flex-wrap gap-1 items-center justify-end'; + // Add client badges with counts and unidentified badge if needed + badgeWrapper.appendChild(createClientBadgesWithCounts(entry.clientIds || {}, 'gray')); if (entry.totalUnidentified > 0) { - const unidentifiedContainer = document.createElement('div'); - unidentifiedContainer.appendChild(createBadgeWithCount('Unidentified', entry.totalUnidentified, color)); - card.appendChild(unidentifiedContainer); + badgeWrapper.appendChild(createBadgeWithCount('Unidentified', entry.totalUnidentified, 'gray')); } + card.appendChild(badgeWrapper); + + // Add count badge + const countBadge = createCountBadge(entry.total, color); + countBadge.className = countBadge.className + ' ml-2 flex-shrink-0'; + card.appendChild(countBadge); + return card; } -function createSectionContent(typeKey: string, entry: Ably.SummaryEntry) { +function createSectionContent(fullTypeKey: string, entry: Ably.SummaryEntry) { + const typeKey = getAnnotationTypeKey(fullTypeKey); const { color } = findAnnotationType(typeKey); const sectionContent = document.createElement('div'); - sectionContent.className = 'bg-white'; - - if (typeKey.endsWith('flag.v1')) { - sectionContent.appendChild(createFlagCard(entry as Ably.SummaryClientIdList, color)); - } else if (typeKey.endsWith('distinct.v1') || typeKey.endsWith('unique.v1')) { - for (const [value, info] of Object.entries(entry as Ably.SummaryUniqueValues | Ably.SummaryDistinctValues)) { - sectionContent.appendChild(createDistinctUniqueCard(value, info, color)); - } - } else if (typeKey.endsWith('multiple.v1')) { - for (const [value, info] of Object.entries(entry as Ably.SummaryMultipleValues)) { - sectionContent.appendChild(createMultipleCard(value, info, color)); - } + sectionContent.className = `overflow-hidden border-l-4 border-l-${color}-500 border-b border-r border-gray-200`; + + if (typeKey === 'flag.v1') { + const card = createFlagCard(entry as Ably.SummaryClientIdList, color); + sectionContent.appendChild(card); + } else if (typeKey === 'distinct.v1' || typeKey === 'unique.v1') { + const entries = Object.entries(entry as Ably.SummaryUniqueValues | Ably.SummaryDistinctValues); + entries.forEach((entryData, index) => { + const [value, info] = entryData; + const card = createDistinctUniqueCard(value, info, color); + if (index < entries.length - 1) { + card.classList.add('border-b', 'border-gray-100'); + } + sectionContent.appendChild(card); + }); + } else if (typeKey === 'multiple.v1') { + const entries = Object.entries(entry as Ably.SummaryMultipleValues); + entries.forEach((entryData, index) => { + const [value, info] = entryData; + const card = createMultipleCard(value, info, color); + if (index < entries.length - 1) { + card.classList.add('border-b', 'border-gray-100'); + } + sectionContent.appendChild(card); + }); } return sectionContent; } export function createSection(key: string, entry: Ably.SummaryEntry, wasExpanded: boolean) { - const { color } = findAnnotationType(key); - const section = document.createElement('div'); - section.className = `border border-${color}-200 rounded-md overflow-hidden`; section.setAttribute('data-type', key); const sectionHeader = createSectionHeader(key, entry); section.appendChild(sectionHeader); - if (key.endsWith('total.v1')) { + const typeKey = getAnnotationTypeKey(key); + if (typeKey === 'total.v1') { return section; } @@ -245,7 +213,8 @@ export function createSection(key: string, entry: Ably.SummaryEntry, wasExpanded rotateArrow(arrow, shouldExpand); } - sectionHeader.addEventListener('click', () => { + sectionHeader.addEventListener('click', (e) => { + e.preventDefault(); sectionContent.classList.toggle('hidden'); if (arrow instanceof SVGElement) { diff --git a/examples/pub-sub-message-annotations/javascript/src/config.ts b/examples/pub-sub-message-annotations/javascript/src/config.ts index 59b9cfc28b..5ff7fdb2e4 100644 --- a/examples/pub-sub-message-annotations/javascript/src/config.ts +++ b/examples/pub-sub-message-annotations/javascript/src/config.ts @@ -5,12 +5,13 @@ export const annotationNamespace = 'my-annotations'; export const annotationTypes = [ { key: 'total.v1', color: 'blue', label: 'Total' }, - { key: 'distinct.v1', color: 'green', label: 'Distinct' }, + { key: 'distinct.v1', color: 'pink', label: 'Distinct' }, { key: 'unique.v1', color: 'purple', label: 'Unique' }, { key: 'multiple.v1', color: 'amber', label: 'Multiple' }, - { key: 'flag.v1', color: 'red', label: 'Flag' }, + { key: 'flag.v1', color: 'cyan', label: 'Flag' }, ]; +// Looks up an annotation type by key, returning a fallback gray type if not found export function findAnnotationType(key: string) { return annotationTypes.find((type) => type.key === key) || { key, color: 'gray', label: 'Unknown' }; } diff --git a/examples/pub-sub-message-annotations/javascript/src/script.ts b/examples/pub-sub-message-annotations/javascript/src/script.ts index cdf7f101e7..4aff43a5b6 100644 --- a/examples/pub-sub-message-annotations/javascript/src/script.ts +++ b/examples/pub-sub-message-annotations/javascript/src/script.ts @@ -11,7 +11,8 @@ import { addAnnotation } from './components/annotations'; async function main() { // Publish regular messages that can be annotated. const publishButton = document.getElementById('publish-button'); - publishButton?.addEventListener('click', () => { + publishButton?.addEventListener('click', (e) => { + e.preventDefault(); const messageInput = document.getElementById('message-input') as HTMLInputElement; const message = messageInput.value.trim(); if (message) { @@ -33,7 +34,8 @@ async function main() { } }); - // Subscribe to individual annotations and display them in the raw annotations view + // Subscribe to individual annotations (both annotation.create and annotation.delete events) + // and display them in the raw annotations view getChannel().annotations.subscribe((annotation: Ably.Annotation) => { addAnnotation(annotation); }); diff --git a/examples/pub-sub-message-annotations/javascript/src/types.ts b/examples/pub-sub-message-annotations/javascript/src/types.ts index 04930464d5..525a2f5cd9 100644 --- a/examples/pub-sub-message-annotations/javascript/src/types.ts +++ b/examples/pub-sub-message-annotations/javascript/src/types.ts @@ -1,6 +1,7 @@ import type { Message } from 'ably'; export type MessageSummary = Message & Required>; + export type MessageCreate = Message & Required>; export type AnnotationType = { diff --git a/examples/pub-sub-message-annotations/javascript/tailwind.config.ts b/examples/pub-sub-message-annotations/javascript/tailwind.config.ts index 3eb1ffa37d..f6763bb1bb 100644 --- a/examples/pub-sub-message-annotations/javascript/tailwind.config.ts +++ b/examples/pub-sub-message-annotations/javascript/tailwind.config.ts @@ -7,10 +7,10 @@ const config: Config = { safelist: [ // allow dynamic classes for colors { - pattern: /(bg|text|border)-(blue|green|purple|amber|red|gray)-(50|100|200|300|400|500|600|700|800|900)/, + pattern: /(bg|text|border)-(blue|cyan|green|purple|pink|amber|red|gray)-(50|100|200|300|400|500|600|700|800|900)/, }, { - pattern: /border-(l|t|r|b)-(blue|green|purple|amber|red|gray)-(50|100|200|300|400|500|600|700|800|900)/, + pattern: /border-(l|t|r|b)-(blue|cyan|green|purple|pink|amber|red|gray)-(50|100|200|300|400|500|600|700|800|900)/, }, ], }; From c7e571902748f95a5f49c131f794e9854ec8c213 Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Wed, 28 May 2025 14:29:38 +0100 Subject: [PATCH 12/15] examples/annotations: fix usage from sandpack Adds the franken-ui dependency to the examples renderer. Updates the set of visible files configured for sandpack. --- src/components/Examples/ExamplesRenderer.tsx | 1 + src/data/examples/index.ts | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/Examples/ExamplesRenderer.tsx b/src/components/Examples/ExamplesRenderer.tsx index c925540124..d16cf398fc 100644 --- a/src/components/Examples/ExamplesRenderer.tsx +++ b/src/components/Examples/ExamplesRenderer.tsx @@ -40,6 +40,7 @@ const getDependencies = (id: string, products: string[], activeLanguage: Languag ably: '^2.9.0', nanoid: '^5.0.7', minifaker: '1.34.1', + 'franken-ui': '^2.0.0', ...(products.includes('auth') ? { cors: '^2.8.5' } : {}), ...(products.includes('chat') ? { '@ably/chat': '^0.14.0', '@ably/chat-react-ui-components': '^0.1.2', clsx: '^2.1.1' } diff --git a/src/data/examples/index.ts b/src/data/examples/index.ts index 5b9422f95d..2d24fb03f8 100644 --- a/src/data/examples/index.ts +++ b/src/data/examples/index.ts @@ -194,7 +194,17 @@ export const examples: Example[] = [ description: 'Annotate pub/sub messages with additional data.', products: ['pubsub'], layout: 'double-horizontal', - visibleFiles: ['src/script.ts'], + visibleFiles: [ + 'src/script.ts', + 'src/types.ts', + 'src/config.ts', + 'src/ably.ts', + 'src/components/annotations.ts', + 'src/components/arrow.ts', + 'src/components/badge.ts', + 'src/components/message.ts', + 'src/components/summary.ts', + ], metaTitle: `Implement message annotations with the Ably Pub/Sub SDK`, metaDescription: `Use the Ably Pub/Sub JavaScript SDK to implement message annotations. Annotate messages with additional data and view summaries of the annotations.`, }, From 43e3aa93bc935c51e25ace25a40f86a2b2e18c2b Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Wed, 28 May 2025 16:56:16 +0100 Subject: [PATCH 13/15] examples/annotations: update README --- .../javascript/README.md | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/examples/pub-sub-message-annotations/javascript/README.md b/examples/pub-sub-message-annotations/javascript/README.md index c9832a9fe4..d6c3d31292 100644 --- a/examples/pub-sub-message-annotations/javascript/README.md +++ b/examples/pub-sub-message-annotations/javascript/README.md @@ -1,31 +1,39 @@ -# Using message annotations with Pub/Sub +# Adding annotations to messages with Pub/Sub -This example demonstrates how to use Ably's message annotations feature to add additional metadata to messages in a pub/sub system. Message annotations allow clients to add reactions, flags, or other metadata to messages without modifying the original message content. +Enable users to annotate messages with additional data, such as reactions, flags, or other contextual information without modifying the original message content. + +Message annotations provide a powerful way to extend messages with additional information. Unlike editing a message, annotations allow multiple clients to add their own metadata while preserving the original message. This is ideal for implementing features like reactions, content categorization, moderation flags, or any other metadata that enhances message context. + +Message annotations are implemented using [Ably Pub/Sub](/docs/channels). The Pub/Sub SDK with annotations provides a way to add structured metadata to messages, with support for different annotation types and automatic summarization. ## Resources -- [Ably Documentation](https://ably.com/docs) -- [Message Annotations Documentation](https://ably.com/docs/messages/annotations) +Use the following methods to work with message annotations in a pub/sub application: -The channel name must be in a mutable message namespace, which is why we're using `mutable:pub-sub-message-annotations` in this example. +- [`channels.get()`](/docs/channels#create) - creates a new or retrieves an existing `channel`. Specify the `ANNOTATION_PUBLISH` and `ANNOTATION_SUBSCRIBE` modes to publish and subscribe to message annotations. +- [`channel.subscribe()`](/docs/pub-sub#subscribe) - subscribes to message events within a specific channel by registering a listener. Message events with a `message.create` action are received when a user publishes a message. Message events with a `message.summary` action are received when a user publishes or deletes an annotation. + +- `channel.annotations.publish()` - publishes an annotation for a specific message +- `channel.annotations.subscribe()` - subscribes to receive individual annotation events +- `channel.annotations.delete()` - deletes a previously published annotation -## Features + +Find out more about annotations. -In this example, you can: +## Annotation Types -1. Publish messages to a channel -2. Add annotations to messages using different annotation types: - - **distinct.v1**: Track different values with client IDs that created them - - **unique.v1**: Similar to distinct, but only the first client ID is recorded - - **multiple.v1**: Track counts of values by different clients - - **flag.v1**: Simple flags with client IDs - - **total.v1**: Count the total annotations +This example demonstrates five common annotation types, each suited to different use cases: -3. View annotation summaries showing: - - How many of each annotation type exist - - Which clients contributed annotations - - The values of annotations - - Expandable/collapsible sections for detailed information + + +## Features + +This example demonstrates: + +1. Publishing regular messages to a channel +2. Adding different types of annotations to messages +3. Viewing both summarized and raw annotation data +4. Deleting annotations ## Getting started @@ -63,16 +71,19 @@ In this example, you can: 7. Try it out by opening two tabs to [http://localhost:5173/](http://localhost:5173/) with your browser to see the result. +## Technical notes + +- Annotations require a channel in the mutable channel namespace. This example uses `mutable:pub-sub-message-annotations` +- Annotations are logically grouped by an annotation namespace. This example uses `my-annotations` + ## How to use this example -1. Enter a message in the input field and click "Publish" to send it to the channel. -2. After publishing a message, you'll see it appear in the message list with an expandable annotation interface. -3. To add an annotation, select an annotation type from the dropdown menu, enter a value, and click "Publish". -4. Open the example in multiple browser tabs with different URL parameters (e.g., `?clientId=user1` and `?clientId=user2`) to see how annotations from different clients are handled. -5. Experiment with different annotation types: - - For reactions, try using the "multiple.v1" type with values like "👍" or "❤️" - - For flagging content, use the "flag.v1" type - - For tracking unique entries, use "distinct.v1" or "unique.v1" +1. Enter a message in the input field and click "Publish" to send it to the channel +2. Click on a message to expand it and reveal the annotation interface +3. Select an annotation type, enter a value, and click "Publish" to add an annotation +4. Switch between the "Summary" and "Raw Annotations" tabs to see different views +5. Open the example in multiple browser tabs with different client IDs (e.g., `?clientId=user1` and `?clientId=user2`) to see how annotations from different clients are handled and summarized +6. Delete annotations by clicking the trash icon in the raw annotations view and see how the summary is updated ## Open in CodeSandbox From 223c11c1a27e726eebb2acae8258878bcf4bc09f Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Wed, 1 Oct 2025 17:29:53 +0100 Subject: [PATCH 14/15] examples/annotations: update functionality of channelName and namespace --- examples/pub-sub-message-annotations/javascript/src/ably.ts | 2 +- .../javascript/src/components/summary.ts | 4 ++-- examples/pub-sub-message-annotations/javascript/src/config.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/pub-sub-message-annotations/javascript/src/ably.ts b/examples/pub-sub-message-annotations/javascript/src/ably.ts index 0a2037335f..55b3f0ec7d 100644 --- a/examples/pub-sub-message-annotations/javascript/src/ably.ts +++ b/examples/pub-sub-message-annotations/javascript/src/ably.ts @@ -18,7 +18,7 @@ function getClient(): Ably.Realtime { // Returns the configured channel with all annotation modes enabled export function getChannel() { - return getClient().channels.get(channelName, { + return getClient().channels.get(`annotation:${channelName}`, { modes: ['PUBLISH', 'SUBSCRIBE', 'ANNOTATION_PUBLISH', 'ANNOTATION_SUBSCRIBE'], }); } diff --git a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts index 899076c2c5..58b9a89ab5 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts @@ -242,7 +242,7 @@ export function updateAnnotationSummary(message: MessageSummary) { } sectionsContainer.innerHTML = ''; - const hasAnnotations = annotationTypes.some((type) => message.summary && message.summary[`${annotationNamespace}:${type.key}`]); + const hasAnnotations = annotationTypes.some((type) => message.annotations.summary && message.annotations.summary[`${annotationNamespace}:${type.key}`]); if (!hasAnnotations) { sectionsContainer.appendChild(createEmptyAnnotationSummaryContentElement()); @@ -250,7 +250,7 @@ export function updateAnnotationSummary(message: MessageSummary) { } for (const { key } of annotationTypes) { - const entry = message.summary[`${annotationNamespace}:${key}`]; + const entry = message.annotations.summary[`${annotationNamespace}:${key}`]; if (!entry) { continue; } diff --git a/examples/pub-sub-message-annotations/javascript/src/config.ts b/examples/pub-sub-message-annotations/javascript/src/config.ts index 5ff7fdb2e4..3745b75bc4 100644 --- a/examples/pub-sub-message-annotations/javascript/src/config.ts +++ b/examples/pub-sub-message-annotations/javascript/src/config.ts @@ -1,7 +1,7 @@ export const urlParams = new URLSearchParams(window.location.search); export const clientId = urlParams.get('clientId') || 'user2'; -export const channelName = urlParams.get('name') || 'mutable:pub-sub-message-annotations'; -export const annotationNamespace = 'my-annotations'; +export const annotationNamespace = 'annotation'; +export const channelName = urlParams.get('name') || `${annotationNamespace}:pub-sub-message-annotations`; export const annotationTypes = [ { key: 'total.v1', color: 'blue', label: 'Total' }, From f7a321abfb8fa78f821a24874d204982b030679c Mon Sep 17 00:00:00 2001 From: Greg Holmes Date: Wed, 1 Oct 2025 17:55:18 +0100 Subject: [PATCH 15/15] examples/annotations: bump ably-js to 2.13.0 --- examples/package.json | 2 +- .../javascript/src/components/summary.ts | 6 ++++-- examples/yarn.lock | 8 ++++---- src/components/Examples/ExamplesRenderer.tsx | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/package.json b/examples/package.json index f6474fef3e..896fd79730 100644 --- a/examples/package.json +++ b/examples/package.json @@ -105,7 +105,7 @@ "@ably/chat": "^0.14.0", "@ably/chat-react-ui-components": "^0.1.2", "@ably/spaces": "^0.4.0", - "ably": "^2.9.0", + "ably": "^2.13.0", "cors": "^2.8.5", "franken-ui": "^2.0.0", "minifaker": "^1.34.1", diff --git a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts index 58b9a89ab5..7f42638d00 100644 --- a/examples/pub-sub-message-annotations/javascript/src/components/summary.ts +++ b/examples/pub-sub-message-annotations/javascript/src/components/summary.ts @@ -242,7 +242,9 @@ export function updateAnnotationSummary(message: MessageSummary) { } sectionsContainer.innerHTML = ''; - const hasAnnotations = annotationTypes.some((type) => message.annotations.summary && message.annotations.summary[`${annotationNamespace}:${type.key}`]); + const hasAnnotations = annotationTypes.some( + (type) => message.annotations?.summary && message.annotations?.summary[`${annotationNamespace}:${type.key}`], + ); if (!hasAnnotations) { sectionsContainer.appendChild(createEmptyAnnotationSummaryContentElement()); @@ -250,7 +252,7 @@ export function updateAnnotationSummary(message: MessageSummary) { } for (const { key } of annotationTypes) { - const entry = message.annotations.summary[`${annotationNamespace}:${key}`]; + const entry = message.annotations?.summary[`${annotationNamespace}:${key}`]; if (!entry) { continue; } diff --git a/examples/yarn.lock b/examples/yarn.lock index 7772151a8d..c332e1150c 100644 --- a/examples/yarn.lock +++ b/examples/yarn.lock @@ -703,10 +703,10 @@ magic-string "^0.27.0" react-refresh "^0.14.0" -ably@^2.9.0: - version "2.9.0" - resolved "https://registry.npmjs.org/ably/-/ably-2.9.0.tgz" - integrity sha512-ddaurgvYHGmVVZkd5U2xJgLrbVdtAIw1RunfuZroE/ZTsmK2+vUnAZ7aKhR20cwOFP3QyLFYs6IfvwaijnIPlA== +ably@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/ably/-/ably-2.13.0.tgz#f9e1aebdf1f69700b5b20f0029ff1c383c2ed123" + integrity sha512-fgrzWlUWRCOCqCNq1szMZNsa/VXYwS3DParDpMuhCBPxmsDL2Y1fMpppfHtQiFRvNFcInY9bPQXuPFjJpmqSHw== dependencies: "@ably/msgpack-js" "^0.4.0" dequal "^2.0.3" diff --git a/src/components/Examples/ExamplesRenderer.tsx b/src/components/Examples/ExamplesRenderer.tsx index d16cf398fc..e0c97a433a 100644 --- a/src/components/Examples/ExamplesRenderer.tsx +++ b/src/components/Examples/ExamplesRenderer.tsx @@ -37,7 +37,7 @@ const UserIndicator = ({ user }: { user: string }) => { const getDependencies = (id: string, products: string[], activeLanguage: LanguageKey) => { return { - ably: '^2.9.0', + ably: '^2.13.0', nanoid: '^5.0.7', minifaker: '1.34.1', 'franken-ui': '^2.0.0',