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
+
+
+
+
+ Cool Button
+
+
+```
+
+Optionally, you can pass a lookup object to automatically map the selected variant to a custom value.
+
+```vue
+
+
+
+ Cool Button
+
+```
+
+
+ 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
+
+
+
+ Here is the new feature
+
+```
+
+### 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
+
+
+
+ {{ customButtonText }}
+
+```
+
+### 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
+
+
+
+ Here is the new feature
+ {{ buttonText }}
+
+```
+
+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: