From 471b56e40b329990b1f5ae0a4021299ce6deb2a9 Mon Sep 17 00:00:00 2001 From: r0c0y Date: Thu, 29 Oct 2026 14:46:23 +0530 Subject: [PATCH] feat(vue): add Vue integration Adds @tryabby/vue with the same API as the React integration: useAbby, useFeatureFlag, useRemoteConfig, useFeatureFlags, useRemoteConfigVariables, the non-reactive helpers and withDevtools. An AbbyPlugin provides the state per app, which keeps SSR (Nuxt) requests apart, and loadInitialData() lets the server render flags and remote config. Variants are only selected in the browser once the weights are loaded. Closes #68 --- .changeset/quiet-vue-hearts.md | 5 + apps/docs/pages/integrations/_meta.json | 1 + apps/docs/pages/integrations/vue.mdx | 205 +++++++++ packages/vue/.gitignore | 1 + packages/vue/README.md | 48 ++ packages/vue/package.json | 47 ++ packages/vue/src/StorageService.ts | 76 ++++ packages/vue/src/createAbby.ts | 442 +++++++++++++++++++ packages/vue/src/index.ts | 7 + packages/vue/tests/mocks/handlers.ts | 42 ++ packages/vue/tests/mocks/server.ts | 5 + packages/vue/tests/setup.ts | 30 ++ packages/vue/tests/ssr.test.ts | 71 +++ packages/vue/tests/types.test-d.ts | 97 ++++ packages/vue/tests/useAbby.test.ts | 462 +++++++++++++++++++ packages/vue/tests/utils.ts | 47 ++ packages/vue/tsconfig.json | 11 + packages/vue/tsup.config.ts | 9 + packages/vue/vite.config.ts | 13 + pnpm-lock.yaml | 561 +++++++++++++++++++----- 20 files changed, 2074 insertions(+), 106 deletions(-) create mode 100644 .changeset/quiet-vue-hearts.md create mode 100644 apps/docs/pages/integrations/vue.mdx create mode 100644 packages/vue/.gitignore create mode 100644 packages/vue/README.md create mode 100644 packages/vue/package.json create mode 100644 packages/vue/src/StorageService.ts create mode 100644 packages/vue/src/createAbby.ts create mode 100644 packages/vue/src/index.ts create mode 100644 packages/vue/tests/mocks/handlers.ts create mode 100644 packages/vue/tests/mocks/server.ts create mode 100644 packages/vue/tests/setup.ts create mode 100644 packages/vue/tests/ssr.test.ts create mode 100644 packages/vue/tests/types.test-d.ts create mode 100644 packages/vue/tests/useAbby.test.ts create mode 100644 packages/vue/tests/utils.ts create mode 100644 packages/vue/tsconfig.json create mode 100644 packages/vue/tsup.config.ts create mode 100644 packages/vue/vite.config.ts diff --git a/.changeset/quiet-vue-hearts.md b/.changeset/quiet-vue-hearts.md new file mode 100644 index 00000000..bbae68bf --- /dev/null +++ b/.changeset/quiet-vue-hearts.md @@ -0,0 +1,5 @@ +--- +"@tryabby/vue": minor +--- + +add Vue integration diff --git a/apps/docs/pages/integrations/_meta.json b/apps/docs/pages/integrations/_meta.json index 5cbf2999..1f8b2ad8 100644 --- a/apps/docs/pages/integrations/_meta.json +++ b/apps/docs/pages/integrations/_meta.json @@ -3,6 +3,7 @@ "react": "React", "remix": "Remix", "svelte": "Svelte", + "vue": "Vue", "angular": "Angular", "node": "Node", "express": "Express", diff --git a/apps/docs/pages/integrations/vue.mdx b/apps/docs/pages/integrations/vue.mdx new file mode 100644 index 00000000..db679076 --- /dev/null +++ b/apps/docs/pages/integrations/vue.mdx @@ -0,0 +1,205 @@ +import { Tab, Tabs, Callout } from "nextra-theme-docs"; + +# Vue + +Our Vue integration works with Vue 3.5 or later. It works with SPAs as well as server side rendered apps like [Nuxt](#nuxt). + +## Installation + +To get started make sure to install the package using your favorite package manager. + + + + ```bash + npm i @tryabby/vue + ``` + + + ```bash + yarn add @tryabby/vue + ``` + + + ```bash + pnpm i @tryabby/vue + ``` + + + +### Create your config + +To use Abby you need to create your config first. You can do this by creating a file called `abby.config.ts` in your `root` folder. This file will be used to configure your project. + +```ts +// abby.config.ts +import { defineConfig } from "@tryabby/vue"; + +export default defineConfig({ + projectId: "", + currentEnvironment: process.env.NODE_ENV, + environments: ["production", "development"], + tests: { + test: { variants: ["A", "B"] }, + footer: { variants: ["dark", "orange", "green"] }, + // ... your tests + }, + flags: ["darkMode", "newFeature"], + remoteConfig: { + customButtonText: "String", + }, +}); +``` + +### Create your Instance + +To use Abby in your code you will need to create typed composables and a plugin first. You can do this by using the `createAbby` function. +Please copy the id of your project from the dashboard to get started. + +```ts +// abby.ts +import { createAbby } from "@tryabby/vue"; +import abbyConfig from "../abby.config"; + +export const { AbbyPlugin, useAbby, useFeatureFlag, useRemoteConfig } = + createAbby(abbyConfig); +``` + +### Install the plugin + +The composables need the `AbbyPlugin` to be installed in your app. The plugin loads your project's data in the background. + +```ts +// main.ts +import { createApp } from "vue"; +import App from "./App.vue"; +import { AbbyPlugin } from "./abby"; + +createApp(App).use(AbbyPlugin).mount("#app"); +``` + +You can now import the composables created by `createAbby` and use them in your components. + +## Usage + +The composables return [computed refs](https://vuejs.org/api/reactivity-core.html#computed), so your components update automatically +when your data is loaded or when you change something in the [Devtools](/devtools). + +### useAbby + +The `useAbby` composable returns an object with the following values: + +- `variant` - A computed ref with the variant that is currently active +- `onAct` - A function that you can call to trigger any kind of interaction with the tested component (will be used to track conversions) + +```vue + + + +``` + +Optionally, you can pass a lookup object to automatically map the selected variant to a custom value. + +```vue + + + +``` + + + The variant is an empty string until the component is mounted and the project data is loaded. The server can't know which + variant a user is going to see, so the variant is selected in the browser, using the weights from your dashboard. + This way server side rendering won't cause any hydration mismatches. + + +### useFeatureFlag + +The `useFeatureFlag` composable returns a computed boolean that indicates if the flag is active or not. + +```vue + + + +``` + +### useRemoteConfig + +The `useRemoteConfig` composable returns a computed value as specified in your `abby.config.ts`. +The type of the returned value will automatically be inferred from your config. + +```vue + + + +``` + +### Devtools + +To use the [Devtools](/devtools) you need to install the `@tryabby/devtools` package and render the component created by `withDevtools`. +They are only shown in development unless you pass `dangerouslyForceShow: true`. + +```vue + + + +``` + +## Nuxt + +In Nuxt you install the plugin in a [Nuxt plugin](https://nuxt.com/docs/guide/directory-structure/plugins). If you load the data with `loadInitialData`, +your flags and remote config are already rendered on the server, and the client reuses the data from the payload instead of fetching it again. + +```ts +// plugins/abby.ts +import { AbbyPlugin, loadInitialData } from "~/abby"; + +export default defineNuxtPlugin(async (nuxtApp) => { + const { data } = await useAsyncData("abby", () => loadInitialData()); + nuxtApp.vueApp.use(AbbyPlugin, { initialData: data.value ?? undefined }); +}); +``` + +Make sure to also export `loadInitialData` from your `abby.ts`. diff --git a/packages/vue/.gitignore b/packages/vue/.gitignore new file mode 100644 index 00000000..53c37a16 --- /dev/null +++ b/packages/vue/.gitignore @@ -0,0 +1 @@ +dist \ No newline at end of file diff --git a/packages/vue/README.md b/packages/vue/README.md new file mode 100644 index 00000000..56dae148 --- /dev/null +++ b/packages/vue/README.md @@ -0,0 +1,48 @@ +# @tryabby/vue + +Vue integration for [Abby](https://tryabby.com): feature flags, remote config and A/B tests with full type safety. Works with Vue 3.5+ and Nuxt. + +## Installation + +```bash +npm i @tryabby/vue +``` + +## Usage + +```ts +// abby.ts +import { createAbby } from "@tryabby/vue"; + +export const { AbbyPlugin, useAbby, useFeatureFlag, useRemoteConfig } = + createAbby({ + projectId: "", + currentEnvironment: "production", + environments: ["production", "development"], + tests: { footer: { variants: ["dark", "orange", "green"] } }, + flags: ["newFeature"], + remoteConfig: { customButtonText: "String" }, + }); +``` + +```ts +// main.ts +createApp(App).use(AbbyPlugin).mount("#app"); +``` + +```vue + + + +``` + +All composables return computed refs. Check out the [documentation](https://docs.tryabby.com/integrations/vue) for the full API, the devtools and the Nuxt setup. diff --git a/packages/vue/package.json b/packages/vue/package.json new file mode 100644 index 00000000..93f5abb6 --- /dev/null +++ b/packages/vue/package.json @@ -0,0 +1,47 @@ +{ + "name": "@tryabby/vue", + "version": "0.0.0", + "description": "Vue integration for Abby: feature flags, remote config and A/B tests", + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "files": ["dist"], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.js" + } + }, + "scripts": { + "build": "tsup src/", + "dev": "pnpm run build --watch", + "test": "tsc --noEmit && vitest" + }, + "homepage": "https://docs.tryabby.com", + "keywords": ["vue", "nuxt", "feature-flags", "ab-testing", "remote-config"], + "author": "", + "license": "ISC", + "devDependencies": { + "@tryabby/devtools": "workspace:*", + "@types/js-cookie": "^3.0.3", + "@vue/server-renderer": "^3.5.13", + "@vue/test-utils": "^2.4.6", + "jsdom": "^20.0.3", + "msw": "^0.49.1", + "node-fetch": "^3.3.0", + "tsconfig": "workspace:*", + "tsup": "^6.5.0", + "typescript": "5.5.4", + "vite": "5.4.0", + "vitest": "2.0.5", + "vue": "^3.5.13" + }, + "peerDependencies": { + "vue": "^3.5.0" + }, + "dependencies": { + "@tryabby/core": "workspace:*", + "js-cookie": "^3.0.1" + } +} diff --git a/packages/vue/src/StorageService.ts b/packages/vue/src/StorageService.ts new file mode 100644 index 00000000..7633105e --- /dev/null +++ b/packages/vue/src/StorageService.ts @@ -0,0 +1,76 @@ +import { + type IStorageService, + type StorageServiceOptions, + getABStorageKey, + getFFStorageKey, + getRCStorageKey, +} from "@tryabby/core"; +import Cookie from "js-cookie"; + +const DEFAULT_COOKIE_AGE = 365; + +class ABStorageService implements IStorageService { + get(projectId: string, testName: string): string | null { + const retrievedValue = Cookie.get(getABStorageKey(projectId, testName)); + if (!retrievedValue) return null; + + return retrievedValue; + } + + set( + projectId: string, + testName: string, + value: string, + options?: StorageServiceOptions + ): void { + Cookie.set(getABStorageKey(projectId, testName), value, { + expires: options?.expiresInDays + ? options.expiresInDays + : DEFAULT_COOKIE_AGE, + }); + } + + remove(projectId: string, testName: string): void { + Cookie.remove(getABStorageKey(projectId, testName)); + } +} + +class FFStorageService implements IStorageService { + get(projectId: string, flagName: string): string | null { + const retrievedValue = Cookie.get(getFFStorageKey(projectId, flagName)); + if (!retrievedValue) return null; + + return retrievedValue; + } + + set(projectId: string, flagName: string, value: string): void { + Cookie.set(getFFStorageKey(projectId, flagName), value, { + expires: DEFAULT_COOKIE_AGE, + }); + } + + remove(projectId: string, flagName: string): void { + Cookie.remove(getFFStorageKey(projectId, flagName)); + } +} + +class RCStorageService implements IStorageService { + get(projectId: string, key: string): string | null { + const retrievedValue = Cookie.get(getRCStorageKey(projectId, key)); + return retrievedValue ?? null; + } + + set(projectId: string, key: string, value: string): void { + Cookie.set(getRCStorageKey(projectId, key), value, { + expires: DEFAULT_COOKIE_AGE, + }); + } + + remove(projectId: string, key: string): void { + Cookie.remove(getRCStorageKey(projectId, key)); + } +} + +export const TestStorageService = new ABStorageService(); +export const FlagStorageService = new FFStorageService(); +export const RemoteConfigStorageService = new RCStorageService(); diff --git a/packages/vue/src/createAbby.ts b/packages/vue/src/createAbby.ts new file mode 100644 index 00000000..a5edd6d4 --- /dev/null +++ b/packages/vue/src/createAbby.ts @@ -0,0 +1,442 @@ +import { + type ABConfig, + Abby, + type AbbyConfig, + type AbbyDataResponse, + AbbyEventType, + HttpService, + type RemoteConfigValueString, + type RemoteConfigValueStringToType, + type ValidatorType, +} from "@tryabby/core"; +import type { Infer } from "@tryabby/core/validation"; +import type { AbbyDevtoolProps, DevtoolsFactory } from "@tryabby/devtools"; +import { + type App, + type Component, + type ComputedRef, + type InjectionKey, + type ShallowRef, + computed, + defineComponent, + hasInjectionContext, + inject, + onMounted, + onUnmounted, + shallowRef, + watch, +} from "vue"; +import { + FlagStorageService, + RemoteConfigStorageService, + TestStorageService, +} from "./StorageService"; + +export type ABTestReturnValue = Lookup extends undefined + ? TestVariant + : TestVariant extends keyof Lookup + ? Lookup[TestVariant] + : never; + +export type AbbyPluginOptions = { + /** + * Project data that was loaded beforehand, e.g. on the server with `loadInitialData()`. + * If it's not passed, the data is loaded in the browser once the plugin is installed. + */ + initialData?: AbbyDataResponse; +}; + +export type withDevtoolsFunction = ( + factory: DevtoolsFactory, + props?: Omit & { + dangerouslyForceShow?: boolean; + } +) => Component; + +export function createAbby< + const FlagName extends string, + const TestName extends string, + const Tests extends Record, + const RemoteConfig extends Record, + const RemoteConfigName extends Extract, + const User extends Record = Record< + string, + ValidatorType + >, +>( + abbyConfig: AbbyConfig< + FlagName, + Tests, + string[], + RemoteConfigName, + RemoteConfig, + User + > +) { + // we need to keep the config as a const so that the types are narrowed + const config = abbyConfig; + + const abby = new Abby< + FlagName, + TestName, + Tests, + RemoteConfig, + RemoteConfigName, + string[], + User + >( + abbyConfig, + { + get: (key: string) => { + if (typeof window === "undefined") return null; + return TestStorageService.get(config.projectId, key); + }, + set: (key: string, value: any) => { + if (typeof window === "undefined" || config.cookies?.disableByDefault) + return; + TestStorageService.set(config.projectId, key, value); + }, + }, + { + get: (key: string) => { + if (typeof window === "undefined") return null; + return FlagStorageService.get(config.projectId, key); + }, + set: (key: string, value: any) => { + if (typeof window === "undefined") return; + FlagStorageService.set(config.projectId, key, value); + }, + }, + { + get: (key: string) => { + if (typeof window === "undefined") return null; + return RemoteConfigStorageService.get(config.projectId, key); + }, + set: (key: string, value: any) => { + if (typeof window === "undefined") return; + RemoteConfigStorageService.set(config.projectId, key, value); + }, + } + ); + + type AbbyProjectData = ReturnType; + + const AbbyDataKey: InjectionKey> = Symbol("abby"); + + /** + * `getProjectData()` selects and stores a variant for every test. Before the + * weights are loaded from the API that would use equal weights and keep that + * variant forever, so the tests are left out until the data is loaded. + */ + const getDataWithoutTests = (): AbbyProjectData => ({ + tests: {} as AbbyProjectData["tests"], + flags: Object.fromEntries( + abby.getFeatureFlags().map(({ name, value }) => [name, { value }]) + ) as AbbyProjectData["flags"], + remoteConfig: Object.fromEntries( + abby + .getRemoteConfigVariables() + // the generic value type can't be narrowed here + .map(({ name, value }) => [name, { value: value as unknown }]) + ) as AbbyProjectData["remoteConfig"], + }); + + /** + * Vue plugin that makes the Abby data available to the composables. + * The state lives on the app (not in this module) so every app, and every + * request when rendering on the server, gets its own copy. + */ + const AbbyPlugin = { + install(app: App, options: AbbyPluginOptions = {}) { + // The core mutates its data in place and hands out the same nested objects, + // so the data is kept in a shallowRef and replaced with a fresh snapshot + // on every change. A deep ref would not notice the core's updates. + const data = shallowRef( + options.initialData + ? abby.init(options.initialData) + : getDataWithoutTests() + ); + app.provide(AbbyDataKey, data); + + // On the server the app is rendered once and never unmounted, so there + // is nothing to update and a subscription would leak on every request. + if (typeof window === "undefined") return; + + const unsubscribe = abby.subscribe((newData) => { + data.value = newData as AbbyProjectData; + }); + app.onUnmount(unsubscribe); + + if (!options.initialData) { + // `init()` notifies the subscribers before it applies the local overrides + // from the cookies, so the resolved data is set once more afterwards. + // If the data can't be loaded, the tests fall back to the configured variants. + abby.loadProjectData().then((loadedData) => { + data.value = loadedData ?? abby.getProjectData(); + }); + } + }, + }; + + const useAbbyData = () => { + const data = hasInjectionContext() ? inject(AbbyDataKey, null) : null; + + if (!data) { + throw new Error( + "Abby composables must be used inside the setup of a component in an app that uses the AbbyPlugin. Call app.use(AbbyPlugin) to fix this error." + ); + } + + return data; + }; + + const useAbby = < + K extends keyof Tests, + TestVariant extends Tests[K]["variants"][number], + LookupValue, + const Lookup extends + | Record + | undefined = undefined, + >( + name: K, + lookupObject?: Lookup + ): { + variant: ComputedRef>; + onAct: () => void; + } => { + const data = useAbbyData(); + + // The server can't know which variant a user gets (it's stored in a cookie), + // so like the React integration the variant stays empty until the component + // is mounted. This avoids hydration mismatches. + const isMounted = shallowRef(false); + onMounted(() => { + isMounted.value = true; + }); + + const selectedVariant = computed(() => + isMounted.value + ? (data.value.tests[name as unknown as TestName]?.selectedVariant ?? "") + : "" + ); + + // tell the server which variant was rendered, again whenever it changes + watch(selectedVariant, (variant) => { + if (!variant) return; + + HttpService.sendData({ + url: config.apiUrl, + type: AbbyEventType.PING, + data: { + projectId: config.projectId, + selectedVariant: variant, + testName: name as string, + }, + }); + }); + + const onAct = () => { + if (!selectedVariant.value) return; + + HttpService.sendData({ + url: config.apiUrl, + type: AbbyEventType.ACT, + data: { + projectId: config.projectId, + selectedVariant: selectedVariant.value, + testName: name as string, + }, + }); + }; + + const variant = computed(() => + lookupObject + ? lookupObject[selectedVariant.value as TestVariant] + : selectedVariant.value + ) as ComputedRef>; + + return { + variant, + /** + * This function can be called to indicate that something that + * uses the selected variant has been interacted with. + * It will automatically send the selected variant to the server. + */ + onAct, + }; + }; + + const useFeatureFlag = (name: FlagName): ComputedRef => { + const data = useAbbyData(); + return computed(() => data.value.flags[name].value); + }; + + /** + * Returns an Array of all flags with their name and value + */ + const useFeatureFlags = () => { + const data = useAbbyData(); + return computed(() => + (Object.keys(data.value.flags) as Array).map((flagName) => ({ + name: flagName, + value: data.value.flags[flagName].value, + })) + ); + }; + + const useRemoteConfig = < + T extends RemoteConfigName, + Config extends RemoteConfig[T], + >( + remoteConfigName: T + ): ComputedRef> => { + const data = useAbbyData(); + return computed( + () => + data.value.remoteConfig[remoteConfigName] + .value as RemoteConfigValueStringToType + ); + }; + + /** + * Returns an Array of all remote config variables with their name and value + */ + const useRemoteConfigVariables = () => { + const data = useAbbyData(); + return computed( + () => + (Object.keys(data.value.remoteConfig) as Array).map( + (configName) => ({ + name: configName, + value: data.value.remoteConfig[configName].value, + }) + ) as Array<{ + name: RemoteConfigName; + value: RemoteConfigValueStringToType; + }> + ); + }; + + /** + * Loads the project data from the Abby API, e.g. on the server to pass it + * as `initialData` to the plugin so the first render already has the right values + */ + const loadInitialData = () => + HttpService.getProjectData({ + projectId: config.projectId, + environment: config.currentEnvironment as string, + url: config.apiUrl, + fetch: config.fetch, + __experimentalCdnUrl: config.__experimentalCdnUrl + ? `${config.__experimentalCdnUrl}/${config.projectId}/${config.currentEnvironment}` + : undefined, + }); + + const getFeatureFlagValue = (name: FlagName) => { + return abby.getFeatureFlag(name); + }; + + const getRemoteConfig = < + T extends RemoteConfigName, + Config extends RemoteConfig[T], + >( + remoteConfigName: T + ): RemoteConfigValueStringToType => { + return abby.getRemoteConfig(remoteConfigName); + }; + + const getABTestValue = < + TestName extends keyof Tests, + TestVariant extends Tests[TestName]["variants"][number], + LookupValue, + const Lookup extends + | Record + | undefined = undefined, + >( + testName: TestName, + lookupObject?: Lookup + ): ABTestReturnValue => { + const variant = abby.getTestVariant(testName); + // Typescript looses its typing here, so we cast as any in favor of having + // better type inference for the user + if (lookupObject === undefined) { + return variant as any; + } + + return lookupObject[variant as TestVariant] as any; + }; + + /** + * Creates a component that renders the Abby devtools. + * They are only shown in development unless `dangerouslyForceShow` is set. + */ + const withDevtools: withDevtoolsFunction = (factory, props) => + defineComponent({ + name: "AbbyDevtools", + setup() { + let destroy: (() => void) | undefined; + + onMounted(() => { + if ( + !props?.dangerouslyForceShow && + process.env.NODE_ENV !== "development" + ) { + return; + } + destroy = factory.create({ ...props, abby }); + }); + + onUnmounted(() => { + destroy?.(); + }); + + return () => null; + }, + }); + + /** + * Simple helper function create a function that resets an AB test + * @param name the name of the test + * @returns A function that can be called to reset the test + */ + const getABResetFunction = (name: T) => { + return () => { + TestStorageService.remove(config.projectId, name as string); + }; + }; + + /** + * Simple helper function to get a list of all variants for a given test + * @param name the name of the test + * @returns an array of all variants + */ + const getVariants = (name: T) => { + return abby.getVariants(name); + }; + + const updateUserProperties = ( + user: Partial<{ + -readonly [K in keyof User]: Infer; + }> + ) => { + abby.updateUserProperties(user); + }; + + return { + AbbyPlugin, + useAbby, + useFeatureFlag, + useFeatureFlags, + useRemoteConfig, + useRemoteConfigVariables, + loadInitialData, + getFeatureFlagValue, + getRemoteConfig, + getABTestValue, + getABResetFunction, + getVariants, + updateUserProperties, + withDevtools, + __abby__: abby, + }; +} diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts new file mode 100644 index 00000000..a62b597a --- /dev/null +++ b/packages/vue/src/index.ts @@ -0,0 +1,7 @@ +export { + createAbby, + type ABTestReturnValue, + type AbbyPluginOptions, + type withDevtoolsFunction, +} from "./createAbby"; +export { type ABConfig, type AbbyConfig, defineConfig } from "@tryabby/core"; diff --git a/packages/vue/tests/mocks/handlers.ts b/packages/vue/tests/mocks/handlers.ts new file mode 100644 index 00000000..f2028cb7 --- /dev/null +++ b/packages/vue/tests/mocks/handlers.ts @@ -0,0 +1,42 @@ +import { ABBY_BASE_URL, type AbbyDataResponse } from "@tryabby/core"; +import { rest } from "msw"; + +const returnData: AbbyDataResponse = { + tests: [ + { + name: "test", + weights: [1, 1, 1, 1], + }, + { + name: "test2", + weights: [1, 0], + }, + ], + flags: [ + { + name: "flag1", + value: true, + }, + { + name: "flag2", + value: false, + }, + ], + remoteConfig: [ + { + name: "remoteConfig1", + value: "FooBar", + }, + ], +}; +export const handlers = [ + rest.get( + `${ABBY_BASE_URL}api/dashboard/:projectId/data`, + (_req, res, ctx) => { + return res(ctx.json(returnData)); + } + ), + rest.get(`${ABBY_BASE_URL}api/v2/data/:projectId`, (_req, res, ctx) => { + return res(ctx.json(returnData)); + }), +]; diff --git a/packages/vue/tests/mocks/server.ts b/packages/vue/tests/mocks/server.ts new file mode 100644 index 00000000..9bb8a870 --- /dev/null +++ b/packages/vue/tests/mocks/server.ts @@ -0,0 +1,5 @@ +import { setupServer } from "msw/node"; +import { handlers } from "./handlers"; + +// This configures a request mocking server with the given request handlers. +export const server = setupServer(...handlers); diff --git a/packages/vue/tests/setup.ts b/packages/vue/tests/setup.ts new file mode 100644 index 00000000..0066b826 --- /dev/null +++ b/packages/vue/tests/setup.ts @@ -0,0 +1,30 @@ +import { enableAutoUnmount } from "@vue/test-utils"; +import fetch from "node-fetch"; +import { afterAll, afterEach, beforeAll } from "vitest"; +import { server } from "./mocks/server"; + +/// @ts-ignore +global.fetch = fetch; + +// Establish API mocking before all tests. +beforeAll(() => server.listen()); + +// Clean up after the tests are finished. +afterAll(() => server.close()); + +// unmount every mounted app, which also runs the plugin's cleanup +enableAutoUnmount(afterEach); + +afterEach(() => { + // Reset any request handlers that we may add during the tests, + // so they don't affect other tests. + server.resetHandlers(); + vi.restoreAllMocks(); + // remove all cookies so tests don't share stored variants + if (typeof document === "undefined") return; + for (const cookie of document.cookie.split(";")) { + const name = cookie.split("=")[0]?.trim(); + if (name) + document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT`; + } +}); diff --git a/packages/vue/tests/ssr.test.ts b/packages/vue/tests/ssr.test.ts new file mode 100644 index 00000000..acdaa1c2 --- /dev/null +++ b/packages/vue/tests/ssr.test.ts @@ -0,0 +1,71 @@ +// @vitest-environment node + +import { HttpService } from "@tryabby/core"; +import { renderToString } from "@vue/server-renderer"; +import { createSSRApp, defineComponent, h } from "vue"; +import { createAbby } from "../src"; +import { initialData } from "./utils"; + +const createTestAbby = () => + createAbby({ + projectId: "123", + environments: [""], + currentEnvironment: "", + tests: { test: { variants: ["A", "B", "C"] } }, + flags: ["flag1", "flag2"], + remoteConfig: { text: "String" }, + }); + +describe("server side rendering", () => { + it("renders flags and remote config but no variant", async () => { + const { AbbyPlugin, useAbby, useFeatureFlag, useRemoteConfig } = + createTestAbby(); + + const app = createSSRApp( + defineComponent({ + setup() { + const { variant } = useAbby("test"); + const flag1 = useFeatureFlag("flag1"); + const text = useRemoteConfig("text"); + return () => + h("div", [ + h("span", { id: "variant" }, variant.value), + h("span", { id: "flag" }, String(flag1.value)), + h("span", { id: "text" }, text.value), + ]); + }, + }) + ).use(AbbyPlugin, { initialData }); + + const html = await renderToString(app); + + // the server doesn't know the user's variant, it's selected after hydration + expect(html).toContain(''); + expect(html).toContain('true'); + expect(html).toContain('Hello'); + }); + + it("doesn't subscribe, load data or send events on the server", async () => { + const { AbbyPlugin, useAbby, __abby__ } = createTestAbby(); + const subscribeSpy = vi.spyOn(__abby__, "subscribe"); + const loadSpy = vi.spyOn(__abby__, "loadProjectData"); + const sendSpy = vi.spyOn(HttpService, "sendData"); + + for (const options of [{ initialData }, undefined]) { + const app = createSSRApp( + defineComponent({ + setup() { + const { variant } = useAbby("test"); + return () => h("p", variant.value); + }, + }) + ).use(AbbyPlugin, options); + + await renderToString(app); + } + + expect(subscribeSpy).not.toHaveBeenCalled(); + expect(loadSpy).not.toHaveBeenCalled(); + expect(sendSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/vue/tests/types.test-d.ts b/packages/vue/tests/types.test-d.ts new file mode 100644 index 00000000..e37fb840 --- /dev/null +++ b/packages/vue/tests/types.test-d.ts @@ -0,0 +1,97 @@ +import type { AbbyDataResponse } from "@tryabby/core"; +import { type ComputedRef, createApp } from "vue"; +import { createAbby } from "../src"; + +const { AbbyPlugin, useAbby, useFeatureFlag, useRemoteConfig, ...abby } = + createAbby({ + projectId: "123", + environments: ["production"], + currentEnvironment: "production", + tests: { + test: { variants: ["ONLY_ONE_VARIANT"] }, + test2: { variants: ["A", "B"] }, + }, + flags: ["flag1"], + remoteConfig: { + text: "String", + count: "Number", + json: "JSON", + }, + }); + +describe("useAbby", () => { + it("returns the variants as a computed ref", () => { + expectTypeOf(useAbby("test").variant).toEqualTypeOf< + ComputedRef<"ONLY_ONE_VARIANT"> + >(); + expectTypeOf(useAbby("test2").variant).toEqualTypeOf< + ComputedRef<"A" | "B"> + >(); + expectTypeOf(useAbby("test").onAct).toEqualTypeOf<() => void>(); + }); + + it("uses the types of the lookup object", () => { + expectTypeOf(useAbby("test2", { A: 1, B: 2 }).variant).toEqualTypeOf< + ComputedRef<1 | 2> + >(); + }); + + it("rejects unknown tests and incomplete lookup objects", () => { + // @ts-expect-error unknown test + useAbby("unknown"); + // @ts-expect-error variant B is missing + useAbby("test2", { A: 1 }); + }); +}); + +describe("useFeatureFlag", () => { + it("returns a boolean computed ref", () => { + expectTypeOf(useFeatureFlag("flag1")).toEqualTypeOf>(); + }); + + it("rejects unknown flags", () => { + // @ts-expect-error unknown flag + useFeatureFlag("unknown"); + }); +}); + +describe("useRemoteConfig", () => { + it("infers the type from the config", () => { + expectTypeOf(useRemoteConfig("text")).toEqualTypeOf>(); + expectTypeOf(useRemoteConfig("count")).toEqualTypeOf>(); + expectTypeOf(useRemoteConfig("json")).toEqualTypeOf< + ComputedRef> + >(); + }); + + it("rejects unknown remote config", () => { + // @ts-expect-error unknown remote config + useRemoteConfig("unknown"); + }); +}); + +describe("helpers", () => { + it("are typed like the composables", () => { + expectTypeOf(abby.getFeatureFlagValue("flag1")).toEqualTypeOf(); + expectTypeOf(abby.getRemoteConfig("count")).toEqualTypeOf(); + expectTypeOf(abby.getABTestValue("test2")).toEqualTypeOf<"A" | "B">(); + expectTypeOf( + abby.getABTestValue("test2", { A: "a", B: "b" }) + ).toEqualTypeOf<"a" | "b">(); + expectTypeOf(abby.useFeatureFlags().value).toEqualTypeOf< + Array<{ name: "flag1"; value: boolean }> + >(); + // @ts-expect-error unknown flag + abby.getFeatureFlagValue("unknown"); + }); +}); + +describe("AbbyPlugin", () => { + it("can be installed with and without initial data", () => { + const initialData = {} as AbbyDataResponse; + createApp({}).use(AbbyPlugin); + createApp({}).use(AbbyPlugin, { initialData }); + // @ts-expect-error wrong option type + createApp({}).use(AbbyPlugin, { initialData: "nope" }); + }); +}); diff --git a/packages/vue/tests/useAbby.test.ts b/packages/vue/tests/useAbby.test.ts new file mode 100644 index 00000000..60f8c972 --- /dev/null +++ b/packages/vue/tests/useAbby.test.ts @@ -0,0 +1,462 @@ +import { + ABBY_BASE_URL, + AbbyEventType, + HttpService, + getABStorageKey, + getFFStorageKey, +} from "@tryabby/core"; +import { mount } from "@vue/test-utils"; +import { rest } from "msw"; +import { defineComponent, h, nextTick, watch } from "vue"; +import { createAbby } from "../src"; +import { server } from "./mocks/server"; +import { initialData, setStoredVariant, withSetup } from "./utils"; + +const OLD_ENV = process.env; + +beforeEach(() => { + process.env = { ...OLD_ENV }; +}); + +afterAll(() => { + process.env = OLD_ENV; +}); + +const createTestAbby = () => + createAbby({ + projectId: "123", + environments: [""], + currentEnvironment: "", + tests: { test: { variants: ["A", "B", "C"] } }, + flags: ["flag1", "flag2"], + remoteConfig: { text: "String", count: "Number" }, + }); + +describe("useAbby", () => { + it("returns one of the variants once mounted", () => { + const { AbbyPlugin, useAbby } = createTestAbby(); + + const { result } = withSetup(() => useAbby("test"), AbbyPlugin, { + initialData, + }); + + expect(["A", "B", "C"]).toContain(result.variant.value); + }); + + it("uses the stored variant", () => { + setStoredVariant("123", "test", "B"); + const { AbbyPlugin, useAbby } = createTestAbby(); + + const { result } = withSetup(() => useAbby("test"), AbbyPlugin, { + initialData, + }); + + expect(result.variant.value).toBe("B"); + }); + + it("looks up the selected variant in the lookup object", () => { + setStoredVariant("123", "test", "C"); + const { AbbyPlugin, useAbby } = createTestAbby(); + + const { result } = withSetup( + () => useAbby("test", { A: "red", B: "green", C: "blue" }), + AbbyPlugin, + { initialData } + ); + + expect(result.variant.value).toBe("blue"); + }); + + it("renders the variant in a component", async () => { + setStoredVariant("123", "test", "A"); + const { AbbyPlugin, useAbby } = createTestAbby(); + + const wrapper = mount( + defineComponent({ + setup() { + const { variant } = useAbby("test"); + return () => h("p", variant.value); + }, + }), + { global: { plugins: [[AbbyPlugin, { initialData }]] } } + ); + await nextTick(); + + expect(wrapper.text()).toBe("A"); + }); + + it("pings the server with the selected variant after mount", async () => { + setStoredVariant("123", "test", "B"); + const spy = vi + .spyOn(HttpService, "sendData") + .mockImplementation(() => undefined); + const { AbbyPlugin, useAbby } = createTestAbby(); + + withSetup(() => useAbby("test"), AbbyPlugin, { initialData }); + await nextTick(); + + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + type: AbbyEventType.PING, + data: { projectId: "123", selectedVariant: "B", testName: "test" }, + }) + ); + }); + + it("notifies the server with onAct", async () => { + setStoredVariant("123", "test", "C"); + const spy = vi + .spyOn(HttpService, "sendData") + .mockImplementation(() => undefined); + const { AbbyPlugin, useAbby } = createTestAbby(); + + const { result } = withSetup(() => useAbby("test"), AbbyPlugin, { + initialData, + }); + result.onAct(); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + type: AbbyEventType.ACT, + data: { projectId: "123", selectedVariant: "C", testName: "test" }, + }) + ); + }); + + it("updates the variant and pings again when it changes", async () => { + setStoredVariant("123", "test", "A"); + const spy = vi + .spyOn(HttpService, "sendData") + .mockImplementation(() => undefined); + const { AbbyPlugin, useAbby, __abby__ } = createTestAbby(); + + const { result } = withSetup(() => useAbby("test"), AbbyPlugin, { + initialData, + }); + await nextTick(); + + // this is what the devtools do + __abby__.updateLocalVariant("test", "C"); + await nextTick(); + + expect(result.variant.value).toBe("C"); + expect(spy).toHaveBeenLastCalledWith( + expect.objectContaining({ + type: AbbyEventType.PING, + data: { projectId: "123", selectedVariant: "C", testName: "test" }, + }) + ); + }); + + it("uses the weights from the API for new visitors", async () => { + // a random value close to 1 picks the last variant when all weights are equal + vi.spyOn(window.crypto, "getRandomValues").mockImplementation((array) => { + (array as Uint32Array)[0] = 0xffffffff; + return array; + }); + const { AbbyPlugin, useAbby } = createAbby({ + projectId: "123", + environments: [""], + currentEnvironment: "", + tests: { test2: { variants: ["A", "B"] } }, + }); + + // the mocked API gives B a weight of 0 + const { result } = withSetup(() => useAbby("test2"), AbbyPlugin); + expect(result.variant.value).toBe(""); + + await vi.waitFor(() => expect(result.variant.value).not.toBe("")); + expect(result.variant.value).toBe("A"); + expect(document.cookie).toContain(`${getABStorageKey("123", "test2")}=A`); + }); + + it("still selects a variant if the data can't be loaded", async () => { + server.use( + rest.get(`${ABBY_BASE_URL}api/v2/data/:projectId`, (_req, res, ctx) => + res(ctx.status(500)) + ) + ); + const { AbbyPlugin, useAbby } = createTestAbby(); + + const { result } = withSetup(() => useAbby("test"), AbbyPlugin); + + await vi.waitFor(() => + expect(["A", "B", "C"]).toContain(result.variant.value) + ); + }); + + it("throws a helpful error without the plugin", () => { + const { useAbby } = createTestAbby(); + + expect(() => useAbby("test")).toThrowError(/app\.use\(AbbyPlugin\)/); + expect(() => + mount( + defineComponent({ + setup() { + useAbby("test"); + return () => null; + }, + }) + ) + ).toThrowError(/app\.use\(AbbyPlugin\)/); + }); +}); + +describe("useFeatureFlag", () => { + it("returns the flag values", () => { + const { AbbyPlugin, useFeatureFlag } = createTestAbby(); + + const { result } = withSetup( + () => ({ + flag1: useFeatureFlag("flag1"), + flag2: useFeatureFlag("flag2"), + }), + AbbyPlugin, + { initialData } + ); + + expect(result.flag1.value).toBe(true); + expect(result.flag2.value).toBe(false); + }); + + it("loads the data from the API without initialData", async () => { + const { AbbyPlugin, useFeatureFlag } = createTestAbby(); + + const { result } = withSetup(() => useFeatureFlag("flag1"), AbbyPlugin); + expect(result.value).toBe(false); + + await vi.waitFor(() => expect(result.value).toBe(true)); + }); + + it("uses the devOverrides in development", () => { + process.env.NODE_ENV = "development"; + const { AbbyPlugin, useFeatureFlag } = createAbby({ + projectId: "123", + environments: [""], + currentEnvironment: "", + flags: ["flag1"], + settings: { flags: { devOverrides: { flag1: false } } }, + }); + + const { result } = withSetup(() => useFeatureFlag("flag1"), AbbyPlugin, { + initialData, + }); + + expect(result.value).toBe(false); + }); + + it("re-renders when a flag changes", async () => { + const { AbbyPlugin, useFeatureFlag, __abby__ } = createTestAbby(); + + const wrapper = mount( + defineComponent({ + setup() { + const flag1 = useFeatureFlag("flag1"); + return () => h("p", flag1.value ? "on" : "off"); + }, + }), + { global: { plugins: [[AbbyPlugin, { initialData }]] } } + ); + expect(wrapper.text()).toBe("on"); + + // this is what the devtools do + __abby__.updateFlag("flag1", false); + await nextTick(); + + expect(wrapper.text()).toBe("off"); + }); + + it("returns all flags with useFeatureFlags", async () => { + const { AbbyPlugin, useFeatureFlags, __abby__ } = createTestAbby(); + + const { result } = withSetup(() => useFeatureFlags(), AbbyPlugin, { + initialData, + }); + + expect(result.value).toEqual([ + { name: "flag1", value: true }, + { name: "flag2", value: false }, + ]); + + __abby__.updateFlag("flag2", true); + await nextTick(); + + expect(result.value).toEqual([ + { name: "flag1", value: true }, + { name: "flag2", value: true }, + ]); + }); +}); + +describe("useRemoteConfig", () => { + it("returns the remote config values", () => { + const { AbbyPlugin, useRemoteConfig } = createTestAbby(); + + const { result } = withSetup( + () => ({ + text: useRemoteConfig("text"), + count: useRemoteConfig("count"), + }), + AbbyPlugin, + { initialData } + ); + + expect(result.text.value).toBe("Hello"); + expect(result.count.value).toBe(42); + }); + + it("uses the default values until the data is loaded", () => { + const { AbbyPlugin, useRemoteConfig } = createAbby({ + projectId: "123", + environments: [""], + currentEnvironment: "", + remoteConfig: { text: "String" }, + settings: { remoteConfig: { defaultValues: { String: "Default" } } }, + }); + + const { result } = withSetup(() => useRemoteConfig("text"), AbbyPlugin); + + expect(result.value).toBe("Default"); + }); + + it("uses the devOverrides in development", () => { + process.env.NODE_ENV = "development"; + const { AbbyPlugin, useRemoteConfig } = createAbby({ + projectId: "123", + environments: [""], + currentEnvironment: "", + remoteConfig: { text: "String" }, + settings: { remoteConfig: { devOverrides: { text: "Overridden" } } }, + }); + + const { result } = withSetup(() => useRemoteConfig("text"), AbbyPlugin, { + initialData, + }); + + expect(result.value).toBe("Overridden"); + }); + + it("updates when a value changes", async () => { + const { AbbyPlugin, useRemoteConfig, __abby__ } = createTestAbby(); + + const { result } = withSetup(() => useRemoteConfig("text"), AbbyPlugin, { + initialData, + }); + + __abby__.updateRemoteConfig("text", "Changed"); + await nextTick(); + + expect(result.value).toBe("Changed"); + }); + + it("returns all variables with useRemoteConfigVariables", () => { + const { AbbyPlugin, useRemoteConfigVariables } = createTestAbby(); + + const { result } = withSetup(() => useRemoteConfigVariables(), AbbyPlugin, { + initialData, + }); + + expect(result.value).toEqual([ + { name: "text", value: "Hello" }, + { name: "count", value: 42 }, + ]); + }); +}); + +describe("AbbyPlugin", () => { + it("unsubscribes from the core when the app is unmounted", () => { + const { AbbyPlugin, useFeatureFlag, __abby__ } = createTestAbby(); + const unsubscribe = vi.fn(); + vi.spyOn(__abby__, "subscribe").mockReturnValue(unsubscribe); + + const { wrapper } = withSetup(() => useFeatureFlag("flag1"), AbbyPlugin, { + initialData, + }); + expect(__abby__.subscribe).toHaveBeenCalledTimes(1); + + wrapper.unmount(); + + expect(unsubscribe).toHaveBeenCalledTimes(1); + }); + + it("applies the cookie overrides once the data is loaded", async () => { + // the API returns `true` for flag1, the override (e.g. from the devtools) says `false` + document.cookie = `${getFFStorageKey("123", "flag1")}=false`; + const { AbbyPlugin, useFeatureFlag, __abby__ } = createTestAbby(); + const loadSpy = vi.spyOn(__abby__, "loadProjectData"); + + const { result } = withSetup(() => { + const flag1 = useFeatureFlag("flag1"); + // a sync watcher reads the value at the moment the core notifies, + // which is before the overrides are applied + watch(flag1, () => {}, { flush: "sync" }); + return flag1; + }, AbbyPlugin); + await vi.waitFor(() => expect(loadSpy).toHaveBeenCalledTimes(1)); + await loadSpy.mock.results[0]?.value; + + expect(result.value).toBe(false); + }); +}); + +describe("helpers", () => { + it("returns the values without a component", () => { + const { + __abby__, + getFeatureFlagValue, + getRemoteConfig, + getABTestValue, + getVariants, + } = createTestAbby(); + __abby__.init(initialData); + + expect(getFeatureFlagValue("flag1")).toBe(true); + expect(getRemoteConfig("text")).toBe("Hello"); + expect(getVariants("test")).toEqual(["A", "B", "C"]); + expect(["A", "B", "C"]).toContain(getABTestValue("test")); + expect(["a", "b", "c"]).toContain( + getABTestValue("test", { A: "a", B: "b", C: "c" }) + ); + }); + + it("resets a test with getABResetFunction", () => { + setStoredVariant("123", "test", "B"); + const { getABResetFunction } = createTestAbby(); + + getABResetFunction("test")(); + + expect(document.cookie).not.toContain("_test=B"); + }); +}); + +describe("withDevtools", () => { + const createFactory = () => { + const destroy = vi.fn(); + const factory = { create: vi.fn(() => destroy) }; + return { factory, destroy }; + }; + + it("creates the devtools on mount and destroys them on unmount", () => { + const { withDevtools } = createTestAbby(); + const { factory, destroy } = createFactory(); + + const wrapper = mount( + withDevtools(factory as any, { dangerouslyForceShow: true }) + ); + expect(factory.create).toHaveBeenCalledTimes(1); + + wrapper.unmount(); + expect(destroy).toHaveBeenCalledTimes(1); + }); + + it("does not show the devtools outside of development", () => { + process.env.NODE_ENV = "production"; + const { withDevtools } = createTestAbby(); + const { factory } = createFactory(); + + mount(withDevtools(factory as any)); + + expect(factory.create).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/vue/tests/utils.ts b/packages/vue/tests/utils.ts new file mode 100644 index 00000000..5bee329d --- /dev/null +++ b/packages/vue/tests/utils.ts @@ -0,0 +1,47 @@ +import { type AbbyDataResponse, getABStorageKey } from "@tryabby/core"; +import { mount } from "@vue/test-utils"; +import { type Plugin, defineComponent } from "vue"; + +export const initialData: AbbyDataResponse = { + tests: [{ name: "test", weights: [1, 0, 0] }], + flags: [ + { name: "flag1", value: true }, + { name: "flag2", value: false }, + ], + remoteConfig: [ + { name: "text", value: "Hello" }, + { name: "count", value: 42 }, + ], +}; + +/** + * Runs a composable inside the setup of a component that is mounted + * in an app with the given plugin installed. + */ +export function withSetup( + composable: () => T, + plugin: Plugin<[options?: { initialData?: AbbyDataResponse }]>, + options?: { initialData?: AbbyDataResponse } +) { + let result!: T; + + const wrapper = mount( + defineComponent({ + setup() { + result = composable(); + return () => null; + }, + }), + { global: { plugins: [[plugin, options]] } } + ); + + return { result, wrapper }; +} + +export function setStoredVariant( + projectId: string, + testName: string, + variant: string +) { + document.cookie = `${getABStorageKey(projectId, testName)}=${variant}`; +} diff --git a/packages/vue/tsconfig.json b/packages/vue/tsconfig.json new file mode 100644 index 00000000..7015f100 --- /dev/null +++ b/packages/vue/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "tsconfig/base.json", + "compilerOptions": { + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "target": "es6", + "types": ["vitest/globals"] + }, + "include": ["src", "tests"] +} diff --git a/packages/vue/tsup.config.ts b/packages/vue/tsup.config.ts new file mode 100644 index 00000000..bf89044f --- /dev/null +++ b/packages/vue/tsup.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + dts: true, + clean: true, + format: ["cjs", "esm"], + sourcemap: true, + treeshake: true, +}); diff --git a/packages/vue/vite.config.ts b/packages/vue/vite.config.ts new file mode 100644 index 00000000..c5e5a986 --- /dev/null +++ b/packages/vue/vite.config.ts @@ -0,0 +1,13 @@ +/// + +import { defineConfig } from "vite"; + +export default defineConfig({ + test: { + globals: true, + environment: "jsdom", + setupFiles: "./tests/setup.ts", + // the type tests in *.test-d.ts are checked by `tsc`, see the test script + include: ["tests/**/*.test.ts"], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 69fa896e..fc59fd25 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -327,7 +327,7 @@ importers: version: 3.1.55(@next/env@14.2.4)(next@14.1.1(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8)) next-themes: specifier: ^0.2.1 - version: 0.2.1(next@14.1.1(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 0.2.1(next@14.1.1(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) nextjs-cors: specifier: ^2.1.2 version: 2.1.2(next@14.1.1(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8)) @@ -620,7 +620,7 @@ importers: version: 2.4.2 tsup: specifier: ^6.5.0 - version: 6.7.0(postcss@8.4.41)(ts-node@10.9.1(@types/node@20.3.1)(typescript@5.5.4))(typescript@5.5.4) + version: 6.7.0(postcss@8.5.32)(ts-node@10.9.1(@types/node@20.3.1)(typescript@5.5.4))(typescript@5.5.4) unconfig: specifier: ^0.3.10 version: 0.3.10 @@ -681,7 +681,7 @@ importers: version: link:../tsconfig tsup: specifier: ^6.5.0 - version: 6.7.0(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) + version: 6.7.0(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) typescript: specifier: 5.5.4 version: 5.5.4 @@ -757,7 +757,7 @@ importers: version: 3.59.1 svelte-check: specifier: ^2.10.3 - version: 2.10.3(@babel/core@7.23.6)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.4.41)(sass@1.77.8)(svelte@3.59.1) + version: 2.10.3(@babel/core@7.23.6)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.5.32)(sass@1.77.8)(svelte@3.59.1) tslib: specifier: ^2.5.0 version: 2.5.3 @@ -827,7 +827,7 @@ importers: version: link:../tsconfig tsup: specifier: ^6.5.0 - version: 6.7.0(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) + version: 6.7.0(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) typescript: specifier: 5.5.4 version: 5.5.4 @@ -876,7 +876,7 @@ importers: version: link:../tsconfig tsup: specifier: ^6.5.0 - version: 6.7.0(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) + version: 6.7.0(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) typescript: specifier: 5.5.4 version: 5.5.4 @@ -940,7 +940,7 @@ importers: version: link:../tsconfig tsup: specifier: ^6.5.0 - version: 6.7.0(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) + version: 6.7.0(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) typescript: specifier: 5.5.4 version: 5.5.4 @@ -1004,7 +1004,7 @@ importers: version: link:../tsconfig tsup: specifier: ^6.5.0 - version: 6.7.0(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) + version: 6.7.0(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) typescript: specifier: 5.5.4 version: 5.5.4 @@ -1089,7 +1089,7 @@ importers: version: 3.59.1 svelte-check: specifier: ^2.10.3 - version: 2.10.3(@babel/core@7.24.9)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.4.41)(sass@1.77.8)(svelte@3.59.1) + version: 2.10.3(@babel/core@7.24.9)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.5.32)(sass@1.77.8)(svelte@3.59.1) tslib: specifier: ^2.5.0 version: 2.5.3 @@ -1108,6 +1108,55 @@ importers: packages/tsconfig: {} + packages/vue: + dependencies: + '@tryabby/core': + specifier: workspace:* + version: link:../core + js-cookie: + specifier: ^3.0.1 + version: 3.0.5 + devDependencies: + '@tryabby/devtools': + specifier: workspace:* + version: link:../devtools + '@types/js-cookie': + specifier: ^3.0.3 + version: 3.0.3 + '@vue/server-renderer': + specifier: ^3.5.13 + version: 3.5.44 + '@vue/test-utils': + specifier: ^2.4.6 + version: 2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.44(typescript@5.5.4)) + jsdom: + specifier: ^20.0.3 + version: 20.0.3 + msw: + specifier: ^0.49.1 + version: 0.49.3(encoding@0.1.13)(typescript@5.5.4) + node-fetch: + specifier: ^3.3.0 + version: 3.3.2 + tsconfig: + specifier: workspace:* + version: link:../tsconfig + tsup: + specifier: ^6.5.0 + version: 6.7.0(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4) + typescript: + specifier: 5.5.4 + version: 5.5.4 + vite: + specifier: 5.4.0 + version: 5.4.0(@types/node@22.1.0)(less@4.2.0)(sass@1.77.8)(terser@5.31.1) + vitest: + specifier: 2.0.5 + version: 2.0.5(@types/node@22.1.0)(jsdom@20.0.3)(less@4.2.0)(sass@1.77.8)(terser@5.31.1) + vue: + specifier: ^3.5.13 + version: 3.5.44(typescript@5.5.4) + packages: '@adobe/css-tools@4.2.0': @@ -1582,6 +1631,10 @@ packages: resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.11': + resolution: {integrity: sha512-snZbO7MEDOof+hvNa97EjEY7qD7h2kwvQr5AJC3ZhQudKW5dnej6k3kP9NQV88hJwaS8vDqRLFo9rivLEhle2g==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.22.20': resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} @@ -1590,6 +1643,10 @@ packages: resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.22.5': resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} engines: {node: '>=6.9.0'} @@ -1656,11 +1713,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@7.24.4': - resolution: {integrity: sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/parser@7.24.7': resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} engines: {node: '>=6.0.0'} @@ -1671,6 +1723,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.11': + resolution: {integrity: sha512-OZ6+oaK7GMyg3IfCpj8JOmn8n+w2rJbDT0LLfVDTLb1ZFeKDh3AiNELgCMUw175IJHSkLl74hG0M0VLsvx+gag==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.3': resolution: {integrity: sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==} engines: {node: '>=6.9.0'} @@ -2673,6 +2730,10 @@ packages: resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.11': + resolution: {integrity: sha512-WCsemW40Cpc6gouC1SrY6PBaZ+oLRlEVY9XBvZBI7il/HyUrb2nJ505wE1MHEFyDZNnrWDEuy4jL50WVHfTTSQ==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -2892,7 +2953,7 @@ packages: '@emotion/use-insertion-effect-with-fallbacks@1.0.1': resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==} peerDependencies: - react: ^18.2.0 + react: '>=16.8.0' '@esbuild-plugins/node-globals-polyfill@0.2.3': resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} @@ -3750,6 +3811,9 @@ packages: '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + '@jridgewell/trace-mapping@0.3.18': resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} @@ -3845,7 +3909,7 @@ packages: '@mdx-js/react@2.3.0': resolution: {integrity: sha512-zQH//gdOmuu7nt2oJR29vFhDv88oGPmVw6BggmrHeMI+xgEkp1B2dX9/bMBSYtK0dyLX/aOmesKS09g222K1/g==} peerDependencies: - react: ^18.2.0 + react: '>=16' '@mdx-js/react@3.0.0': resolution: {integrity: sha512-nDctevR9KyYFyV+m+/+S4cpzCWHqj+iHDHq3QrsWezcC+B17uZdIWgCguESUkwFhM3n/56KxWVE3V6EokrmONQ==} @@ -4295,6 +4359,9 @@ packages: resolution: {integrity: sha512-TUkJLtI163Bz5+JK0O+zDkQpn4gKwN+BovclUvCj6pI/6RXrFqQvUMRS2M+Rt8Rv0qR3wjoMoOPmpJKeOh0nBg==} engines: {node: '>= 18'} + '@one-ini/wasm@0.2.1': + resolution: {integrity: sha512-TUqERXGNTifZ9y2g3wPxQrw3HpHv/02DsW3D90T9x0hhonrL1ZqpSmNrU2XkoIq0fP1N6gZfVQzy2Fw1ZvGBNg==} + '@open-draft/until@1.0.3': resolution: {integrity: sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==} @@ -4671,8 +4738,8 @@ packages: '@radix-ui/react-direction@1.1.0': resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} peerDependencies: - '@types/react': 18.0.26 - react: ^18.2.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -5161,8 +5228,8 @@ packages: '@radix-ui/react-use-layout-effect@1.1.0': resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} peerDependencies: - '@types/react': 18.0.26 - react: ^18.2.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -6690,9 +6757,21 @@ packages: '@vue/compiler-core@3.4.24': resolution: {integrity: sha512-vbW/tgbwJYj62N/Ww99x0zhFTkZDTcGh3uwJEuadZ/nF9/xuFMC4693P9r+3sxGXISABpDKvffY5ApH9pmdd1A==} + '@vue/compiler-core@3.5.44': + resolution: {integrity: sha512-k34nCytbK8PQ1gR2mGROYOw6Pnv/mumqIdrZ3x2tbyXZDWm7ViKGLTfdB+DRrWqEQsLgGJvn0WN9jBif5zCTLQ==} + '@vue/compiler-dom@3.4.24': resolution: {integrity: sha512-4XgABML/4cNndVsQndG6BbGN7+EoisDwi3oXNovqL/4jdNhwvP8/rfRMTb6FxkxIxUUtg6AI1/qZvwfSjxJiWA==} + '@vue/compiler-dom@3.5.44': + resolution: {integrity: sha512-W5AoBFWdw1lQAKiHowkfgFKFab82oSRT6sGsPfw/q1GRjsy/ZJFLHGhJyBRIFN9APLTUduDH9U2JAiPOIyKuYg==} + + '@vue/compiler-sfc@3.5.44': + resolution: {integrity: sha512-dzHmQ4jXTpdr5FjIQUeykVakN/uzqFbUo9/C5ikBFg3a3PeM6uRxeczx1ZbXBML0/zJstEh3ygYipzR5Z7b2Pw==} + + '@vue/compiler-ssr@3.5.44': + resolution: {integrity: sha512-xr5gb1JVHlfXJwSlRz1FeP6uxoazdzHuMTVLE7up+4Vrqxk219CvxLPxD9NXBt47yvZW7+p4DXfyp4O1fkByIA==} + '@vue/language-core@1.8.27': resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==} peerDependencies: @@ -6701,9 +6780,34 @@ packages: typescript: optional: true + '@vue/reactivity@3.5.44': + resolution: {integrity: sha512-u+QJdKeBBEADkPdevsL+6E12QlYVfBD8Zcw5qjDQKtamI6l14KyqazJMobhCKelhWN5zpyKUiEDoTyHE93cqWw==} + + '@vue/runtime-core@3.5.44': + resolution: {integrity: sha512-uEa/ndwjhrrhnOfb2p+sZy6zeoamJOISqaLSJGk/8R6nABT1ZldpzcJoPzKj+zHVomVBPcmQYyC2r4LtvDV6CQ==} + + '@vue/runtime-dom@3.5.44': + resolution: {integrity: sha512-3fc4ARcXVhVBaJ3ujWiNZJARD6pkyRcwG+ZYhMzjKtKUp7MAY0HLwr7r3Smep3Li6ZaWT6ewdmx8XqdaD5oNZg==} + + '@vue/server-renderer@3.5.44': + resolution: {integrity: sha512-R4S1UoH4h5Frrauv8Z5XE5TxV9oBiUSgWIC4TyVK1FK+RocRnOLwFA5Xcmo2011RlgJp+AbZCnw6afrhlgRuUQ==} + '@vue/shared@3.4.24': resolution: {integrity: sha512-BW4tajrJBM9AGAknnyEw5tO2xTmnqgup0VTnDAMcxYmqOX0RG0b9aSUGAbEKolD91tdwpA6oCwbltoJoNzpItw==} + '@vue/shared@3.5.44': + resolution: {integrity: sha512-H82XLH0DjmSOdbEwO15x3QTo1f5PWEtv237eLpYKc0mqLu+B8hnq16lFWmuBmNurkeiG3wr+oM1FhOll/YVFRg==} + + '@vue/test-utils@2.5.1': + resolution: {integrity: sha512-V/4a99odJ7hapr0bRt35XxljGk8hefq31gSOnlKTcEq2fUeoj2qb+FcpJYfQu4qfYhW9Ug+O2+CZ3QmZ7gXDzA==} + peerDependencies: + '@vue/compiler-dom': 3.x + '@vue/server-renderer': 3.x + vue: 3.x + peerDependenciesMeta: + '@vue/server-renderer': + optional: true + '@web3-storage/multipart-parser@1.0.0': resolution: {integrity: sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==} @@ -6786,6 +6890,10 @@ packages: resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + abbrev@5.0.0: + resolution: {integrity: sha512-/XrFJgzQQQHpti1raDJC6m4ws6aNktmjBlhk8Fdlk7LwCEuDoieEJJY9OFHjfiFJFFRM2tK+Ky/IsfbbmlMu1w==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -7141,6 +7249,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -7206,6 +7318,10 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} + braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -7576,6 +7692,10 @@ packages: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -7796,6 +7916,9 @@ packages: csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + csv-generate@3.4.3: resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==} @@ -8276,6 +8399,11 @@ packages: resolution: {integrity: sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==} hasBin: true + editorconfig@3.0.2: + resolution: {integrity: sha512-T0ix8GhtxyKVfUFEcvdNDt3YGqlwkFHbD4/5bgFUDgFmxhI/cSRAeJ87/Sz//Cq8Eam6JX/e23RkoFO71P7aAA==} + engines: {node: '>=20'} + hasBin: true + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -8345,6 +8473,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -8994,6 +9126,10 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} deprecated: Glob versions prior to v9 are no longer supported @@ -9882,10 +10018,18 @@ packages: engines: {node: '>=12'} hasBin: true + js-beautify@2.0.3: + resolution: {integrity: sha512-cyFbh3tkPhknnTD/0bLf0T0yy2ZIbqL05mttzbt4y1Zfr7NxqXQZ62dkBLKs3oHH/lpjmDRAnciJiSUyOy8XwQ==} + engines: {node: '>=14'} + hasBin: true + js-cookie@3.0.5: resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} engines: {node: '>=14'} + js-cookie@3.0.8: + resolution: {integrity: sha512-yeJd4aNAdYZQjaon2bpD/Gb0B/omw7HQOsynXXcOiWVCacbBcPlgn8S/d1X6blFSaHao7ozqtW7NZW19xpCtIw==} + js-levenshtein@1.1.6: resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} engines: {node: '>=0.10.0'} @@ -10220,6 +10364,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.5.3: + resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==} + engines: {node: 20 || >=22} + lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} @@ -10261,6 +10409,9 @@ packages: magic-string@0.30.10: resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magic-string@0.30.8: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} engines: {node: '>=12'} @@ -10713,6 +10864,10 @@ packages: minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + minimatch@3.0.8: resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} @@ -10774,6 +10929,10 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} @@ -10884,6 +11043,11 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -11131,6 +11295,11 @@ packages: resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} hasBin: true + nopt@10.0.1: + resolution: {integrity: sha512-df3sBr/6ax9hSGuC3CspvLlbnX8cP5L5nZwXF8cGN8l0zSWR6BvzmQ6jPUKjvo6+/xdpkNvEcucBNUdBeeV13g==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} + hasBin: true + nopt@6.0.0: resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -11516,6 +11685,10 @@ packages: resolution: {integrity: sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==} engines: {node: '>=16 || 14 >=14.17'} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} @@ -11569,6 +11742,9 @@ packages: picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} @@ -11735,6 +11911,10 @@ packages: resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.32: + resolution: {integrity: sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==} + engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} @@ -12414,11 +12594,6 @@ packages: rollup-pluginutils@2.8.2: resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - rollup@3.25.0: - resolution: {integrity: sha512-FnJkNRst2jEZGw7f+v4hFo6UTzpDKrAKcHZWcEfm5/GJQ5CK7wgb4moNLNAe7npKUev7yQn1AY/YbZRIxOv6Qg==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} - hasBin: true - rollup@3.27.1: resolution: {integrity: sha512-tXNDFwOkN6C2w5Blj1g6ForKeFw6c1mDu5jxoeDO3/pmYjgt+8yvIFjKzH5FQUq70OKZBkOt0zzv0THXL7vwzQ==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} @@ -12587,6 +12762,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -12771,6 +12951,10 @@ packages: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + source-map-loader@5.0.0: resolution: {integrity: sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==} engines: {node: '>= 18.12.0'} @@ -12791,6 +12975,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} @@ -13964,6 +14149,9 @@ packages: vscode-textmate@8.0.0: resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} + vue-component-type-helpers@3.3.13: + resolution: {integrity: sha512-02KCxSmKDhIITjKyJ4QT5csP6L0WoRborLqY/34a40+S9uvMvdNgMV0yVjO3p2Gkz3ZoPmFz/0JsGHacwJYTxw==} + vue-template-compiler@2.7.16: resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==} @@ -13973,6 +14161,14 @@ packages: peerDependencies: typescript: '*' + vue@3.5.44: + resolution: {integrity: sha512-dvvmaOCG7lAMkJTPqPwWeGMsPS6DIsFsfZDUgBp9V6mHf9b3+/wyVwYR4Es+WV6uJC0FKRxp81Obcq0ZwUcGFQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} @@ -14046,7 +14242,7 @@ packages: engines: {node: '>= 18.12.0'} hasBin: true peerDependencies: - webpack: 5.93.0 + webpack: ^5.0.0 webpack-cli: '*' peerDependenciesMeta: webpack: @@ -14099,6 +14295,7 @@ packages: whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-fetch@3.6.2: resolution: {integrity: sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==} @@ -14708,7 +14905,7 @@ snapshots: '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.21.8) '@babel/helpers': 7.24.4 - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.3 '@babel/template': 7.24.0 '@babel/traverse': 7.24.1 '@babel/types': 7.24.7 @@ -14748,7 +14945,7 @@ snapshots: '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) '@babel/helpers': 7.24.4 - '@babel/parser': 7.24.4 + '@babel/parser': 7.25.3 '@babel/template': 7.24.0 '@babel/traverse': 7.24.1 '@babel/types': 7.24.0 @@ -14816,7 +15013,7 @@ snapshots: '@babel/generator@7.24.4': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 @@ -14845,7 +15042,7 @@ snapshots: '@babel/helper-builder-binary-assignment-operator-visitor@7.22.5': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 '@babel/helper-builder-binary-assignment-operator-visitor@7.24.7': dependencies: @@ -15008,7 +15205,7 @@ snapshots: '@babel/helper-function-name@7.23.0': dependencies: '@babel/template': 7.24.7 - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 '@babel/helper-function-name@7.24.7': dependencies: @@ -15017,7 +15214,7 @@ snapshots: '@babel/helper-hoist-variables@7.22.5': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 '@babel/helper-hoist-variables@7.24.7': dependencies: @@ -15025,7 +15222,7 @@ snapshots: '@babel/helper-member-expression-to-functions@7.22.5': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 '@babel/helper-member-expression-to-functions@7.24.8': dependencies: @@ -15142,7 +15339,7 @@ snapshots: '@babel/helper-optimise-call-expression@7.22.5': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 '@babel/helper-optimise-call-expression@7.24.7': dependencies: @@ -15160,7 +15357,7 @@ snapshots: '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-wrap-function': 7.22.5 - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 transitivePeerDependencies: - supports-color @@ -15170,7 +15367,7 @@ snapshots: '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-wrap-function': 7.22.5 - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 transitivePeerDependencies: - supports-color @@ -15190,7 +15387,7 @@ snapshots: '@babel/helper-optimise-call-expression': 7.22.5 '@babel/template': 7.24.7 '@babel/traverse': 7.24.7 - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 transitivePeerDependencies: - supports-color @@ -15216,7 +15413,7 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers@7.22.5': dependencies: - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 '@babel/helper-skip-transparent-expression-wrappers@7.24.7': dependencies: @@ -15239,10 +15436,14 @@ snapshots: '@babel/helper-string-parser@7.24.8': {} + '@babel/helper-string-parser@7.29.11': {} + '@babel/helper-validator-identifier@7.22.20': {} '@babel/helper-validator-identifier@7.24.7': {} + '@babel/helper-validator-identifier@7.29.7': {} + '@babel/helper-validator-option@7.22.5': {} '@babel/helper-validator-option@7.23.5': {} @@ -15256,7 +15457,7 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/template': 7.22.15 '@babel/traverse': 7.23.6 - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 transitivePeerDependencies: - supports-color @@ -15280,7 +15481,7 @@ snapshots: dependencies: '@babel/template': 7.24.7 '@babel/traverse': 7.24.7 - '@babel/types': 7.24.7 + '@babel/types': 7.25.2 transitivePeerDependencies: - supports-color @@ -15328,10 +15529,6 @@ snapshots: dependencies: '@babel/types': 7.23.6 - '@babel/parser@7.24.4': - dependencies: - '@babel/types': 7.24.7 - '@babel/parser@7.24.7': dependencies: '@babel/types': 7.24.7 @@ -15340,6 +15537,10 @@ snapshots: dependencies: '@babel/types': 7.25.2 + '@babel/parser@7.29.11': + dependencies: + '@babel/types': 7.29.11 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.3(@babel/core@7.24.7)': dependencies: '@babel/core': 7.24.7 @@ -17057,14 +17258,14 @@ snapshots: '@babel/template@7.22.15': dependencies: '@babel/code-frame': 7.24.7 - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.3 '@babel/types': 7.24.7 '@babel/template@7.24.0': dependencies: '@babel/code-frame': 7.24.7 - '@babel/parser': 7.24.7 - '@babel/types': 7.24.7 + '@babel/parser': 7.25.3 + '@babel/types': 7.25.2 '@babel/template@7.24.7': dependencies: @@ -17086,7 +17287,7 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.3 '@babel/types': 7.24.7 debug: 4.3.5 globals: 11.12.0 @@ -17101,7 +17302,7 @@ snapshots: '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.3 '@babel/types': 7.24.7 debug: 4.3.5 globals: 11.12.0 @@ -17116,8 +17317,8 @@ snapshots: '@babel/helper-function-name': 7.24.7 '@babel/helper-hoist-variables': 7.24.7 '@babel/helper-split-export-declaration': 7.24.7 - '@babel/parser': 7.24.7 - '@babel/types': 7.24.7 + '@babel/parser': 7.25.3 + '@babel/types': 7.25.2 debug: 4.3.5 globals: 11.12.0 transitivePeerDependencies: @@ -17180,6 +17381,11 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + '@babel/types@7.29.11': + dependencies: + '@babel/helper-string-parser': 7.29.11 + '@babel/helper-validator-identifier': 7.29.7 + '@bcoe/v8-coverage@0.2.3': {} '@biomejs/biome@1.9.4': @@ -18088,6 +18294,8 @@ snapshots: '@jridgewell/sourcemap-codec@1.4.15': {} + '@jridgewell/sourcemap-codec@1.6.0': {} + '@jridgewell/trace-mapping@0.3.18': dependencies: '@jridgewell/resolve-uri': 3.1.0 @@ -18691,6 +18899,8 @@ snapshots: '@octokit/request-error': 6.1.4 '@octokit/webhooks-methods': 5.1.0 + '@one-ini/wasm@0.2.1': {} + '@open-draft/until@1.0.3': {} '@openpanel/nextjs@1.0.3(next@14.1.1(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': @@ -20702,7 +20912,7 @@ snapshots: ts-dedent: 2.2.0 util-deprecate: 1.0.2 watchpack: 2.4.1 - ws: 8.13.0 + ws: 8.18.0 transitivePeerDependencies: - bufferutil - encoding @@ -21291,7 +21501,7 @@ snapshots: '@types/babel__core@7.20.1': dependencies: - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.3 '@babel/types': 7.24.7 '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 @@ -21315,7 +21525,7 @@ snapshots: '@types/babel__template@7.4.1': dependencies: - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.3 '@babel/types': 7.24.7 '@types/babel__template@7.4.4': @@ -21841,17 +22051,47 @@ snapshots: '@vue/compiler-core@3.4.24': dependencies: - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.3 '@vue/shared': 3.4.24 entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.2.0 + '@vue/compiler-core@3.5.44': + dependencies: + '@babel/parser': 7.29.11 + '@vue/shared': 3.5.44 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.2 + '@vue/compiler-dom@3.4.24': dependencies: '@vue/compiler-core': 3.4.24 '@vue/shared': 3.4.24 + '@vue/compiler-dom@3.5.44': + dependencies: + '@vue/compiler-core': 3.5.44 + '@vue/shared': 3.5.44 + + '@vue/compiler-sfc@3.5.44': + dependencies: + '@babel/parser': 7.29.11 + '@vue/compiler-core': 3.5.44 + '@vue/compiler-dom': 3.5.44 + '@vue/compiler-ssr': 3.5.44 + '@vue/shared': 3.5.44 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.32 + source-map-js: 1.2.2 + + '@vue/compiler-ssr@3.5.44': + dependencies: + '@vue/compiler-dom': 3.5.44 + '@vue/shared': 3.5.44 + '@vue/language-core@1.8.27(typescript@5.5.4)': dependencies: '@volar/language-core': 1.11.1 @@ -21866,8 +22106,41 @@ snapshots: optionalDependencies: typescript: 5.5.4 + '@vue/reactivity@3.5.44': + dependencies: + '@vue/shared': 3.5.44 + + '@vue/runtime-core@3.5.44': + dependencies: + '@vue/reactivity': 3.5.44 + '@vue/shared': 3.5.44 + + '@vue/runtime-dom@3.5.44': + dependencies: + '@vue/reactivity': 3.5.44 + '@vue/runtime-core': 3.5.44 + '@vue/shared': 3.5.44 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.44': + dependencies: + '@vue/compiler-ssr': 3.5.44 + '@vue/runtime-dom': 3.5.44 + '@vue/shared': 3.5.44 + '@vue/shared@3.4.24': {} + '@vue/shared@3.5.44': {} + + '@vue/test-utils@2.5.1(@vue/compiler-dom@3.5.44)(@vue/server-renderer@3.5.44)(vue@3.5.44(typescript@5.5.4))': + dependencies: + '@vue/compiler-dom': 3.5.44 + js-beautify: 2.0.3 + vue: 3.5.44(typescript@5.5.4) + vue-component-type-helpers: 3.3.13 + optionalDependencies: + '@vue/server-renderer': 3.5.44 + '@web3-storage/multipart-parser@1.0.0': {} '@webassemblyjs/ast@1.12.1': @@ -21968,6 +22241,8 @@ snapshots: abbrev@2.0.0: {} + abbrev@5.0.0: {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -21979,7 +22254,7 @@ snapshots: acorn-globals@7.0.1: dependencies: - acorn: 8.11.3 + acorn: 8.12.0 acorn-walk: 8.3.2 acorn-import-assertions@1.9.0(acorn@8.12.0): @@ -21991,10 +22266,6 @@ snapshots: dependencies: acorn: 8.12.0 - acorn-jsx@5.3.2(acorn@8.11.3): - dependencies: - acorn: 8.11.3 - acorn-jsx@5.3.2(acorn@8.12.0): dependencies: acorn: 8.12.0 @@ -22327,6 +22598,8 @@ snapshots: balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + base64-js@1.5.1: {} base64id@2.0.0: {} @@ -22407,6 +22680,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.12: + dependencies: + balanced-match: 4.0.4 + braces@3.0.2: dependencies: fill-range: 7.0.1 @@ -22798,6 +23075,8 @@ snapshots: commander@12.1.0: {} + commander@14.0.3: {} + commander@2.20.3: {} commander@4.1.1: {} @@ -23018,6 +23297,8 @@ snapshots: csstype@3.1.2: {} + csstype@3.2.3: {} + csv-generate@3.4.3: {} csv-parse@4.16.3: {} @@ -23508,6 +23789,13 @@ snapshots: semver: 5.7.1 sigmund: 1.0.1 + editorconfig@3.0.2: + dependencies: + '@one-ini/wasm': 0.2.1 + commander: 14.0.3 + minimatch: 10.2.6 + semver: 7.8.5 + ee-first@1.1.1: {} ejs@3.1.9: @@ -23575,6 +23863,8 @@ snapshots: entities@4.5.0: {} + entities@7.0.1: {} + env-paths@2.2.1: {} envinfo@7.8.1: {} @@ -23874,8 +24164,8 @@ snapshots: espree@9.2.0: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.0 + acorn-jsx: 5.3.2(acorn@8.12.0) eslint-visitor-keys: 3.4.1 espree@9.5.2: @@ -24460,6 +24750,12 @@ snapshots: package-json-from-dist: 1.0.0 path-scurry: 1.11.1 + glob@13.0.6: + dependencies: + minimatch: 10.2.6 + minipass: 7.1.3 + path-scurry: 2.0.2 + glob@7.1.6: dependencies: fs.realpath: 1.0.0 @@ -25507,8 +25803,18 @@ snapshots: glob: 8.1.0 nopt: 6.0.0 + js-beautify@2.0.3: + dependencies: + config-chain: 1.1.13 + editorconfig: 3.0.2 + glob: 13.0.6 + js-cookie: 3.0.8 + nopt: 10.0.1 + js-cookie@3.0.5: {} + js-cookie@3.0.8: {} + js-levenshtein@1.1.6: {} js-tokens@4.0.0: {} @@ -25527,7 +25833,7 @@ snapshots: jscodeshift@0.14.0(@babel/preset-env@7.21.5(@babel/core@7.21.8)): dependencies: '@babel/core': 7.24.4 - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.3 '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.4) '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.4) '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.4) @@ -25552,7 +25858,7 @@ snapshots: jscodeshift@0.14.0(@babel/preset-env@7.22.5(@babel/core@7.23.6)): dependencies: '@babel/core': 7.24.4 - '@babel/parser': 7.24.7 + '@babel/parser': 7.25.3 '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.4) '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.4) '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.4) @@ -25577,7 +25883,7 @@ snapshots: jsdom@20.0.3: dependencies: abab: 2.0.6 - acorn: 8.11.2 + acorn: 8.12.0 acorn-globals: 7.0.1 cssom: 0.5.0 cssstyle: 2.3.0 @@ -25600,7 +25906,7 @@ snapshots: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 11.0.0 - ws: 8.13.0 + ws: 8.18.0 xml-name-validator: 4.0.0 transitivePeerDependencies: - bufferutil @@ -25961,6 +26267,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.5.3: {} + lru-cache@4.1.5: dependencies: pseudomap: 1.0.2 @@ -26000,6 +26308,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + magic-string@0.30.8: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 @@ -26602,8 +26914,8 @@ snapshots: micromark-extension-mdxjs@1.0.1: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.0 + acorn-jsx: 5.3.2(acorn@8.12.0) micromark-extension-mdx-expression: 1.0.8 micromark-extension-mdx-jsx: 1.0.5 micromark-extension-mdx-md: 1.0.1 @@ -26613,8 +26925,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.0 + acorn-jsx: 5.3.2(acorn@8.12.0) micromark-extension-mdx-expression: 3.0.0 micromark-extension-mdx-jsx: 3.0.0 micromark-extension-mdx-md: 2.0.0 @@ -26948,6 +27260,10 @@ snapshots: minimalistic-assert@1.0.1: {} + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.12 + minimatch@3.0.8: dependencies: brace-expansion: 1.1.11 @@ -27010,6 +27326,8 @@ snapshots: minipass@7.1.2: {} + minipass@7.1.3: {} + minizlib@2.1.2: dependencies: minipass: 3.3.6 @@ -27036,7 +27354,7 @@ snapshots: mlly@1.6.1: dependencies: - acorn: 8.11.3 + acorn: 8.12.0 pathe: 1.1.2 pkg-types: 1.0.3 ufo: 1.5.3 @@ -27085,7 +27403,7 @@ snapshots: '@types/cookie': 0.4.1 '@types/js-levenshtein': 1.1.1 chalk: 4.1.1 - chokidar: 3.5.3 + chokidar: 3.6.0 cookie: 0.4.2 graphql: 16.6.0 headers-polyfill: 3.1.2 @@ -27150,6 +27468,8 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 + nanoid@3.3.20: {} + nanoid@3.3.6: {} nanoid@3.3.7: {} @@ -27227,7 +27547,7 @@ snapshots: minimist: 1.2.8 next: 14.1.1(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8) - next-themes@0.2.1(next@14.1.1(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + next-themes@0.2.1(next@14.1.1(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: next: 14.1.1(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8) react: 18.2.0 @@ -27306,7 +27626,7 @@ snapshots: match-sorter: 6.3.1 next: 14.1.1(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8) next-seo: 6.4.0(next@14.1.1(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - next-themes: 0.2.1(next@14.1.1(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + next-themes: 0.2.1(next@14.1.1(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) nextra: 2.13.2(next@14.1.1(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.8))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -27475,6 +27795,10 @@ snapshots: dependencies: abbrev: 1.1.1 + nopt@10.0.1: + dependencies: + abbrev: 5.0.0 + nopt@6.0.0: dependencies: abbrev: 1.1.1 @@ -27922,6 +28246,11 @@ snapshots: lru-cache: 9.1.2 minipass: 5.0.0 + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.3 + minipass: 7.1.3 + path-to-regexp@0.1.7: {} path-to-regexp@6.2.1: {} @@ -27968,6 +28297,8 @@ snapshots: picocolors@1.0.1: {} + picocolors@1.1.1: {} + picomatch@2.3.1: {} picomatch@4.0.2: {} @@ -28033,20 +28364,20 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.24 - postcss-load-config@3.1.4(postcss@8.4.41)(ts-node@10.9.1(@types/node@20.3.1)(typescript@5.5.4)): + postcss-load-config@3.1.4(postcss@8.5.32)(ts-node@10.9.1(@types/node@20.3.1)(typescript@5.5.4)): dependencies: lilconfig: 2.1.0 yaml: 1.10.2 optionalDependencies: - postcss: 8.4.41 + postcss: 8.5.32 ts-node: 10.9.1(@types/node@20.3.1)(typescript@5.5.4) - postcss-load-config@3.1.4(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)): + postcss-load-config@3.1.4(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)): dependencies: lilconfig: 2.1.0 yaml: 1.10.2 optionalDependencies: - postcss: 8.4.41 + postcss: 8.5.32 ts-node: 10.9.1(@types/node@22.1.0)(typescript@5.5.4) postcss-load-config@4.0.1(postcss@8.4.24)(ts-node@10.9.1(@types/node@18.16.17)(typescript@5.5.4)): @@ -28066,12 +28397,12 @@ snapshots: ts-node: 10.9.1(@types/node@20.3.1)(typescript@5.5.4) optional: true - postcss-load-config@4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)): + postcss-load-config@4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 optionalDependencies: - postcss: 8.4.41 + postcss: 8.5.32 ts-node: 10.9.1(@types/node@22.1.0)(typescript@5.5.4) optional: true @@ -28156,6 +28487,12 @@ snapshots: picocolors: 1.0.1 source-map-js: 1.2.0 + postcss@8.5.32: + dependencies: + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + postgres-array@2.0.0: {} postgres-bytea@1.0.0: {} @@ -28943,10 +29280,6 @@ snapshots: dependencies: estree-walker: 0.6.1 - rollup@3.25.0: - optionalDependencies: - fsevents: 2.3.3 - rollup@3.27.1: optionalDependencies: fsevents: 2.3.3 @@ -29118,6 +29451,8 @@ snapshots: semver@7.6.2: {} + semver@7.8.5: {} + send@0.18.0: dependencies: debug: 2.6.9 @@ -29393,6 +29728,8 @@ snapshots: source-map-js@1.2.0: {} + source-map-js@1.2.2: {} + source-map-loader@5.0.0(webpack@5.92.1(esbuild@0.21.5)): dependencies: iconv-lite: 0.6.3 @@ -29689,7 +30026,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@2.10.3(@babel/core@7.23.6)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.4.41)(sass@1.77.8)(svelte@3.59.1): + svelte-check@2.10.3(@babel/core@7.23.6)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.5.32)(sass@1.77.8)(svelte@3.59.1): dependencies: '@jridgewell/trace-mapping': 0.3.18 chokidar: 3.5.3 @@ -29698,7 +30035,7 @@ snapshots: picocolors: 1.0.0 sade: 1.8.1 svelte: 3.59.1 - svelte-preprocess: 4.10.7(@babel/core@7.23.6)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.4.41)(sass@1.77.8)(svelte@3.59.1)(typescript@5.5.4) + svelte-preprocess: 4.10.7(@babel/core@7.23.6)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.5.32)(sass@1.77.8)(svelte@3.59.1)(typescript@5.5.4) typescript: 5.5.4 transitivePeerDependencies: - '@babel/core' @@ -29712,7 +30049,7 @@ snapshots: - stylus - sugarss - svelte-check@2.10.3(@babel/core@7.24.9)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.4.41)(sass@1.77.8)(svelte@3.59.1): + svelte-check@2.10.3(@babel/core@7.24.9)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.5.32)(sass@1.77.8)(svelte@3.59.1): dependencies: '@jridgewell/trace-mapping': 0.3.18 chokidar: 3.5.3 @@ -29721,7 +30058,7 @@ snapshots: picocolors: 1.0.0 sade: 1.8.1 svelte: 3.59.1 - svelte-preprocess: 4.10.7(@babel/core@7.24.9)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.4.41)(sass@1.77.8)(svelte@3.59.1)(typescript@5.5.4) + svelte-preprocess: 4.10.7(@babel/core@7.24.9)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.5.32)(sass@1.77.8)(svelte@3.59.1)(typescript@5.5.4) typescript: 5.5.4 transitivePeerDependencies: - '@babel/core' @@ -29739,7 +30076,7 @@ snapshots: dependencies: svelte: 3.59.1 - svelte-preprocess@4.10.7(@babel/core@7.23.6)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.4.41)(sass@1.77.8)(svelte@3.59.1)(typescript@5.5.4): + svelte-preprocess@4.10.7(@babel/core@7.23.6)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.5.32)(sass@1.77.8)(svelte@3.59.1)(typescript@5.5.4): dependencies: '@types/pug': 2.0.6 '@types/sass': 1.45.0 @@ -29751,12 +30088,12 @@ snapshots: optionalDependencies: '@babel/core': 7.23.6 less: 4.2.0 - postcss: 8.4.41 - postcss-load-config: 4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)) + postcss: 8.5.32 + postcss-load-config: 4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)) sass: 1.77.8 typescript: 5.5.4 - svelte-preprocess@4.10.7(@babel/core@7.24.9)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.4.41)(sass@1.77.8)(svelte@3.59.1)(typescript@5.5.4): + svelte-preprocess@4.10.7(@babel/core@7.24.9)(less@4.2.0)(postcss-load-config@4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)))(postcss@8.5.32)(sass@1.77.8)(svelte@3.59.1)(typescript@5.5.4): dependencies: '@types/pug': 2.0.6 '@types/sass': 1.45.0 @@ -29768,8 +30105,8 @@ snapshots: optionalDependencies: '@babel/core': 7.24.9 less: 4.2.0 - postcss: 8.4.41 - postcss-load-config: 4.0.1(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)) + postcss: 8.5.32 + postcss-load-config: 4.0.1(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)) sass: 1.77.8 typescript: 5.5.4 @@ -30151,47 +30488,47 @@ snapshots: tsscmp@1.0.6: {} - tsup@6.7.0(postcss@8.4.41)(ts-node@10.9.1(@types/node@20.3.1)(typescript@5.5.4))(typescript@5.5.4): + tsup@6.7.0(postcss@8.5.32)(ts-node@10.9.1(@types/node@20.3.1)(typescript@5.5.4))(typescript@5.5.4): dependencies: bundle-require: 4.0.1(esbuild@0.17.19) cac: 6.7.14 - chokidar: 3.5.3 - debug: 4.3.4 + chokidar: 3.6.0 + debug: 4.3.5 esbuild: 0.17.19 execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 3.1.4(postcss@8.4.41)(ts-node@10.9.1(@types/node@20.3.1)(typescript@5.5.4)) + postcss-load-config: 3.1.4(postcss@8.5.32)(ts-node@10.9.1(@types/node@20.3.1)(typescript@5.5.4)) resolve-from: 5.0.0 - rollup: 3.25.0 + rollup: 3.29.4 source-map: 0.8.0-beta.0 sucrase: 3.32.0 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.4.41 + postcss: 8.5.32 typescript: 5.5.4 transitivePeerDependencies: - supports-color - ts-node - tsup@6.7.0(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4): + tsup@6.7.0(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4))(typescript@5.5.4): dependencies: bundle-require: 4.0.1(esbuild@0.17.19) cac: 6.7.14 - chokidar: 3.5.3 - debug: 4.3.4 + chokidar: 3.6.0 + debug: 4.3.5 esbuild: 0.17.19 execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 3.1.4(postcss@8.4.41)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)) + postcss-load-config: 3.1.4(postcss@8.5.32)(ts-node@10.9.1(@types/node@22.1.0)(typescript@5.5.4)) resolve-from: 5.0.0 - rollup: 3.25.0 + rollup: 3.29.4 source-map: 0.8.0-beta.0 sucrase: 3.32.0 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.4.41 + postcss: 8.5.32 typescript: 5.5.4 transitivePeerDependencies: - supports-color @@ -30905,6 +31242,8 @@ snapshots: vscode-textmate@8.0.0: {} + vue-component-type-helpers@3.3.13: {} + vue-template-compiler@2.7.16: dependencies: de-indent: 1.0.2 @@ -30917,6 +31256,16 @@ snapshots: semver: 7.6.0 typescript: 5.5.4 + vue@3.5.44(typescript@5.5.4): + dependencies: + '@vue/compiler-dom': 3.5.44 + '@vue/compiler-sfc': 3.5.44 + '@vue/runtime-dom': 3.5.44 + '@vue/server-renderer': 3.5.44 + '@vue/shared': 3.5.44 + optionalDependencies: + typescript: 5.5.4 + w3c-keyname@2.2.8: {} w3c-xmlserializer@4.0.0: