diff --git a/packages/visual-editor/THIRD-PARTY-NOTICES b/packages/visual-editor/THIRD-PARTY-NOTICES index 7de02992ed..9200bd093e 100644 --- a/packages/visual-editor/THIRD-PARTY-NOTICES +++ b/packages/visual-editor/THIRD-PARTY-NOTICES @@ -1163,7 +1163,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. The following npm packages may be included in this product: - - @measured/puck@0.20.2 + - @measured/puck-plugin-heading-analyzer@0.20.2 + - @measured/puck@0.21.0-canary.c0db75c1 - next-themes@0.3.0 These packages each contain the following license: diff --git a/packages/visual-editor/package.json b/packages/visual-editor/package.json index f44dbb5d25..bcbfd65e81 100644 --- a/packages/visual-editor/package.json +++ b/packages/visual-editor/package.json @@ -61,10 +61,13 @@ "i18n:check-empty": "pnpm exec tsx scripts/checkEmptyTranslations.ts" }, "dependencies": { - "@measured/puck": "0.20.2", + "@measured/puck": "0.21.0-canary.c0db75c1", + "@measured/puck-plugin-heading-analyzer": "^0.20.2", "@microsoft/api-documenter": "^7.26.29", "@microsoft/api-extractor": "^7.52.8", "@microsoft/api-extractor-model": "^7.30.6", + "@puckeditor/cloud-client": "^0.3.1", + "@puckeditor/plugin-ai": "^0.3.1", "@radix-ui/react-accordion": "^1.2.3", "@radix-ui/react-alert-dialog": "^1.1.1", "@radix-ui/react-dialog": "^1.1.13", @@ -155,7 +158,7 @@ "vite": "^5.3.5", "vitepress": "^1.6.3", "vitest": "^3.2.4", - "zod": "^3.23.8" + "zod": "^4.1.13" }, "peerDependencies": { "@yext/pages-components": "1.1.16", diff --git a/packages/visual-editor/src/components/categories/SlotsCategory.tsx b/packages/visual-editor/src/components/categories/SlotsCategory.tsx index 3c91d16c9a..79042a4d6d 100644 --- a/packages/visual-editor/src/components/categories/SlotsCategory.tsx +++ b/packages/visual-editor/src/components/categories/SlotsCategory.tsx @@ -192,81 +192,82 @@ const ExpandedHeaderComponents = { }, }; -export const SlotsCategoryComponents = { - AddressSlot: { ...Address, permissions: lockedPermissions }, - BodyTextSlot: { ...BodyText, permissions: lockedPermissions }, - BreadcrumbsSlot: { ...BreadcrumbsSection, permissions: lockedPermissions }, - CopyrightMessageSlot: { - ...CopyrightMessageSlot, - permissions: lockedPermissions, - }, - CTASlot: { ...CTAWrapper, permissions: lockedPermissions }, - DirectoryCard: { ...DirectoryCard, permissions: lockedPermissions }, - DirectoryGrid: { ...DirectoryGrid, permissions: lockedPermissions }, - EmailsSlot: { ...Emails, permissions: lockedPermissions }, - EventCard: { ...EventCard, permissions: lockedPermissions }, - EventCardsWrapper: { ...EventCardsWrapper, permissions: lockedPermissions }, - ...ExpandedHeaderComponents, - FAQsWrapperSlot: { ...FAQsWrapperSlot, permissions: lockedPermissions }, - FAQSlot: { ...FAQSlot, permissions: lockedPermissions }, - FooterExpandedLinkSectionSlot: { - ...FooterExpandedLinkSectionSlot, - permissions: lockedPermissions, - }, - FooterExpandedLinksWrapper: { - ...FooterExpandedLinksWrapper, - permissions: lockedPermissions, - }, - FooterLinksSlot: { ...FooterLinksSlot, permissions: lockedPermissions }, - FooterLogoSlot: { ...FooterLogoSlot, permissions: lockedPermissions }, - FooterSocialLinksSlot: { - ...FooterSocialLinksSlot, - permissions: lockedPermissions, - }, - FooterUtilityImagesSlot: { - ...FooterUtilityImagesSlot, - permissions: lockedPermissions, - }, - HeadingTextSlot: { ...HeadingText, permissions: lockedPermissions }, - HeroImageSlot: { ...HeroImage, permissions: lockedPermissions }, - HoursStatusSlot: { ...HoursStatus, permissions: lockedPermissions }, - HoursTableSlot: { ...HoursTable, permissions: lockedPermissions }, - ImageSlot: { ...ImageWrapper, permissions: lockedPermissions }, - InsightCardsWrapper: { - ...InsightCardsWrapper, - permissions: lockedPermissions, - }, - InsightCard: { ...InsightCard, permissions: lockedPermissions }, - NearbyLocationCardsWrapper: { - ...NearbyLocationCardsWrapper, - permissions: lockedPermissions, - }, - PhoneNumbersSlot: { ...PhoneList, permissions: lockedPermissions }, - PhoneSlot: { ...Phone, permissions: lockedPermissions }, - PhotoGalleryWrapper: { - ...PhotoGalleryWrapper, - permissions: lockedPermissions, - }, - ProductCardsWrapper: { - ...ProductCardsWrapper, - permissions: lockedPermissions, - }, - ProductCard: { ...ProductCard, permissions: lockedPermissions }, - SecondaryFooterSlot: { - ...SecondaryFooterSlot, - permissions: lockedPermissions, - }, - TeamCard: { ...TeamCard, permissions: lockedPermissions }, - TeamCardsWrapper: { ...TeamCardsWrapper, permissions: lockedPermissions }, - TestimonialCard: { ...TestimonialCard, permissions: lockedPermissions }, - TestimonialCardsWrapper: { - ...TestimonialCardsWrapper, - permissions: lockedPermissions, - }, - TextListSlot: { ...TextList, permissions: lockedPermissions }, - Timestamp: { ...Timestamp, permissions: lockedPermissions }, - VideoSlot: { ...Video, permissions: lockedPermissions }, -}; +export const SlotsCategoryComponents: { [K in keyof SlotsCategoryProps]: any } = + { + AddressSlot: { ...Address, permissions: lockedPermissions }, + BodyTextSlot: { ...BodyText, permissions: lockedPermissions }, + BreadcrumbsSlot: { ...BreadcrumbsSection, permissions: lockedPermissions }, + CopyrightMessageSlot: { + ...CopyrightMessageSlot, + permissions: lockedPermissions, + }, + CTASlot: { ...CTAWrapper, permissions: lockedPermissions }, + DirectoryCard: { ...DirectoryCard, permissions: lockedPermissions }, + DirectoryGrid: { ...DirectoryGrid, permissions: lockedPermissions }, + EmailsSlot: { ...Emails, permissions: lockedPermissions }, + EventCard: { ...EventCard, permissions: lockedPermissions }, + EventCardsWrapper: { ...EventCardsWrapper, permissions: lockedPermissions }, + ...ExpandedHeaderComponents, + FAQsWrapperSlot: { ...FAQsWrapperSlot, permissions: lockedPermissions }, + FAQSlot: { ...FAQSlot, permissions: lockedPermissions }, + FooterExpandedLinkSectionSlot: { + ...FooterExpandedLinkSectionSlot, + permissions: lockedPermissions, + }, + FooterExpandedLinksWrapper: { + ...FooterExpandedLinksWrapper, + permissions: lockedPermissions, + }, + FooterLinksSlot: { ...FooterLinksSlot, permissions: lockedPermissions }, + FooterLogoSlot: { ...FooterLogoSlot, permissions: lockedPermissions }, + FooterSocialLinksSlot: { + ...FooterSocialLinksSlot, + permissions: lockedPermissions, + }, + FooterUtilityImagesSlot: { + ...FooterUtilityImagesSlot, + permissions: lockedPermissions, + }, + HeadingTextSlot: { ...HeadingText, permissions: lockedPermissions }, + HeroImageSlot: { ...HeroImage, permissions: lockedPermissions }, + HoursStatusSlot: { ...HoursStatus, permissions: lockedPermissions }, + HoursTableSlot: { ...HoursTable, permissions: lockedPermissions }, + ImageSlot: { ...ImageWrapper, permissions: lockedPermissions }, + InsightCardsWrapper: { + ...InsightCardsWrapper, + permissions: lockedPermissions, + }, + InsightCard: { ...InsightCard, permissions: lockedPermissions }, + NearbyLocationCardsWrapper: { + ...NearbyLocationCardsWrapper, + permissions: lockedPermissions, + }, + PhoneNumbersSlot: { ...PhoneList, permissions: lockedPermissions }, + PhoneSlot: { ...Phone, permissions: lockedPermissions }, + PhotoGalleryWrapper: { + ...PhotoGalleryWrapper, + permissions: lockedPermissions, + }, + ProductCardsWrapper: { + ...ProductCardsWrapper, + permissions: lockedPermissions, + }, + ProductCard: { ...ProductCard, permissions: lockedPermissions }, + SecondaryFooterSlot: { + ...SecondaryFooterSlot, + permissions: lockedPermissions, + }, + TeamCard: { ...TeamCard, permissions: lockedPermissions }, + TeamCardsWrapper: { ...TeamCardsWrapper, permissions: lockedPermissions }, + TestimonialCard: { ...TestimonialCard, permissions: lockedPermissions }, + TestimonialCardsWrapper: { + ...TestimonialCardsWrapper, + permissions: lockedPermissions, + }, + TextListSlot: { ...TextList, permissions: lockedPermissions }, + Timestamp: { ...Timestamp, permissions: lockedPermissions }, + VideoSlot: { ...Video, permissions: lockedPermissions }, + }; export const SlotsCategory = Object.keys( SlotsCategoryComponents diff --git a/packages/visual-editor/src/components/testing/screenshots/StaticMapSection/[desktop] default props with coordinate - with api key.png b/packages/visual-editor/src/components/testing/screenshots/StaticMapSection/[desktop] default props with coordinate - with api key.png index fd8f22600a..0131aebf7f 100644 Binary files a/packages/visual-editor/src/components/testing/screenshots/StaticMapSection/[desktop] default props with coordinate - with api key.png and b/packages/visual-editor/src/components/testing/screenshots/StaticMapSection/[desktop] default props with coordinate - with api key.png differ diff --git a/packages/visual-editor/src/editor/Editor.tsx b/packages/visual-editor/src/editor/Editor.tsx index ad67c7d48a..ae2d135830 100644 --- a/packages/visual-editor/src/editor/Editor.tsx +++ b/packages/visual-editor/src/editor/Editor.tsx @@ -1,5 +1,5 @@ import "./index.css"; -import React, { ErrorInfo, useEffect, useState } from "react"; +import { ErrorInfo, useEffect, useState } from "react"; import { ErrorBoundary } from "react-error-boundary"; import { LoadingScreen } from "../internal/puck/components/LoadingScreen.tsx"; import { Toaster } from "../internal/puck/ui/Toaster.tsx"; diff --git a/packages/visual-editor/src/editor/YextEntityFieldSelector.tsx b/packages/visual-editor/src/editor/YextEntityFieldSelector.tsx index cb3b1a0666..f7ef42c566 100644 --- a/packages/visual-editor/src/editor/YextEntityFieldSelector.tsx +++ b/packages/visual-editor/src/editor/YextEntityFieldSelector.tsx @@ -1,5 +1,11 @@ import React from "react"; -import { AutoField, FieldLabel, Field, CustomField } from "@measured/puck"; +import { + AutoField, + FieldLabel, + Field, + CustomField, + UiState, +} from "@measured/puck"; import { ConstantValueTypes, EntityFieldTypes, @@ -44,11 +50,10 @@ import { EmbeddedFieldStringInputFromEntity } from "./EmbeddedFieldStringInput.t import { ComboboxOption } from "../internal/puck/ui/Combobox.tsx"; import { DATE_TIME_CONSTANT_CONFIG } from "../internal/puck/components/DateTimeSelector.tsx"; import { FAQ_SECTION_CONSTANT_CONFIG } from "../internal/puck/constant-value-fields/FAQsSection"; +import { getSchemaForYextEntityField, FieldAiConfig } from "./aiSchemas.ts"; const devLogger = new DevLogger(); -type RenderProps = Parameters["render"]>[0]; - /** Represents data that can either be from the Yext Knowledge Graph or statically defined */ export type YextEntityField = { /** The api name of the Yext field */ @@ -94,6 +99,8 @@ export type RenderYextEntityFieldSelectorProps> = disableConstantValueToggle?: boolean; disallowTranslation?: boolean; typeSelectorConfig?: TypeSelectorConfigProps; + /** AI configuration for Puck AI plugin */ + ai?: FieldAiConfig; }; export const TYPE_TO_CONSTANT_CONFIG: Record> = { @@ -196,16 +203,36 @@ const returnConstantFieldConfig = ( } return fieldConfiguration; }; - /** * Allows the user to select an entity field from the document and set a constant value. */ export const YextEntityFieldSelector = , U>( props: RenderYextEntityFieldSelectorProps ): Field> => { + // Generate default schema based on filter types + const defaultSchema = getSchemaForYextEntityField(props.filter); + + // Build AI config with default schema (can be overridden by props.ai) + // If exclude is true, don't include schema (workaround for Puck bug) + const aiConfig: FieldAiConfig = props.ai?.exclude + ? { ...props.ai } + : { + ...(defaultSchema ? { schema: defaultSchema } : {}), + ...props.ai, + }; + return { type: "custom", - render: ({ value, onChange }: RenderProps) => { + // Include AI config if we have a schema or user provided config + ...(Object.keys(aiConfig).length > 0 ? { ai: aiConfig } : {}), + + render: ({ + value, + onChange, + }: { + value: YextEntityField; + onChange: (value: YextEntityField) => void; + }) => { const toggleConstantValueEnabled = (constantValueEnabled: boolean) => { onChange({ ...value, @@ -217,7 +244,7 @@ export const YextEntityFieldSelector = , U>( <> >({ ) : ( + onChange={(newConstantValue: T, uiState?: Partial) => onChange( { ...value, @@ -375,8 +402,8 @@ export const ConstantValueInput = >({ uiState ) } - value={value?.constantValue} - field={constantFieldConfig} + value={value?.constantValue as T} + field={constantFieldConfig as Field} /> ); @@ -499,7 +526,7 @@ export const EntityFieldInput = >({ {typeSelectorConfig && ( { + onChange={(selectedType: string, uiState?: Partial) => { onChange( { ...value, @@ -515,7 +542,7 @@ export const EntityFieldInput = >({ { + onChange={(selectedEntityField: string, uiState?: Partial) => { onChange( { ...value, diff --git a/packages/visual-editor/src/editor/YextField.tsx b/packages/visual-editor/src/editor/YextField.tsx index 2379a702d6..6f31556081 100644 --- a/packages/visual-editor/src/editor/YextField.tsx +++ b/packages/visual-editor/src/editor/YextField.tsx @@ -31,47 +31,83 @@ import { RenderEntityFieldFilter } from "../internal/utils/getFilteredEntityFiel import { MsgString } from "../utils/i18n/platform.ts"; import { IMAGE_CONSTANT_CONFIG } from "../internal/puck/constant-value-fields/Image.tsx"; import { VIDEO_CONSTANT_CONFIG } from "../internal/puck/constant-value-fields/Video.tsx"; - -/** Copied from Puck, do not change */ +import { ComboboxOption } from "../internal/puck/ui/Combobox.tsx"; +import { + getSchemaForYextEntityField, + getSchemaForSelectField, + textFieldSchema, + numberFieldSchema, + translatableStringFieldSchema, + FieldAiConfig, +} from "./aiSchemas.ts"; + +/** Field option type for select/radio fields */ export type FieldOption = { label: string; - value: string | number | boolean; + value: string | number | boolean | undefined | null | object; }; -/** Copied from Puck, do not change */ +/** Array of field options for select/radio fields */ export type FieldOptions = Array | ReadonlyArray; -type radioOptions = +type RadioOptions = | "PHONE_OPTIONS" | "ALIGNMENT" | "BODY_VARIANT" | "JUSTIFY_CONTENT" | "CTA_VARIANT"; -type selectOptions = keyof Omit; +type SelectOptions = keyof Omit; + +type ThemeOptionsKey = keyof typeof ThemeOptions; + +/** Type guard to check if a value is a valid ThemeOptions key */ +function isThemeOptionsKey(value: unknown): value is ThemeOptionsKey { + return typeof value === "string" && value in ThemeOptions; +} + +/** + * Builds AI config for a field with the given default schema. + * If exclude is true, the schema is not included (workaround for Puck bug). + */ +function buildAiConfig( + defaultSchema: FieldAiConfig["schema"], + userAi?: FieldAiConfig +): FieldAiConfig { + if (userAi?.exclude) { + return { ...userAi }; + } + return { + ...(defaultSchema ? { schema: defaultSchema } : {}), + ...userAi, + }; +} type YextBaseField = { type: string; visible?: boolean; + ai?: FieldAiConfig; }; // YextArrayField has same functionality as Puck's ArrayField +// Note: Uses `any` for Props due to complex generic constraints with Puck's Field types type YextArrayField< - Props extends { [key: string]: any }[] = { [key: string]: any }[], + Props extends { [key: string]: unknown }[] = { [key: string]: unknown }[], > = YextBaseField & Omit, keyof BaseField>; // YextNumberField has same functionality as Puck's NumberField type YextNumberField = YextBaseField & Omit; // YextObjectField has same functionality as Puck's ObjectField +// Note: Uses `any` for Props due to complex generic constraints with Puck's Field types type YextObjectField< - Props extends { [key: string]: any } = { [key: string]: any }, + Props extends { [key: string]: unknown } = { [key: string]: unknown }, > = YextBaseField & Omit, keyof BaseField>; // YextRadioField accepts normal FieldOptions or specific ThemeConfig options. type YextRadioField = YextBaseField & { type: "radio"; - options: FieldOptions | radioOptions; + options: FieldOptions | RadioOptions; }; // YextSelectField accepts normal FieldOptions or specific ThemeConfig options. @@ -79,7 +115,7 @@ type YextRadioField = YextBaseField & { type YextSelectField = YextBaseField & { type: "select"; hasSearch?: boolean; - options: FieldOptions | selectOptions; + options: FieldOptions | SelectOptions; }; // YextTextField has same functionality as Puck's TextField @@ -107,7 +143,7 @@ type YextMaxWidthField = YextBaseField & { type YextTranslatableStringField = YextBaseField & { type: "translatableString"; - filter?: RenderEntityFieldFilter; + filter?: RenderEntityFieldFilter>; showApplyAllOption?: boolean; }; @@ -136,18 +172,25 @@ type YextDynamicSingleSelectField = }; // YextEntitySelectorField has same functionality as YextEntityFieldSelector +// Note: Uses Record as default for T to maintain type flexibility type YextEntitySelectorField< - T extends Record = Record, + T extends Record = Record, > = YextBaseField & Omit, "label"> & { type: "entityField"; }; +// Note: This union type uses conditional types with `any` fallbacks to maintain +// compatibility with existing call sites that rely on flexible type inference. +// eslint-disable-next-line @typescript-eslint/no-explicit-any type YextFieldConfig = + // eslint-disable-next-line @typescript-eslint/no-explicit-any | YextArrayField[] ? Props : any> + // eslint-disable-next-line @typescript-eslint/no-explicit-any | YextObjectField ? Props : any> | YextNumberField | YextTextField + // eslint-disable-next-line @typescript-eslint/no-explicit-any | YextEntitySelectorField ? Props : any> | YextSelectField | YextRadioField @@ -157,16 +200,20 @@ type YextFieldConfig = | YextTranslatableStringField | YextImageField | YextVideoField + // eslint-disable-next-line @typescript-eslint/no-explicit-any | YextDynamicSelectField | YextDynamicSingleSelectField< + // eslint-disable-next-line @typescript-eslint/no-explicit-any Props extends DynamicOptionValueTypes ? Props : any >; +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function YextField( fieldName: MsgString, config: YextFieldConfig ): Field; +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function YextField, U = any>( fieldName: MsgString, config: YextEntitySelectorField @@ -185,78 +232,145 @@ export function YextField< U extends DynamicOptionValueTypes, >(fieldName: MsgString, config: YextDynamicSingleSelectField): Field; +/** + * Creates a Puck field configuration with Yext-specific enhancements. + * + * @param fieldName - The label for the field + * @param config - Configuration object that determines the field type and options + * @returns A Puck Field configuration + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function YextField( fieldName: MsgString, config: YextFieldConfig + // eslint-disable-next-line @typescript-eslint/no-explicit-any ): any { // use YextEntityFieldSelector if (config.type === "entityField") { - return YextEntityFieldSelector ? T : any, U>({ + // Get schema for the entity field based on filter types + const schema = getSchemaForYextEntityField(config.filter); + + // Build the field with AI config + const field = YextEntityFieldSelector< + T extends Record ? T : any, + U + >({ label: fieldName, filter: config.filter, disableConstantValueToggle: config.disableConstantValueToggle, disallowTranslation: config.disallowTranslation, typeSelectorConfig: config.typeSelectorConfig, }); + + // Merge AI config if schema exists or if user provided AI config + if (schema || config.ai) { + return { + ...field, + ai: buildAiConfig(schema, config.ai), + }; + } + + return field; } if (config.type === "optionalNumber") { - return OptionalNumberField({ + const field = OptionalNumberField({ fieldLabel: fieldName, hideNumberFieldRadioLabel: config.hideNumberFieldRadioLabel, showNumberFieldRadioLabel: config.showNumberFieldRadioLabel, defaultCustomValue: config.defaultCustomValue, }); + // Default schema for optional number + const defaultSchema = numberFieldSchema; + return { + ...field, + ai: buildAiConfig(defaultSchema, config.ai), + }; } if (config.type === "select" && config.options === "BACKGROUND_COLOR") { - const options = ThemeOptions[config.options]; - return BasicSelector({ + const options = ThemeOptions.BACKGROUND_COLOR.flatMap( + (group) => group.options + ); + const field = BasicSelector({ label: fieldName, - optionGroups: options, + optionGroups: ThemeOptions.BACKGROUND_COLOR, disableSearch: true, }); + // Default schema from options + const defaultSchema = getSchemaForSelectField(options as FieldOptions); + return { + ...field, + ai: buildAiConfig(defaultSchema, config.ai), + }; } // use BasicSelector functionality if (config.type === "select" && config.hasSearch) { - const options = - typeof config.options === "string" - ? ThemeOptions[config.options] - : config.options; - return BasicSelector({ label: fieldName, options: options as any }); + const options = isThemeOptionsKey(config.options) + ? ThemeOptions[config.options] + : config.options; + const field = BasicSelector({ + label: fieldName, + options: options as ComboboxOption[], + }); + // Default schema from options + const defaultSchema = getSchemaForSelectField(options as FieldOptions); + return { + ...field, + ai: buildAiConfig(defaultSchema, config.ai), + }; } if ( (config.type === "select" || config.type === "radio") && - typeof config.options === "string" + isThemeOptionsKey(config.options) ) { - return { + const options = ThemeOptions[config.options] as FieldOptions; + const field = { label: fieldName, visible: config.visible, type: config.type, - options: ThemeOptions[config.options] as FieldOptions, + options, + }; + // Default schema from options + const defaultSchema = getSchemaForSelectField(options); + return { + ...field, + ai: buildAiConfig(defaultSchema, config.ai), }; } if (config.type === "text") { - return { + const field = { label: fieldName, visible: config.visible, type: config.isMultiline ? "textarea" : "text", }; + // Default schema for text + const defaultSchema = textFieldSchema; + return { + ...field, + ai: buildAiConfig(defaultSchema, config.ai), + }; } if (config.type === "code") { - return CodeField({ + const field = CodeField({ fieldLabel: fieldName, codeLanguage: config.codeLanguage, }); + // Default schema for code (string) + const defaultSchema = textFieldSchema; + return { + ...field, + ai: buildAiConfig(defaultSchema, config.ai), + }; } if (config.type === "maxWidth") { const maxWidthOptions = getMaxWidthOptions(); - return BasicSelector({ + const field = BasicSelector({ label: fieldName, disableSearch: true, optionGroups: [ @@ -269,50 +383,77 @@ export function YextField( }, ], }); + // Default schema from options + const defaultSchema = getSchemaForSelectField(maxWidthOptions); + return { + ...field, + ai: buildAiConfig(defaultSchema, config.ai), + }; } if (config.type === "translatableString") { - return TranslatableStringField( + const field = TranslatableStringField( fieldName, config.filter, config.showApplyAllOption ); + // Default schema for translatable string + const defaultSchema = translatableStringFieldSchema; + return { + ...field, + ai: buildAiConfig(defaultSchema, config.ai), + }; } if (config.type === "image") { - return { + const field = { ...IMAGE_CONSTANT_CONFIG, label: fieldName, }; + // Image fields typically shouldn't be AI generated, exclude by default + return { + ...field, + ai: { exclude: true, ...config.ai }, + }; } if (config.type === "video") { - return { + const field = { ...VIDEO_CONSTANT_CONFIG, label: fieldName, }; + // Video fields typically shouldn't be AI generated, exclude by default + return { + ...field, + ai: { exclude: true, ...config.ai }, + }; } if (config.type === "dynamicSelect") { - return DynamicOptionsSelector({ + const field = DynamicOptionsSelector({ label: fieldName, dropdownLabel: config.dropdownLabel, getOptions: config.getOptions, placeholderOptionLabel: config.placeholderOptionLabel, }); + // Dynamic options - user should provide schema if needed + return config.ai ? { ...field, ai: config.ai } : field; } if (config.type === "dynamicSingleSelect") { - return DynamicOptionsSingleSelector({ + const field = DynamicOptionsSingleSelector({ label: fieldName, dropdownLabel: config.dropdownLabel, getOptions: config.getOptions, placeholderOptionLabel: config.placeholderOptionLabel, }); + // Dynamic options - user should provide schema if needed + return config.ai ? { ...field, ai: config.ai } : field; } - return { + const field = { label: fieldName, ...config, - } as Field; + }; + return (config.ai ? { ...field, ai: config.ai } : field) as Field; } diff --git a/packages/visual-editor/src/editor/aiSchemas.ts b/packages/visual-editor/src/editor/aiSchemas.ts new file mode 100644 index 0000000000..d354d95e58 --- /dev/null +++ b/packages/visual-editor/src/editor/aiSchemas.ts @@ -0,0 +1,321 @@ +import { z } from "zod/v4"; +import { RenderEntityFieldFilter } from "../internal/utils/getFilteredEntityFields.ts"; + +/** + * JSON Schema type compatible with Puck AI plugin + * Based on the JSONSchema type from @puckeditor/plugin-ai + */ +export type JSONSchema = { + [k: string]: unknown; + type?: + | "object" + | "array" + | "string" + | "number" + | "boolean" + | "null" + | "integer"; + properties?: Record; + required?: string[]; + const?: string | number | boolean | null; + enum?: Array; + anyOf?: JSONSchema[]; + additionalProperties?: boolean | JSONSchema; +}; + +/** + * AI configuration for Puck AI plugin fields + * Based on FieldAiParams from @puckeditor/plugin-ai + */ +export type FieldAiConfig = { + instructions?: string; + exclude?: boolean; + required?: boolean; + stream?: boolean; + schema?: JSONSchema; +}; + +/** + * Zod schema for TranslatableString constant value + * Represents a localized string with hasLocalizedValue flag + */ +const translatableStringConstantValueSchema = z + .object({ + hasLocalizedValue: z.enum(["true"]), + }) + .passthrough(); // Allow additional locale keys (en, es, fr, etc.) + +/** + * Zod schema for YextEntityField + * Used when filter.types includes "type.string" + */ +export const yextEntityFieldTranslatableStringSchema = z.object({ + field: z.string(), + constantValue: translatableStringConstantValueSchema.optional(), + constantValueEnabled: z.boolean().optional(), +}); + +/** + * Zod schema for AssetImageType constant value + * Based on AssetImageType from types/images.ts + */ +const assetImageTypeConstantValueSchema = z.object({ + url: z.string(), + height: z.number(), + width: z.number(), + alternateText: z + .union([ + z.string(), + z + .object({ + hasLocalizedValue: z.enum(["true"]), + }) + .passthrough(), + ]) + .optional(), + assetImage: z.any().optional(), // Complex nested type, allow any +}); + +/** + * Zod schema for YextEntityField + * Used when filter.types includes "type.image" + */ +export const yextEntityFieldImageSchema = z.object({ + field: z.string(), + constantValue: assetImageTypeConstantValueSchema.optional(), + constantValueEnabled: z.boolean().optional(), +}); + +/** + * Zod schema for TranslatableCTA constant value + * Based on TranslatableCTA from types/types.ts + */ +const translatableCTAConstantValueSchema = z.object({ + label: translatableStringConstantValueSchema, + link: translatableStringConstantValueSchema, + linkType: z + .enum([ + "URL", + "EMAIL", + "PHONE", + "CLICK_TO_WEBSITE", + "DRIVING_DIRECTIONS", + "OTHER", + ]) + .optional(), +}); + +/** + * Zod schema for YextEntityField + * Used when filter.types includes "type.cta" + */ +export const yextEntityFieldCTASchema = z.object({ + field: z.string(), + constantValue: translatableCTAConstantValueSchema.optional(), + constantValueEnabled: z.boolean().optional(), +}); + +/** + * Checks if a value is an empty object (from z.any() or similar) + */ +function isEmptyObject(value: unknown): boolean { + return ( + typeof value === "object" && + value !== null && + !Array.isArray(value) && + Object.keys(value).length === 0 + ); +} + +/** + * Cleans a JSON Schema to be compatible with Puck AI + * - Removes $schema property (Puck AI doesn't need it) + * - Converts empty additionalProperties: {} to additionalProperties: true + * - Removes properties with empty object schemas {} (from z.any()) + */ +function cleanSchemaForPuck(schema: unknown): JSONSchema { + if (typeof schema !== "object" || schema === null) { + return schema as JSONSchema; + } + + const obj = schema as Record; + const cleaned: Record = {}; + + for (const [key, value] of Object.entries(obj)) { + // Skip $schema property + if (key === "$schema") { + continue; + } + + // Handle additionalProperties: {} -> additionalProperties: true + if (key === "additionalProperties" && isEmptyObject(value)) { + cleaned[key] = true; + continue; + } + + // Handle properties object - filter out empty object properties + if (key === "properties" && typeof value === "object" && value !== null) { + const props = value as Record; + const cleanedProps: Record = {}; + + for (const [propKey, propValue] of Object.entries(props)) { + // Skip properties with empty object schemas (from z.any()) + if (isEmptyObject(propValue)) { + continue; + } + cleanedProps[propKey] = cleanSchemaForPuck(propValue); + } + + cleaned[key] = cleanedProps; + continue; + } + + // Handle required array - remove references to filtered out properties + if (key === "required" && Array.isArray(value)) { + // We'll handle this after properties are cleaned + cleaned[key] = value; + continue; + } + + // Recursively clean nested objects + if (typeof value === "object" && value !== null) { + if (Array.isArray(value)) { + cleaned[key] = value.map((item) => cleanSchemaForPuck(item)); + } else { + cleaned[key] = cleanSchemaForPuck(value); + } + } else { + cleaned[key] = value; + } + } + + // Update required array to only include properties that still exist + if (cleaned.required && cleaned.properties) { + const existingProps = Object.keys( + cleaned.properties as Record + ); + cleaned.required = (cleaned.required as string[]).filter((prop) => + existingProps.includes(prop) + ); + if ((cleaned.required as string[]).length === 0) { + delete cleaned.required; + } + } + + return cleaned as JSONSchema; +} + +/** + * Gets the appropriate JSON Schema for a YextEntityField based on the filter types + */ +export function getSchemaForYextEntityField( + filter: RenderEntityFieldFilter +): JSONSchema | undefined { + const types = filter.types || []; + + let rawSchema: unknown; + + // Handle type.string (TranslatableString) + if (types.includes("type.string") && !filter.includeListsOnly) { + rawSchema = z.toJSONSchema(yextEntityFieldTranslatableStringSchema); + } + // Handle type.image + else if (types.includes("type.image")) { + rawSchema = z.toJSONSchema(yextEntityFieldImageSchema); + } + // Handle type.cta + else if (types.includes("type.cta")) { + rawSchema = z.toJSONSchema(yextEntityFieldCTASchema); + } + // For other types, return undefined (no schema available yet) + else { + return undefined; + } + + // Clean the schema for Puck AI compatibility + return cleanSchemaForPuck(rawSchema); +} + +/** Option type for select/radio fields */ +type FieldOption = { + label: string; + value: string | number | boolean | undefined | null | object; +}; + +/** + * Generates a JSON Schema for a select/radio field based on its options + */ +export function getSchemaForSelectField( + options: readonly FieldOption[] | FieldOption[] +): JSONSchema { + const values = options + .map((opt) => opt.value) + .filter( + (v): v is string | number | boolean => + typeof v === "string" || typeof v === "number" || typeof v === "boolean" + ); + + if (values.length === 0) { + return { type: "string" }; + } + + // Determine the type from the values + const types = new Set(values.map((v) => typeof v)); + + if (types.size === 1) { + const type = types.values().next().value as string; + if (type === "number") { + return { + type: "number", + enum: values as number[], + }; + } else if (type === "boolean") { + return { + type: "boolean", + }; + } else { + return { + type: "string", + enum: values as string[], + }; + } + } + + // Mixed types - use anyOf + return { + anyOf: values.map((v) => ({ const: v })), + }; +} + +/** + * Default schema for text fields + */ +export const textFieldSchema: JSONSchema = { + type: "string", +}; + +/** + * Default schema for number fields + */ +export const numberFieldSchema: JSONSchema = { + type: "number", +}; + +/** + * Default schema for boolean fields + */ +export const booleanFieldSchema: JSONSchema = { + type: "boolean", +}; + +/** + * Default schema for translatable string fields (simplified) + */ +export const translatableStringFieldSchema: JSONSchema = { + type: "object", + properties: { + hasLocalizedValue: { type: "string", enum: ["true"] }, + }, + required: ["hasLocalizedValue"], + additionalProperties: true, +}; diff --git a/packages/visual-editor/src/editor/sample.json b/packages/visual-editor/src/editor/sample.json new file mode 100644 index 0000000000..a3b3fc6deb --- /dev/null +++ b/packages/visual-editor/src/editor/sample.json @@ -0,0 +1,159 @@ +{ + "categories": { + "blocks": { "title": "Blocks", "components": ["HeadingText"] }, + "hidden": { "visible": false, "components": [] } + }, + "components": { + "HeadingText": { + "label": "Heading Text", + "fields": { + "data": { + "label": "{\"key\":\"fields.data\",\"defaultValue\":\"Data\"}", + "type": "object", + "objectFields": { + "text": { + "type": "custom", + "ai": { + "schema": { + "type": "object", + "properties": { + "field": { "type": "string" }, + "constantValue": { + "type": "object", + "properties": { + "hasLocalizedValue": { + "type": "string", + "enum": ["true"] + } + }, + "required": ["hasLocalizedValue"], + "additionalProperties": true + }, + "constantValueEnabled": { + "type": "boolean", + "enum": [true, false] + } + }, + "required": ["field"], + "additionalProperties": false + }, + "instructions": "Enter the text for the heading" + } + } + } + }, + "styles": { + "label": "{\"key\":\"fields.styles\",\"defaultValue\":\"Styles\"}", + "type": "object", + "objectFields": { + "level": { + "type": "custom", + "ai": { + "schema": { "type": "number", "enum": [1, 2, 3, 4, 5, 6] } + } + }, + "align": { + "label": "{\"key\":\"fields.headingAlign\",\"defaultValue\":\"Heading Align\"}", + "type": "radio", + "options": [ + { + "label": "{\"key\":\"fields.options.left\",\"defaultValue\":\"Left\",\"options\":{\"context\":\"direction\"}}", + "value": "left" + }, + { + "label": "{\"key\":\"fields.options.center\",\"defaultValue\":\"Center\",\"options\":{\"context\":\"direction\"}}", + "value": "center" + }, + { + "label": "{\"key\":\"fields.options.right\",\"defaultValue\":\"Right\",\"options\":{\"context\":\"direction\"}}", + "value": "right" + } + ] + } + } + } + }, + "defaultProps": { + "data": { + "text": { + "field": "", + "constantValue": { "en": "Text", "hasLocalizedValue": "true" }, + "constantValueEnabled": true + } + }, + "styles": { "level": 2, "align": "left" } + } + } + }, + "root": { + "fields": { + "title": { + "type": "custom", + "ai": { + "schema": { + "type": "object", + "properties": { + "field": { "type": "string" }, + "constantValue": { + "type": "object", + "properties": { + "hasLocalizedValue": { "type": "string", "enum": ["true"] } + }, + "required": ["hasLocalizedValue"], + "additionalProperties": true + }, + "constantValueEnabled": { + "type": "boolean", + "enum": [true, false] + } + }, + "required": ["field"], + "additionalProperties": false + }, + "exclude": true + } + }, + "description": { + "type": "custom", + "ai": { + "schema": { + "type": "object", + "properties": { + "field": { "type": "string" }, + "constantValue": { + "type": "object", + "properties": { + "hasLocalizedValue": { "type": "string", "enum": ["true"] } + }, + "required": ["hasLocalizedValue"], + "additionalProperties": true + }, + "constantValueEnabled": { + "type": "boolean", + "enum": [true, false] + } + }, + "required": ["field"], + "additionalProperties": false + }, + "exclude": true + } + }, + "__advancedSettingsLink": { "type": "custom", "ai": { "exclude": true } } + }, + "defaultProps": { + "title": { + "field": "name", + "constantValue": { "hasLocalizedValue": "true" }, + "constantValueEnabled": false + }, + "description": { + "field": "description", + "constantValue": { "hasLocalizedValue": "true" }, + "constantValueEnabled": false + }, + "schemaMarkup": "", + "__advancedSettingsLink": null + } + } +} diff --git a/packages/visual-editor/src/internal/components/InternalLayoutEditor.tsx b/packages/visual-editor/src/internal/components/InternalLayoutEditor.tsx index cd03300993..8bec4144ad 100644 --- a/packages/visual-editor/src/internal/components/InternalLayoutEditor.tsx +++ b/packages/visual-editor/src/internal/components/InternalLayoutEditor.tsx @@ -12,6 +12,7 @@ import { FieldLabel, createUsePuck, resolveAllData, + type Plugin, } from "@measured/puck"; import React from "react"; import { useState, useRef, useCallback } from "react"; @@ -27,12 +28,39 @@ import { msg, pt, usePlatformTranslation } from "../../utils/i18n/platform.ts"; import { ClipboardCopyIcon, ClipboardPasteIcon } from "lucide-react"; import { v4 as uuidv4 } from "uuid"; import { Metadata } from "../../editor/Editor.tsx"; -import { AdvancedSettings } from "./AdvancedSettings.tsx"; +// import { AdvancedSettings } from "./AdvancedSettings.tsx"; import { cn } from "../../utils/cn.ts"; import { removeDuplicateImageActionBars } from "../utils/removeDuplicateImageActionBars.ts"; import { useDocument } from "../../hooks/useDocument.tsx"; import { fieldsOverride } from "../puck/components/FieldsOverride.tsx"; import { isDeepEqual } from "../../utils/deepEqual.ts"; +import "@puckeditor/plugin-ai/styles.css"; + +// Module-level cache for the AI plugin to ensure it's only created once +// and to avoid re-renders when using dynamic import. +let cachedAiPlugin: Plugin | null = null; +let pluginLoadStarted = false; + +// Load the AI plugin dynamically. The dynamic import is necessary because +// static imports would cause the module to be evaluated during SSR/build time +// (e.g., when tailwind processes the CSS and evaluates the bundled code). +// The package is marked as external in vite.config.ts. +const loadAiPlugin = (onLoaded: () => void): Plugin | null => { + if (typeof document === "undefined") { + return null; + } + if (cachedAiPlugin) { + return cachedAiPlugin; + } + if (!pluginLoadStarted) { + pluginLoadStarted = true; + import("@puckeditor/plugin-ai").then((mod) => { + cachedAiPlugin = mod.createAiPlugin(); + onLoaded(); + }); + } + return null; +}; const devLogger = new DevLogger(); const usePuck = createUsePuck(); @@ -40,6 +68,7 @@ const usePuck = createUsePuck(); // Advanced Settings link configuration const createAdvancedSettingsLink = () => ({ type: "custom" as const, + ai: { exclude: true }, render: () => { const getPuck = useGetPuck(); @@ -207,19 +236,20 @@ export const InternalLayoutEditor = ({ } ); - translatedComponents["AdvancedSettings"] = { - ...AdvancedSettings, - label: pt("advancedSettings", "Advanced Settings"), - }; - - translatedComponents["PageSettings"] = { - label: pt("page", "Page"), - fields: {}, - defaultProps: { - data: { title: "Page Settings" }, - }, - render: () => <>, - }; + // Commented out for experimental VE version + // translatedComponents["AdvancedSettings"] = { + // ...AdvancedSettings, + // label: pt("advancedSettings", "Advanced Settings"), + // }; + + // translatedComponents["PageSettings"] = { + // label: pt("page", "Page"), + // fields: {}, + // defaultProps: { + // data: { title: "Page Settings" }, + // }, + // render: () => <>, + // }; return { categories: puckConfig.categories, @@ -232,12 +262,14 @@ export const InternalLayoutEditor = ({ filter: { types: ["type.string"], }, + ai: { exclude: true }, }), description: YextEntityFieldSelector({ label: msg("fields.metaDescription", "Meta Description"), filter: { types: ["type.string"], }, + ai: { exclude: true }, }), ...puckConfig.root?.fields, __advancedSettingsLink: createAdvancedSettingsLink(), @@ -380,9 +412,16 @@ export const InternalLayoutEditor = ({ }; }, []); + // Load the AI plugin once. Uses a simple flag state to trigger a single re-render + // when the plugin loads, and useMemo to keep the same array reference. + const [, setPluginLoaded] = useState(false); + const plugin = loadAiPlugin(() => setPluginLoaded(true)); + const plugins = React.useMemo(() => (plugin ? [plugin] : []), [plugin]); + return ( ( - {children} + + {children} + ), puck: reloadDataOnDocumentChange, }} diff --git a/packages/visual-editor/src/internal/components/LayoutEditor.tsx b/packages/visual-editor/src/internal/components/LayoutEditor.tsx index 36fa8d29db..0ec514d044 100644 --- a/packages/visual-editor/src/internal/components/LayoutEditor.tsx +++ b/packages/visual-editor/src/internal/components/LayoutEditor.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import * as lzstring from "lz-string"; import { InitialHistory, diff --git a/packages/visual-editor/src/internal/hooks/useMessageReceivers.ts b/packages/visual-editor/src/internal/hooks/useMessageReceivers.ts index ce9e5db822..334df8c838 100644 --- a/packages/visual-editor/src/internal/hooks/useMessageReceivers.ts +++ b/packages/visual-editor/src/internal/hooks/useMessageReceivers.ts @@ -97,9 +97,9 @@ export const useCommonMessageReceivers = ( let puckConfig = componentRegistry[payload.templateId]; if (puckConfig) { puckConfig = filterComponentsFromConfig( - puckConfig, - payload.additionalLayoutComponents, - payload.additionalLayoutCategories + puckConfig + // payload.additionalLayoutComponents, + // payload.additionalLayoutCategories ); } else { throw new Error( diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/ConstantField.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/ConstantField.tsx index d7067100af..87e5870a32 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/ConstantField.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/ConstantField.tsx @@ -41,8 +41,8 @@ function ConstantField>( > { + value={props.value[fieldProps.field]} + onChange={(fieldValue: unknown) => { props.onChange({ ...props.value, [fieldProps.field]: fieldValue, diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/EnhancedCallToAction.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/EnhancedCallToAction.tsx index 873d791663..f9c563616a 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/EnhancedCallToAction.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/EnhancedCallToAction.tsx @@ -8,6 +8,7 @@ import { TranslatableStringField } from "../../../editor/TranslatableStringField import { linkTypeOptions } from "./CallToAction.tsx"; import { useMemo } from "react"; import { YextEntityField } from "@yext/visual-editor"; +import { LinkType } from "@yext/pages-components"; export const ctaTypeOptions = () => { return [ @@ -52,7 +53,13 @@ export const getCTAType = >( export const ENHANCED_CTA_CONSTANT_CONFIG: CustomField = { type: "custom", - render: ({ onChange, value }) => { + render: ({ + onChange, + value, + }: { + onChange: (value: EnhancedTranslatableCTA) => void; + value: EnhancedTranslatableCTA; + }) => { const labelField = useMemo(() => { return TranslatableStringField( msg("fields.label", "Label"), @@ -73,7 +80,9 @@ export const ENHANCED_CTA_CONSTANT_CONFIG: CustomField options: ctaTypeOptions(), }} value={value?.ctaType || "textAndLink"} - onChange={(newValue) => { + onChange={( + newValue: "textAndLink" | "getDirections" | "presetImage" + ) => { const updatedValue = { ...value, ctaType: newValue }; // Set defaults based on CTA type if (newValue === "presetImage") { @@ -101,7 +110,9 @@ export const ENHANCED_CTA_CONSTANT_CONFIG: CustomField onChange({ ...value, label: newValue })} + onChange={(newValue: TranslatableString) => + onChange({ ...value, label: newValue }) + } /> )} @@ -112,7 +123,7 @@ export const ENHANCED_CTA_CONSTANT_CONFIG: CustomField + onChange={(newValue: TranslatableString) => onChange({ ...value, link: newValue }) } /> @@ -125,9 +136,9 @@ export const ENHANCED_CTA_CONSTANT_CONFIG: CustomField type: "select", options: linkTypeOptions(), }} - value={value?.linkType || "URL"} - onChange={(newValue) => - onChange({ ...value, linkType: newValue }) + value={value?.linkType || ("URL" as unknown as LinkType)} + onChange={(newValue: LinkType) => + onChange({ ...value, linkType: newValue as LinkType }) } /> @@ -198,7 +209,13 @@ export const restrictedTranslatableCTAFields = // Restricted constant config for components that should only use textAndLink CTA type export const LINK_ONLY_CTA_CONFIG: CustomField = { type: "custom", - render: ({ onChange, value }) => { + render: ({ + onChange, + value, + }: { + onChange: (value: EnhancedTranslatableCTA) => void; + value: EnhancedTranslatableCTA; + }) => { const labelField = TranslatableStringField( msg("fields.label", "Label"), { @@ -212,7 +229,9 @@ export const LINK_ONLY_CTA_CONFIG: CustomField = { onChange({ ...value, label: newValue })} + onChange={(newValue: TranslatableString) => + onChange({ ...value, label: newValue }) + } /> @@ -221,7 +240,9 @@ export const LINK_ONLY_CTA_CONFIG: CustomField = { onChange({ ...value, link: newValue })} + onChange={(newValue: TranslatableString) => + onChange({ ...value, link: newValue }) + } /> @@ -233,8 +254,11 @@ export const LINK_ONLY_CTA_CONFIG: CustomField = { options: linkTypeOptions(), }} value={value?.linkType || "URL"} - onChange={(newValue) => - onChange({ ...value, linkType: newValue }) + onChange={(newValue: string) => + onChange({ + ...value, + linkType: newValue as LinkType | undefined as LinkType, + }) } /> diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/EventSection.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/EventSection.tsx index a795961b6c..8586d0b44d 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/EventSection.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/EventSection.tsx @@ -1,5 +1,6 @@ import { ArrayField } from "@measured/puck"; import { pt } from "../../../utils/i18n/platform.ts"; +import { type EventStruct } from "../../../types/types.ts"; export const EVENT_SECTION_CONSTANT_CONFIG: ArrayField = { type: "array", @@ -10,6 +11,6 @@ export const EVENT_SECTION_CONSTANT_CONFIG: ArrayField = { }, }, label: "", - getItemSummary: (item, index) => + getItemSummary: (item: EventStruct, index?: number) => pt("event", "Event") + " " + ((index ?? 0) + 1), }; diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/FAQsSection.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/FAQsSection.tsx index 285e05d951..d88ead2899 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/FAQsSection.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/FAQsSection.tsx @@ -1,5 +1,6 @@ import { Field } from "@measured/puck"; import { pt } from "../../../utils/i18n/platform.ts"; +import { type FAQStruct } from "../../../types/types.ts"; export const FAQ_SECTION_CONSTANT_CONFIG: Field = { type: "array", @@ -10,5 +11,6 @@ export const FAQ_SECTION_CONSTANT_CONFIG: Field = { }, }, label: "", - getItemSummary: (item, index) => pt("faq", "FAQ") + " " + ((index ?? 0) + 1), + getItemSummary: (item: FAQStruct, index?: number) => + pt("faq", "FAQ") + " " + ((index ?? 0) + 1), }; diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/Image.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/Image.tsx index 19e6979513..245ac62f4a 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/Image.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/Image.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { AutoField, CustomField, FieldLabel } from "@measured/puck"; +import { AutoField, CustomField, Field, FieldLabel } from "@measured/puck"; import { useTranslation } from "react-i18next"; import { TARGET_ORIGINS, @@ -22,7 +22,15 @@ export type ImagePayload = { export const IMAGE_CONSTANT_CONFIG: CustomField = { type: "custom", - render: ({ onChange, value, field }) => { + render: ({ + onChange, + value, + field, + }: { + onChange: (value: AssetImageType | undefined) => void; + value: AssetImageType | undefined; + field: Field; + }) => { const { i18n } = useTranslation(); const streamDocument = useDocument(); const [pendingMessageId, setPendingMessageId] = React.useState< @@ -175,7 +183,7 @@ export const IMAGE_CONSTANT_CONFIG: CustomField = { + onChange={(newValue: TranslatableString | undefined) => onChange(value ? { ...value, alternateText: newValue } : undefined) } /> diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/ImageList.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/ImageList.tsx index 09787b6513..5308ba04b8 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/ImageList.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/ImageList.tsx @@ -1,6 +1,7 @@ import { Field } from "@measured/puck"; import { pt } from "../../../utils/i18n/platform.ts"; import { IMAGE_CONSTANT_CONFIG } from "./Image.tsx"; +import { type AssetImageType } from "../../../types/images.ts"; export const IMAGE_LIST_CONSTANT_CONFIG = (): Field => { return { @@ -12,6 +13,7 @@ export const IMAGE_LIST_CONSTANT_CONFIG = (): Field => { label: pt("fields.image", "Image"), }, }, - getItemSummary: (_, i) => pt("photo", "Photo") + " " + ((i ?? 0) + 1), + getItemSummary: (item: AssetImageType, index?: number) => + pt("photo", "Photo") + " " + ((index ?? 0) + 1), }; }; diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/InsightSection.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/InsightSection.tsx index ef98d24fbd..abdf50a519 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/InsightSection.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/InsightSection.tsx @@ -1,5 +1,6 @@ import { ArrayField } from "@measured/puck"; import { pt } from "../../../utils/i18n/platform.ts"; +import { type InsightStruct } from "../../../types/types.ts"; export const INSIGHT_SECTION_CONSTANT_CONFIG: ArrayField = { type: "array", @@ -10,6 +11,6 @@ export const INSIGHT_SECTION_CONSTANT_CONFIG: ArrayField = { }, }, label: "", - getItemSummary: (item, index) => + getItemSummary: (item: InsightStruct, index?: number) => pt("insight", "Insight") + " " + ((index ?? 0) + 1), }; diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/Phone.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/Phone.tsx index 1fcb542047..c0b349f000 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/Phone.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/Phone.tsx @@ -7,7 +7,13 @@ import React from "react"; export const PHONE_CONSTANT_CONFIG: CustomField = { type: "custom", - render: ({ value, onChange }) => { + render: ({ + value, + onChange, + }: { + value: string | undefined; + onChange: (value: string | undefined) => void; + }) => { /* Managing an internal state is necessary to prevent PhoneInput from reverting back to its initial value unexpectedly. */ const [phoneNumber, setPhoneNumber] = React.useState(value); diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/ProductSection.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/ProductSection.tsx index f70ffc484c..71cefd5ba0 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/ProductSection.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/ProductSection.tsx @@ -1,5 +1,6 @@ import { ArrayField } from "@measured/puck"; import { pt } from "../../../utils/i18n/platform.ts"; +import { type ProductStruct } from "../../../types/types.ts"; export const PRODUCT_SECTION_CONSTANT_CONFIG: ArrayField = { type: "array", @@ -10,6 +11,6 @@ export const PRODUCT_SECTION_CONSTANT_CONFIG: ArrayField = { }, }, label: "", - getItemSummary: (item, index) => + getItemSummary: (item: ProductStruct, index?: number) => pt("product", "Product") + " " + ((index ?? 0) + 1), }; diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/TeamSection.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/TeamSection.tsx index cace9a0c08..6afea35fd7 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/TeamSection.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/TeamSection.tsx @@ -1,5 +1,6 @@ import { ArrayField } from "@measured/puck"; import { pt } from "../../../utils/i18n/platform.ts"; +import { type PersonStruct } from "../../../types/types.ts"; // This config is used by TeamCardsWrapper when constantValueEnabled is true // It just manages an array of card IDs, not the full PersonStruct data @@ -12,6 +13,6 @@ export const TEAM_SECTION_CONSTANT_CONFIG: ArrayField = { }, }, label: "", - getItemSummary: (item, index) => + getItemSummary: (item: PersonStruct, index?: number) => pt("teamMember", "Team Member") + " " + ((index ?? 0) + 1), }; diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/TestimonialSection.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/TestimonialSection.tsx index dff2f8a1d4..c5ea611ded 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/TestimonialSection.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/TestimonialSection.tsx @@ -1,3 +1,4 @@ +import { type TestimonialStruct } from "../../../types/types.ts"; import { pt } from "../../../utils/i18n/platform.ts"; import { ArrayField } from "@measured/puck"; @@ -12,6 +13,6 @@ export const TESTIMONIAL_SECTION_CONSTANT_CONFIG: ArrayField = { }, }, label: "", - getItemSummary: (item, index) => + getItemSummary: (item: TestimonialStruct, index?: number) => pt("testimonial", "Testimonial") + " " + ((index ?? 0) + 1), }; diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/TextList.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/TextList.tsx index 2dfd97c33c..978fe863b4 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/TextList.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/TextList.tsx @@ -10,7 +10,15 @@ const TEXT_LIST_BUTTON_COLOR: string = "#969696"; export const TEXT_LIST_CONSTANT_CONFIG: CustomField = { type: "custom", - render: ({ onChange, value, id }) => { + render: ({ + onChange, + value, + id, + }: { + onChange: (value: string[]) => void; + value: string[]; + id: string; + }) => { const [localItems, setLocalItems] = useState(value); const { t: pt } = usePlatformTranslation(); @@ -75,7 +83,6 @@ export const TEXT_LIST_CONSTANT_CONFIG: CustomField = { removeItem(index)} - variant="secondary" title={pt("deleteItem", "Delete Item")} type="button" > @@ -103,7 +110,15 @@ export const TRANSLATABLE_TEXT_LIST_CONSTANT_CONFIG: CustomField< TranslatableRichText[] > = { type: "custom", - render: ({ onChange, value = [], id }) => { + render: ({ + onChange, + value = [], + id, + }: { + onChange: (value: TranslatableRichText[]) => void; + value: TranslatableRichText[]; + id: string; + }) => { const streamDocument = useDocument(); const { t: pt } = usePlatformTranslation(); const locale = streamDocument?.locale ?? "en"; @@ -176,12 +191,13 @@ export const TRANSLATABLE_TEXT_LIST_CONSTANT_CONFIG: CustomField< field={{ type: "text" }} id={`${id}-value-${index}`} value={getDisplayValue(item, locale)} - onChange={(val) => updateItem(index, locale, val)} + onChange={(val: string | RichText) => + updateItem(index, locale, val) + } />
removeItem(index)} - variant="secondary" title={pt("deleteItem", "Delete Item")} type="button" > diff --git a/packages/visual-editor/src/internal/puck/constant-value-fields/Video.tsx b/packages/visual-editor/src/internal/puck/constant-value-fields/Video.tsx index d2daf5cd8e..b773e05bfa 100644 --- a/packages/visual-editor/src/internal/puck/constant-value-fields/Video.tsx +++ b/packages/visual-editor/src/internal/puck/constant-value-fields/Video.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { CustomField, FieldLabel } from "@measured/puck"; +import { CustomField, Field, FieldLabel } from "@measured/puck"; import { TARGET_ORIGINS, useReceiveMessage, @@ -17,7 +17,15 @@ type VideoPayload = { export const VIDEO_CONSTANT_CONFIG: CustomField = { type: "custom", - render: ({ onChange, value, field }) => { + render: ({ + onChange, + value, + field, + }: { + onChange: (value: AssetVideo | undefined) => void; + value: AssetVideo | undefined; + field: Field; + }) => { const [pendingMessageId, setPendingMessageId] = React.useState< string | undefined >(); diff --git a/packages/visual-editor/src/internal/puck/ui/Tooltip.tsx b/packages/visual-editor/src/internal/puck/ui/Tooltip.tsx index a94b7e5158..dd91c786c0 100644 --- a/packages/visual-editor/src/internal/puck/ui/Tooltip.tsx +++ b/packages/visual-editor/src/internal/puck/ui/Tooltip.tsx @@ -24,7 +24,7 @@ const TooltipContent = React.forwardRef< const [iframeWidth, setIFrameWidth] = React.useState(); // Safe fallback if tooltip renders outside of puck context - let viewportWidth: number | undefined; + let viewportWidth: number | "100%" | undefined; try { const getPuck = useGetPuck(); const puck = getPuck(); @@ -71,7 +71,7 @@ const TooltipContent = React.forwardRef< // Scale the tooltip using on Puck's zoom factor // Based on https://github.com/puckeditor/puck/blob/af1dc89139e0311b1dc014e328f431b1ebab0067/packages/core/components/DraggableComponent/index.tsx#L608 // and https://github.com/puckeditor/puck/blob/af1dc89139e0311b1dc014e328f431b1ebab0067/packages/core/lib/get-zoom-config.ts#L6 - if (iframeWidth && viewportWidth && zoomWithViewport) { + if (iframeWidth && typeof viewportWidth === "number" && zoomWithViewport) { setScaleFactor(1 / (iframeWidth / viewportWidth)); } }, [viewportWidth, iframeWidth, zoomWithViewport]); diff --git a/packages/visual-editor/src/vite-plugin/plugin.ts b/packages/visual-editor/src/vite-plugin/plugin.ts index dbfa44004c..cb22f88252 100644 --- a/packages/visual-editor/src/vite-plugin/plugin.ts +++ b/packages/visual-editor/src/vite-plugin/plugin.ts @@ -1,12 +1,15 @@ import path from "node:path"; import fs from "fs-extra"; import { Plugin } from "vite"; -import mainTemplate from "./templates/main.tsx?raw"; -import editTemplate from "./templates/edit.tsx?raw"; -import directoryTemplate from "./templates/directory.tsx?raw"; -import locatorTemplate from "./templates/locator.tsx?raw"; -import { ComponentField, ComponentFields } from "../types/fields.ts"; -import { defaultLayoutData } from "./defaultLayoutData.ts"; +// import mainTemplate from "./templates/main.tsx?raw"; +// import editTemplate from "./templates/edit.tsx?raw"; +// import directoryTemplate from "./templates/directory.tsx?raw"; +// import locatorTemplate from "./templates/locator.tsx?raw"; +import { + ComponentField, + // ComponentFields +} from "../types/fields.ts"; +// import { defaultLayoutData } from "./defaultLayoutData.ts"; type TemplateManifestEntry = { name: string; @@ -30,56 +33,56 @@ type VirtualFile = { * It also defines entries that will be used to generate the template-manifest.json */ const virtualFiles: VirtualFile[] = [ - { - filepath: "src/templates/main.tsx", - content: mainTemplate, - templateManifestEntry: { - name: "main", - description: - "Use this template to generate pages for each of your Locations.", - exampleSiteUrl: "", - layoutRequired: true, - defaultLayoutData: defaultLayoutData.main, - componentFields: [ - ComponentFields.PromoSection, - ComponentFields.ProductSection, - ComponentFields.EventSection, - ComponentFields.FAQSection, - ComponentFields.TestimonialSection, - ComponentFields.InsightSection, - ComponentFields.TeamSection, - ], - }, - }, - { - filepath: "src/templates/directory.tsx", - content: directoryTemplate, - templateManifestEntry: { - name: "directory", - description: - "Use this template to generate pages for each of your Directory entities.", - exampleSiteUrl: "", - layoutRequired: true, - defaultLayoutData: defaultLayoutData.directory, - // no componentFields are defined because this is handled in the back-end for the dynamically - // generated DM fields - }, - }, - { - filepath: "src/templates/locator.tsx", - content: locatorTemplate, - templateManifestEntry: { - name: "locator", - description: "Use this template to generate pages for your Locators.", - exampleSiteUrl: "", - layoutRequired: true, - defaultLayoutData: defaultLayoutData.locator, - }, - }, - { - filepath: "src/templates/edit.tsx", - content: editTemplate, - }, + // { + // filepath: "src/templates/main.tsx", + // content: mainTemplate, + // templateManifestEntry: { + // name: "main", + // description: + // "Use this template to generate pages for each of your Locations.", + // exampleSiteUrl: "", + // layoutRequired: true, + // defaultLayoutData: defaultLayoutData.main, + // componentFields: [ + // ComponentFields.PromoSection, + // ComponentFields.ProductSection, + // ComponentFields.EventSection, + // ComponentFields.FAQSection, + // ComponentFields.TestimonialSection, + // ComponentFields.InsightSection, + // ComponentFields.TeamSection, + // ], + // }, + // }, + // { + // filepath: "src/templates/directory.tsx", + // content: directoryTemplate, + // templateManifestEntry: { + // name: "directory", + // description: + // "Use this template to generate pages for each of your Directory entities.", + // exampleSiteUrl: "", + // layoutRequired: true, + // defaultLayoutData: defaultLayoutData.directory, + // // no componentFields are defined because this is handled in the back-end for the dynamically + // // generated DM fields + // }, + // }, + // { + // filepath: "src/templates/locator.tsx", + // content: locatorTemplate, + // templateManifestEntry: { + // name: "locator", + // description: "Use this template to generate pages for your Locators.", + // exampleSiteUrl: "", + // layoutRequired: true, + // defaultLayoutData: defaultLayoutData.locator, + // }, + // }, + // { + // filepath: "src/templates/edit.tsx", + // content: editTemplate, + // }, ]; export const yextVisualEditorPlugin = (): Plugin => { diff --git a/packages/visual-editor/vite.config.ts b/packages/visual-editor/vite.config.ts index 0a00908097..e0de2df171 100644 --- a/packages/visual-editor/vite.config.ts +++ b/packages/visual-editor/vite.config.ts @@ -32,6 +32,7 @@ export default defineConfig(() => ({ "mapbox-gl", "@yext/search-headless-react", "@yext/search-ui-react", + "@puckeditor/plugin-ai", ], output: { globals: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f47b23103..6be77f078b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,8 +83,11 @@ importers: packages/visual-editor: dependencies: "@measured/puck": - specifier: 0.20.2 - version: 0.20.2(@types/react@18.3.24)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)) + specifier: 0.21.0-canary.c0db75c1 + version: 0.21.0-canary.c0db75c1(@types/react@18.3.24)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)) + "@measured/puck-plugin-heading-analyzer": + specifier: ^0.20.2 + version: 0.20.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) "@microsoft/api-documenter": specifier: ^7.26.29 version: 7.26.32(@types/node@20.19.11) @@ -94,6 +97,12 @@ importers: "@microsoft/api-extractor-model": specifier: ^7.30.6 version: 7.30.7(@types/node@20.19.11) + "@puckeditor/cloud-client": + specifier: ^0.3.1 + version: 0.3.1 + "@puckeditor/plugin-ai": + specifier: ^0.3.1 + version: 0.3.1(@measured/puck@0.21.0-canary.c0db75c1(@types/react@18.3.24)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)))(@types/react@18.3.24)(react@18.3.1)(zod@4.1.13) "@radix-ui/react-accordion": specifier: ^1.2.3 version: 1.2.12(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -352,10 +361,10 @@ importers: version: 1.6.4(@algolia/client-search@5.35.0)(@types/node@20.19.11)(@types/react@18.3.24)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.9.2) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@20.19.11)(@vitest/browser@3.2.4)(jsdom@24.1.3) + version: 3.2.4(@types/debug@4.1.12)(@types/node@20.19.11)(@vitest/browser@3.2.4)(happy-dom@20.0.11)(jsdom@24.1.3) zod: - specifier: ^3.23.8 - version: 3.25.76 + specifier: ^4.1.13 + version: 4.1.13 starter: dependencies: @@ -494,6 +503,31 @@ importers: version: 5.4.19(@types/node@20.19.11) packages: + "@ai-sdk/gateway@2.0.18": + resolution: + { + integrity: sha512-sDQcW+6ck2m0pTIHW6BPHD7S125WD3qNkx/B8sEzJp/hurocmJ5Cni0ybExg6sQMGo+fr/GWOwpHF1cmCdg5rQ==, + } + engines: { node: ">=18" } + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + "@ai-sdk/provider-utils@3.0.18": + resolution: + { + integrity: sha512-ypv1xXMsgGcNKUP+hglKqtdDuMg68nWHucPPAhIENrbFAI+xCHiqPVN8Zllxyv1TNZwGWUghPxJXU+Mqps0YRQ==, + } + engines: { node: ">=18" } + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + "@ai-sdk/provider@2.0.0": + resolution: + { + integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==, + } + engines: { node: ">=18" } + "@algolia/abtesting@1.1.0": resolution: { @@ -2157,6 +2191,14 @@ packages: } engines: { node: ">=6.0.0" } + "@measured/puck-plugin-heading-analyzer@0.20.2": + resolution: + { + integrity: sha512-dvAw8T9Y8k7Bg3PjQDXAXt7Vl2WV3D2biNcKGygdtZ/4LA0W8ouUxnfrX0mXQFToOfRGQxihAsxdXVIC1Z4GZg==, + } + peerDependencies: + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + "@measured/puck@0.20.2": resolution: { @@ -2165,6 +2207,14 @@ packages: peerDependencies: react: ^18.0.0 || ^19.0.0 + "@measured/puck@0.21.0-canary.c0db75c1": + resolution: + { + integrity: sha512-v3u0aEd/tNifnf3yI9jj5Z51Sth0wXH1PIpc1cGJ/aMIQkLfDK4QqM3Q9uHTk7Ot6e4sOjbTuykHZpV70l+R1w==, + } + peerDependencies: + react: ^18.0.0 || ^19.0.0 + "@microsoft/api-documenter@7.26.32": resolution: { @@ -2416,6 +2466,13 @@ packages: integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==, } + "@opentelemetry/api@1.9.0": + resolution: + { + integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==, + } + engines: { node: ">=8.0.0" } + "@oxlint/darwin-arm64@1.2.0": resolution: { @@ -2526,6 +2583,21 @@ packages: integrity: sha512-etWpENXm469RHMWIZGblgWrapbIGcRcbccEGGaLkFez3PjlI3XkBrUtSiNFsIfV/DN16PxMOxbWAZUIaLFyJDg==, } + "@puckeditor/cloud-client@0.3.1": + resolution: + { + integrity: sha512-/hzadOYlzlqzz1Y2w0YpDsHwMI4pw8lIa9Uohv+pnFO/EgJ6fRQrROQDSTnreZ+fXW/QzTG3uxDlyW9nURkiqg==, + } + + "@puckeditor/plugin-ai@0.3.1": + resolution: + { + integrity: sha512-A6yxtiTC3ckC+iCuz9sk+1oX1A84FpSkOc0Dg+DNARYQgEMFZToisD+w7lzPFDxWzQptzLp7DiOUMgNxQpPEow==, + } + peerDependencies: + "@measured/puck": 0.21.0-canary.c0db75c1 + react: ^18.0.0 || ^19.0.0 + "@radix-ui/primitive@1.1.3": resolution: { @@ -2838,8 +2910,8 @@ packages: integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==, } peerDependencies: - "@types/react": "*" - "@types/react-dom": "*" + "@types/react": ^18.2.0 + "@types/react-dom": ^18.2.0 react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: @@ -2994,7 +3066,7 @@ packages: integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==, } peerDependencies: - "@types/react": "*" + "@types/react": ^18.2.0 react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: "@types/react": @@ -3042,7 +3114,7 @@ packages: integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==, } peerDependencies: - "@types/react": "*" + "@types/react": ^18.2.0 react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: "@types/react": @@ -4415,6 +4487,12 @@ packages: integrity: sha512-gwBNIP8ZAYev/ORDWW0QvxdwPXwxBtLsdsJgSc7eDIRt8ubP+rxUBzPsrwnu16fgEF8Bx4lh/+mvQvJzcTM6Kw==, } + "@standard-schema/spec@1.0.0": + resolution: + { + integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==, + } + "@swc/helpers@0.5.17": resolution: { @@ -4612,6 +4690,12 @@ packages: integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==, } + "@types/estree-jsx@1.0.5": + resolution: + { + integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==, + } + "@types/estree@1.0.8": resolution: { @@ -4738,6 +4822,12 @@ packages: integrity: sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==, } + "@types/node@20.19.26": + resolution: + { + integrity: sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg==, + } + "@types/parse5@5.0.3": resolution: { @@ -4782,7 +4872,7 @@ packages: integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==, } peerDependencies: - "@types/react": ^18.0.0 + "@types/react": ^18.2.0 "@types/react@18.3.24": resolution: @@ -4852,6 +4942,12 @@ packages: integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==, } + "@types/whatwg-mimetype@3.0.2": + resolution: + { + integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==, + } + "@types/yargs-parser@21.0.3": resolution: { @@ -4870,6 +4966,13 @@ packages: integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==, } + "@vercel/oidc@3.0.5": + resolution: + { + integrity: sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==, + } + engines: { node: ">= 20" } + "@vitejs/plugin-react@4.7.0": resolution: { @@ -5320,6 +5423,15 @@ packages: } engines: { node: ">= 14" } + ai@5.0.108: + resolution: + { + integrity: sha512-Jex3Lb7V41NNpuqJHKgrwoU6BCLHdI1Pg4qb4GJH4jRIDRXUBySJErHjyN4oTCwbiYCeb/8II9EnqSRPq9EifA==, + } + engines: { node: ">=18" } + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + ajv-draft-04@1.0.0: resolution: { @@ -5897,6 +6009,12 @@ packages: integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==, } + character-reference-invalid@2.0.1: + resolution: + { + integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==, + } + check-error@2.1.1: resolution: { @@ -6797,6 +6915,12 @@ packages: engines: { node: ">=4" } hasBin: true + estree-util-is-identifier-name@3.0.0: + resolution: + { + integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==, + } + estree-walker@2.0.2: resolution: { @@ -6816,6 +6940,12 @@ packages: } engines: { node: ">= 0.6" } + eventemitter3@4.0.7: + resolution: + { + integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==, + } + eventemitter3@5.0.1: resolution: { @@ -6829,6 +6959,13 @@ packages: } engines: { node: ">=0.8.x" } + eventsource-parser@3.0.6: + resolution: + { + integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==, + } + engines: { node: ">=18.0.0" } + evp_bytestokey@1.0.3: resolution: { @@ -6888,6 +7025,13 @@ packages: integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, } + fast-equals@5.2.2: + resolution: + { + integrity: sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==, + } + engines: { node: ">=6.0.0" } + fast-fifo@1.3.2: resolution: { @@ -7226,6 +7370,13 @@ packages: engines: { node: ">=0.4.7" } hasBin: true + happy-dom@20.0.11: + resolution: + { + integrity: sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g==, + } + engines: { node: ">=20.0.0" } + has-flag@4.0.0: resolution: { @@ -7315,6 +7466,12 @@ packages: integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==, } + hast-util-to-jsx-runtime@2.3.6: + resolution: + { + integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==, + } + hast-util-to-parse5@6.0.0: resolution: { @@ -7371,6 +7528,12 @@ packages: integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==, } + html-url-attributes@3.0.1: + resolution: + { + integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==, + } + html-void-elements@1.0.5: resolution: { @@ -7544,6 +7707,12 @@ packages: integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==, } + inline-style-parser@0.2.7: + resolution: + { + integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==, + } + intl-messageformat@10.7.16: resolution: { @@ -7570,12 +7739,24 @@ packages: integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==, } + is-alphabetical@2.0.1: + resolution: + { + integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==, + } + is-alphanumerical@1.0.4: resolution: { integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==, } + is-alphanumerical@2.0.1: + resolution: + { + integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==, + } + is-arguments@1.2.0: resolution: { @@ -7623,6 +7804,12 @@ packages: integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==, } + is-decimal@2.0.1: + resolution: + { + integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==, + } + is-docker@3.0.0: resolution: { @@ -7686,6 +7873,12 @@ packages: integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==, } + is-hexadecimal@2.0.1: + resolution: + { + integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==, + } + is-inside-container@1.0.0: resolution: { @@ -8052,6 +8245,12 @@ packages: integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, } + json-schema@0.4.0: + resolution: + { + integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==, + } + json-stringify-nice@1.1.4: resolution: { @@ -8264,6 +8463,12 @@ packages: integrity: sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==, } + longest-streak@3.1.0: + resolution: + { + integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==, + } + loose-envify@1.4.0: resolution: { @@ -8405,6 +8610,12 @@ packages: integrity: sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==, } + mdast-util-from-markdown@2.0.2: + resolution: + { + integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==, + } + mdast-util-gfm-autolink-literal@0.1.3: resolution: { @@ -8435,6 +8646,30 @@ packages: integrity: sha512-NNkhDx/qYcuOWB7xHUGWZYVXvjPFFd6afg6/e2g+SV4r9q5XUcCbV4Wfa3DLYIiD+xAEZc6K4MGaE/m0KDcPwQ==, } + mdast-util-mdx-expression@2.0.1: + resolution: + { + integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==, + } + + mdast-util-mdx-jsx@3.2.0: + resolution: + { + integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==, + } + + mdast-util-mdxjs-esm@2.0.1: + resolution: + { + integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==, + } + + mdast-util-phrasing@4.1.0: + resolution: + { + integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==, + } + mdast-util-to-hast@10.2.0: resolution: { @@ -8459,6 +8694,12 @@ packages: integrity: sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==, } + mdast-util-to-markdown@2.1.2: + resolution: + { + integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==, + } + mdast-util-to-string@2.0.0: resolution: { @@ -8471,6 +8712,12 @@ packages: integrity: sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==, } + mdast-util-to-string@4.0.0: + resolution: + { + integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==, + } + mdurl@1.0.1: resolution: { @@ -8516,6 +8763,12 @@ packages: integrity: sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==, } + micromark-core-commonmark@2.0.3: + resolution: + { + integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==, + } + micromark-extension-gfm-autolink-literal@0.5.7: resolution: { @@ -8558,30 +8811,60 @@ packages: integrity: sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==, } + micromark-factory-destination@2.0.1: + resolution: + { + integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==, + } + micromark-factory-label@1.1.0: resolution: { integrity: sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==, } + micromark-factory-label@2.0.1: + resolution: + { + integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==, + } + micromark-factory-space@1.1.0: resolution: { integrity: sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==, } + micromark-factory-space@2.0.1: + resolution: + { + integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==, + } + micromark-factory-title@1.1.0: resolution: { integrity: sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==, } + micromark-factory-title@2.0.1: + resolution: + { + integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==, + } + micromark-factory-whitespace@1.1.0: resolution: { integrity: sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==, } + micromark-factory-whitespace@2.0.1: + resolution: + { + integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==, + } + micromark-util-character@1.2.0: resolution: { @@ -8600,30 +8883,60 @@ packages: integrity: sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==, } + micromark-util-chunked@2.0.1: + resolution: + { + integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==, + } + micromark-util-classify-character@1.0.0: resolution: { integrity: sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==, } + micromark-util-classify-character@2.0.1: + resolution: + { + integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==, + } + micromark-util-combine-extensions@1.0.0: resolution: { integrity: sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==, } + micromark-util-combine-extensions@2.0.1: + resolution: + { + integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==, + } + micromark-util-decode-numeric-character-reference@1.1.0: resolution: { integrity: sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==, } + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: + { + integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==, + } + micromark-util-decode-string@1.1.0: resolution: { integrity: sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==, } + micromark-util-decode-string@2.0.1: + resolution: + { + integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==, + } + micromark-util-encode@1.1.0: resolution: { @@ -8642,18 +8955,36 @@ packages: integrity: sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==, } + micromark-util-html-tag-name@2.0.1: + resolution: + { + integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==, + } + micromark-util-normalize-identifier@1.1.0: resolution: { integrity: sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==, } + micromark-util-normalize-identifier@2.0.1: + resolution: + { + integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==, + } + micromark-util-resolve-all@1.0.0: resolution: { integrity: sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==, } + micromark-util-resolve-all@2.0.1: + resolution: + { + integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==, + } + micromark-util-sanitize-uri@1.2.0: resolution: { @@ -8672,6 +9003,12 @@ packages: integrity: sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==, } + micromark-util-subtokenize@2.1.0: + resolution: + { + integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==, + } + micromark-util-symbol@1.0.1: resolution: { @@ -8708,6 +9045,12 @@ packages: integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==, } + micromark@4.0.2: + resolution: + { + integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==, + } + micromatch@4.0.8: resolution: { @@ -9230,6 +9573,13 @@ packages: engines: { node: ">=8.*" } hasBin: true + p-finally@1.0.0: + resolution: + { + integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==, + } + engines: { node: ">=4" } + p-limit@3.1.0: resolution: { @@ -9251,6 +9601,20 @@ packages: } engines: { node: ">=18" } + p-queue@6.6.2: + resolution: + { + integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==, + } + engines: { node: ">=8" } + + p-timeout@3.2.0: + resolution: + { + integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==, + } + engines: { node: ">=8" } + package-json-from-dist@1.0.1: resolution: { @@ -9313,6 +9677,12 @@ packages: integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==, } + parse-entities@4.0.2: + resolution: + { + integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==, + } + parse-json@5.2.0: resolution: { @@ -9861,6 +10231,12 @@ packages: react: 15.x || 16.x || 17.x || 18.x react-dom: 15.x || 16.x || 17.x || 18.x + qler@0.6.2: + resolution: + { + integrity: sha512-W29Qj+cztc+zCwcTVAHrDLhzweRPScPrCJTn2OKmMFHly+44ipZt6AWNwajYIsAw3MVCtlxv//08esiLvmf1sw==, + } + qs@6.13.0: resolution: { @@ -10014,13 +10390,23 @@ packages: peerDependencies: react: ">=16.13.1" - react-hotkeys-hook@4.6.2: + react-from-json@0.8.0: resolution: { - integrity: sha512-FmP+ZriY3EG59Ug/lxNfrObCnW9xQShgk7Nb83+CkpfkcCpfS95ydv+E9JuXA5cp8KtskU7LGlIARpkc92X22Q==, + integrity: sha512-aVCZ7bQ5sUg4LhgW2qfY/Hfacqma1s600F7Z9GZqRqPtHu1JFi9gufS0o2YOIfo0e34OCqovoFZMl3VABMikCw==, } + engines: { node: ">=18" } peerDependencies: - react: ">=16.8.1" + react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + + react-hotkeys-hook@4.6.2: + resolution: + { + integrity: sha512-FmP+ZriY3EG59Ug/lxNfrObCnW9xQShgk7Nb83+CkpfkcCpfS95ydv+E9JuXA5cp8KtskU7LGlIARpkc92X22Q==, + } + peerDependencies: + react: ">=16.8.1" react-dom: ">=16.8.1" react-i18next@15.7.1: @@ -10076,6 +10462,15 @@ packages: integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==, } + react-markdown@10.1.0: + resolution: + { + integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==, + } + peerDependencies: + "@types/react": ">=18" + react: ">=18" + react-markdown@6.0.3: resolution: { @@ -10316,6 +10711,12 @@ packages: integrity: sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==, } + remark-parse@11.0.0: + resolution: + { + integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==, + } + remark-parse@9.0.0: resolution: { @@ -10328,6 +10729,12 @@ packages: integrity: sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==, } + remark-rehype@11.1.2: + resolution: + { + integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==, + } + remark-rehype@8.1.0: resolution: { @@ -11015,6 +11422,12 @@ packages: integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==, } + style-to-js@1.1.21: + resolution: + { + integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==, + } + style-to-object@0.3.0: resolution: { @@ -11027,6 +11440,12 @@ packages: integrity: sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==, } + style-to-object@1.0.14: + resolution: + { + integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==, + } + sucrase@3.35.0: resolution: { @@ -11452,6 +11871,13 @@ packages: engines: { node: ">=0.8.0" } hasBin: true + ulid@3.0.2: + resolution: + { + integrity: sha512-yu26mwteFYzBAot7KVMqFGCVpsF6g8wXfJzQUHvu1no3+rRRSFcSV2nKeYvNPLD2J4b08jYBDhHUjeH0ygIl9w==, + } + hasBin: true + ulidx@2.4.1: resolution: { @@ -11753,6 +12179,14 @@ packages: "@types/react": optional: true + use-stick-to-bottom@1.1.1: + resolution: + { + integrity: sha512-JkDp0b0tSmv7HQOOpL1hT7t7QaoUBXkq045WWWOFDTlLGRzgIIyW7vyzOIJzY7L2XVIG7j1yUxeDj2LHm9Vwng==, + } + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + use-sync-external-store@1.5.0: resolution: { @@ -11787,6 +12221,14 @@ packages: } hasBin: true + uuid@3.4.0: + resolution: + { + integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==, + } + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + uuid@9.0.1: resolution: { @@ -12124,6 +12566,13 @@ packages: } engines: { node: ">=18" } + whatwg-mimetype@3.0.0: + resolution: + { + integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==, + } + engines: { node: ">=12" } + whatwg-mimetype@4.0.0: resolution: { @@ -12324,6 +12773,12 @@ packages: integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==, } + zod@4.1.13: + resolution: + { + integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==, + } + zustand@5.0.8: resolution: { @@ -12358,6 +12813,24 @@ packages: } snapshots: + "@ai-sdk/gateway@2.0.18(zod@4.1.13)": + dependencies: + "@ai-sdk/provider": 2.0.0 + "@ai-sdk/provider-utils": 3.0.18(zod@4.1.13) + "@vercel/oidc": 3.0.5 + zod: 4.1.13 + + "@ai-sdk/provider-utils@3.0.18(zod@4.1.13)": + dependencies: + "@ai-sdk/provider": 2.0.0 + "@standard-schema/spec": 1.0.0 + eventsource-parser: 3.0.6 + zod: 4.1.13 + + "@ai-sdk/provider@2.0.0": + dependencies: + json-schema: 0.4.0 + "@algolia/abtesting@1.1.0": dependencies: "@algolia/client-common": 5.35.0 @@ -13325,6 +13798,13 @@ snapshots: "@mapbox/whoots-js@3.1.0": {} + "@measured/puck-plugin-heading-analyzer@0.20.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)": + dependencies: + react: 18.3.1 + react-from-json: 0.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + transitivePeerDependencies: + - react-dom + "@measured/puck@0.20.2(@types/react@18.3.24)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1))": dependencies: "@dnd-kit/helpers": 0.1.18 @@ -13344,6 +13824,25 @@ snapshots: - react-dom - use-sync-external-store + "@measured/puck@0.21.0-canary.c0db75c1(@types/react@18.3.24)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1))": + dependencies: + "@dnd-kit/helpers": 0.1.18 + "@dnd-kit/react": 0.1.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + deep-diff: 1.0.2 + fast-equals: 5.2.2 + flat: 5.0.2 + object-hash: 3.0.0 + react: 18.3.1 + react-hotkeys-hook: 4.6.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + use-debounce: 9.0.4(react@18.3.1) + uuid: 9.0.1 + zustand: 5.0.8(@types/react@18.3.24)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)) + transitivePeerDependencies: + - "@types/react" + - immer + - react-dom + - use-sync-external-store + "@microsoft/api-documenter@7.26.32(@types/node@20.19.11)": dependencies: "@microsoft/api-extractor-model": 7.30.7(@types/node@20.19.11) @@ -13597,6 +14096,8 @@ snapshots: dependencies: "@octokit/openapi-types": 24.2.0 + "@opentelemetry/api@1.9.0": {} + "@oxlint/darwin-arm64@1.2.0": optional: true @@ -13642,6 +14143,23 @@ snapshots: "@preact/signals-core@1.12.0": {} + "@puckeditor/cloud-client@0.3.1": {} + + "@puckeditor/plugin-ai@0.3.1(@measured/puck@0.21.0-canary.c0db75c1(@types/react@18.3.24)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)))(@types/react@18.3.24)(react@18.3.1)(zod@4.1.13)": + dependencies: + "@measured/puck": 0.21.0-canary.c0db75c1(@types/react@18.3.24)(immer@9.0.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)) + ai: 5.0.108(zod@4.1.13) + qler: 0.6.2 + react: 18.3.1 + react-markdown: 10.1.0(@types/react@18.3.24)(react@18.3.1) + react-textarea-autosize: 8.5.9(@types/react@18.3.24)(react@18.3.1) + ulid: 3.0.2 + use-stick-to-bottom: 1.1.1(react@18.3.1) + transitivePeerDependencies: + - "@types/react" + - supports-color + - zod + "@radix-ui/primitive@1.1.3": {} "@radix-ui/react-accordion@1.2.12(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)": @@ -15397,6 +15915,8 @@ snapshots: "@sinclair/typebox@0.34.40": {} + "@standard-schema/spec@1.0.0": {} + "@swc/helpers@0.5.17": dependencies: tslib: 2.8.1 @@ -15521,6 +16041,10 @@ snapshots: "@types/deep-eql@4.0.2": {} + "@types/estree-jsx@1.0.5": + dependencies: + "@types/estree": 1.0.8 + "@types/estree@1.0.8": {} "@types/fs-extra@11.0.4": @@ -15593,6 +16117,11 @@ snapshots: dependencies: undici-types: 6.21.0 + "@types/node@20.19.26": + dependencies: + undici-types: 6.21.0 + optional: true + "@types/parse5@5.0.3": {} "@types/pixelmatch@5.2.6": @@ -15647,6 +16176,9 @@ snapshots: "@types/web-bluetooth@0.0.21": {} + "@types/whatwg-mimetype@3.0.2": + optional: true + "@types/yargs-parser@21.0.3": {} "@types/yargs@17.0.33": @@ -15655,6 +16187,8 @@ snapshots: "@ungap/structured-clone@1.3.0": {} + "@vercel/oidc@3.0.5": {} + "@vitejs/plugin-react@4.7.0(vite@5.4.19(@types/node@20.19.11))": dependencies: "@babel/core": 7.28.3 @@ -15681,7 +16215,7 @@ snapshots: magic-string: 0.30.18 sirv: 3.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@20.19.11)(@vitest/browser@3.2.4)(jsdom@24.1.3) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@20.19.11)(@vitest/browser@3.2.4)(happy-dom@20.0.11)(jsdom@24.1.3) ws: 8.18.3 optionalDependencies: playwright: 1.55.1 @@ -16108,6 +16642,14 @@ snapshots: agent-base@7.1.4: {} + ai@5.0.108(zod@4.1.13): + dependencies: + "@ai-sdk/gateway": 2.0.18(zod@4.1.13) + "@ai-sdk/provider": 2.0.0 + "@ai-sdk/provider-utils": 3.0.18(zod@4.1.13) + "@opentelemetry/api": 1.9.0 + zod: 4.1.13 + ajv-draft-04@1.0.0(ajv@8.13.0): optionalDependencies: ajv: 8.13.0 @@ -16464,6 +17006,8 @@ snapshots: character-reference-invalid@1.1.4: {} + character-reference-invalid@2.0.1: {} + check-error@2.1.1: {} chokidar@3.6.0: @@ -16979,6 +17523,8 @@ snapshots: esprima@4.0.1: {} + estree-util-is-identifier-name@3.0.0: {} + estree-walker@2.0.2: {} estree-walker@3.0.3: @@ -16987,10 +17533,14 @@ snapshots: etag@1.8.1: {} + eventemitter3@4.0.7: {} + eventemitter3@5.0.1: {} events@3.3.0: {} + eventsource-parser@3.0.6: {} + evp_bytestokey@1.0.3: dependencies: md5.js: 1.3.5 @@ -17065,6 +17615,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-equals@5.2.2: {} + fast-fifo@1.3.2: {} fast-glob@3.3.3: @@ -17283,6 +17835,13 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 + happy-dom@20.0.11: + dependencies: + "@types/node": 20.19.26 + "@types/whatwg-mimetype": 3.0.2 + whatwg-mimetype: 3.0.0 + optional: true + has-flag@4.0.0: {} has-property-descriptors@1.0.2: @@ -17366,6 +17925,26 @@ snapshots: stringify-entities: 4.0.4 zwitch: 2.0.4 + hast-util-to-jsx-runtime@2.3.6: + dependencies: + "@types/estree": 1.0.8 + "@types/hast": 3.0.4 + "@types/unist": 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + hast-util-to-parse5@6.0.0: dependencies: hast-to-hyperscript: 9.0.1 @@ -17408,6 +17987,8 @@ snapshots: dependencies: void-elements: 3.1.0 + html-url-attributes@3.0.1: {} + html-void-elements@1.0.5: {} html-void-elements@3.0.0: {} @@ -17509,6 +18090,8 @@ snapshots: inline-style-parser@0.1.1: {} + inline-style-parser@0.2.7: {} + intl-messageformat@10.7.16: dependencies: "@formatjs/ecma402-abstract": 2.3.4 @@ -17522,11 +18105,18 @@ snapshots: is-alphabetical@1.0.4: {} + is-alphabetical@2.0.1: {} + is-alphanumerical@1.0.4: dependencies: is-alphabetical: 1.0.4 is-decimal: 1.0.4 + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-arguments@1.2.0: dependencies: call-bound: 1.0.4 @@ -17548,6 +18138,8 @@ snapshots: is-decimal@1.0.4: {} + is-decimal@2.0.1: {} + is-docker@3.0.0: {} is-extendable@0.1.1: {} @@ -17575,6 +18167,8 @@ snapshots: is-hexadecimal@1.0.4: {} + is-hexadecimal@2.0.1: {} + is-inside-container@1.0.0: dependencies: is-docker: 3.0.0 @@ -17781,6 +18375,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema@0.4.0: {} + json-stringify-nice@1.1.4: {} json5@2.2.3: {} @@ -17887,6 +18483,8 @@ snapshots: longest-streak@2.0.4: {} + longest-streak@3.1.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -18019,6 +18617,23 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-from-markdown@2.0.2: + dependencies: + "@types/mdast": 4.0.4 + "@types/unist": 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + mdast-util-gfm-autolink-literal@0.1.3: dependencies: ccount: 1.1.0 @@ -18050,6 +18665,50 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-mdx-expression@2.0.1: + dependencies: + "@types/estree-jsx": 1.0.5 + "@types/hast": 3.0.4 + "@types/mdast": 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + "@types/estree-jsx": 1.0.5 + "@types/hast": 3.0.4 + "@types/mdast": 4.0.4 + "@types/unist": 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + "@types/estree-jsx": 1.0.5 + "@types/hast": 3.0.4 + "@types/mdast": 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + "@types/mdast": 4.0.4 + unist-util-is: 6.0.0 + mdast-util-to-hast@10.2.0: dependencies: "@types/mdast": 3.0.15 @@ -18093,12 +18752,28 @@ snapshots: repeat-string: 1.6.1 zwitch: 1.0.5 + mdast-util-to-markdown@2.1.2: + dependencies: + "@types/mdast": 4.0.4 + "@types/unist": 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + mdast-util-to-string@2.0.0: {} mdast-util-to-string@3.2.0: dependencies: "@types/mdast": 3.0.15 + mdast-util-to-string@4.0.0: + dependencies: + "@types/mdast": 4.0.4 + mdurl@1.0.1: {} media-typer@0.3.0: {} @@ -18130,6 +18805,25 @@ snapshots: micromark-util-types: 1.0.2 uvu: 0.5.6 + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + micromark-extension-gfm-autolink-literal@0.5.7: dependencies: micromark: 2.11.4 @@ -18173,6 +18867,12 @@ snapshots: micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + micromark-factory-label@1.1.0: dependencies: micromark-util-character: 1.2.0 @@ -18180,11 +18880,23 @@ snapshots: micromark-util-types: 1.0.2 uvu: 0.5.6 + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + micromark-factory-space@1.1.0: dependencies: micromark-util-character: 1.2.0 micromark-util-types: 1.0.2 + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + micromark-factory-title@1.1.0: dependencies: micromark-factory-space: 1.1.0 @@ -18192,6 +18904,13 @@ snapshots: micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + micromark-factory-whitespace@1.1.0: dependencies: micromark-factory-space: 1.1.0 @@ -18199,6 +18918,13 @@ snapshots: micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + micromark-util-character@1.2.0: dependencies: micromark-util-symbol: 1.0.1 @@ -18213,21 +18939,40 @@ snapshots: dependencies: micromark-util-symbol: 1.0.1 + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-classify-character@1.0.0: dependencies: micromark-util-character: 1.2.0 micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + micromark-util-combine-extensions@1.0.0: dependencies: micromark-util-chunked: 1.0.0 micromark-util-types: 1.0.2 + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + micromark-util-decode-numeric-character-reference@1.1.0: dependencies: micromark-util-symbol: 1.0.1 + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-decode-string@1.1.0: dependencies: decode-named-character-reference: 1.2.0 @@ -18235,20 +18980,37 @@ snapshots: micromark-util-decode-numeric-character-reference: 1.1.0 micromark-util-symbol: 1.0.1 + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + micromark-util-encode@1.1.0: {} micromark-util-encode@2.0.1: {} micromark-util-html-tag-name@1.2.0: {} + micromark-util-html-tag-name@2.0.1: {} + micromark-util-normalize-identifier@1.1.0: dependencies: micromark-util-symbol: 1.0.1 + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-resolve-all@1.0.0: dependencies: micromark-util-types: 1.0.2 + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + micromark-util-sanitize-uri@1.2.0: dependencies: micromark-util-character: 1.2.0 @@ -18268,6 +19030,13 @@ snapshots: micromark-util-types: 1.0.2 uvu: 0.5.6 + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + micromark-util-symbol@1.0.1: {} micromark-util-symbol@2.0.1: {} @@ -18305,6 +19074,28 @@ snapshots: transitivePeerDependencies: - supports-color + micromark@4.0.2: + dependencies: + "@types/debug": 4.1.12 + debug: 4.4.1 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -18640,6 +19431,8 @@ snapshots: "@oxlint/win32-arm64": 1.2.0 "@oxlint/win32-x64": 1.2.0 + p-finally@1.0.0: {} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -18650,6 +19443,15 @@ snapshots: p-map@7.0.3: {} + p-queue@6.6.2: + dependencies: + eventemitter3: 4.0.7 + p-timeout: 3.2.0 + + p-timeout@3.2.0: + dependencies: + p-finally: 1.0.0 + package-json-from-dist@1.0.1: {} package-json@10.0.1: @@ -18733,6 +19535,16 @@ snapshots: is-decimal: 1.0.4 is-hexadecimal: 1.0.4 + parse-entities@4.0.2: + dependencies: + "@types/unist": 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.2.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + parse-json@5.2.0: dependencies: "@babel/code-frame": 7.27.1 @@ -18998,6 +19810,11 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + qler@0.6.2: + dependencies: + p-queue: 6.6.2 + uuid: 3.4.0 + qs@6.13.0: dependencies: side-channel: 1.1.0 @@ -19169,6 +19986,11 @@ snapshots: "@babel/runtime": 7.28.3 react: 18.3.1 + react-from-json@0.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-hotkeys-hook@4.6.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: react: 18.3.1 @@ -19198,6 +20020,24 @@ snapshots: react-is@18.3.1: {} + react-markdown@10.1.0(@types/react@18.3.24)(react@18.3.1): + dependencies: + "@types/hast": 3.0.4 + "@types/mdast": 4.0.4 + "@types/react": 18.3.24 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.0 + react: 18.3.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.4 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + react-markdown@6.0.3(@types/react@18.3.24)(react@18.3.1): dependencies: "@types/hast": 2.3.10 @@ -19415,6 +20255,15 @@ snapshots: transitivePeerDependencies: - supports-color + remark-parse@11.0.0: + dependencies: + "@types/mdast": 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.4 + transitivePeerDependencies: + - supports-color + remark-parse@9.0.0: dependencies: mdast-util-from-markdown: 0.8.5 @@ -19428,6 +20277,14 @@ snapshots: mdast-util-to-hast: 12.3.0 unified: 10.1.2 + remark-rehype@11.1.2: + dependencies: + "@types/hast": 3.0.4 + "@types/mdast": 4.0.4 + mdast-util-to-hast: 13.2.0 + unified: 11.0.4 + vfile: 6.0.3 + remark-rehype@8.1.0: dependencies: mdast-util-to-hast: 10.2.0 @@ -19856,6 +20713,10 @@ snapshots: dependencies: js-tokens: 9.0.1 + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + style-to-object@0.3.0: dependencies: inline-style-parser: 0.1.1 @@ -19864,6 +20725,10 @@ snapshots: dependencies: inline-style-parser: 0.1.1 + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + sucrase@3.35.0: dependencies: "@jridgewell/gen-mapping": 0.3.13 @@ -20141,6 +21006,8 @@ snapshots: uglify-js@3.19.3: optional: true + ulid@3.0.2: {} + ulidx@2.4.1: dependencies: layerr: 3.0.0 @@ -20330,6 +21197,10 @@ snapshots: optionalDependencies: "@types/react": 18.3.24 + use-stick-to-bottom@1.1.1(react@18.3.1): + dependencies: + react: 18.3.1 + use-sync-external-store@1.5.0(react@18.3.1): dependencies: react: 18.3.1 @@ -20348,6 +21219,8 @@ snapshots: uuid@11.0.3: {} + uuid@3.4.0: {} + uuid@9.0.1: {} uvu@0.5.6: @@ -20582,7 +21455,7 @@ snapshots: - typescript - universal-cookie - vitest@3.2.4(@types/debug@4.1.12)(@types/node@20.19.11)(@vitest/browser@3.2.4)(jsdom@24.1.3): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@20.19.11)(@vitest/browser@3.2.4)(happy-dom@20.0.11)(jsdom@24.1.3): dependencies: "@types/chai": 5.2.2 "@vitest/expect": 3.2.4 @@ -20611,6 +21484,7 @@ snapshots: "@types/debug": 4.1.12 "@types/node": 20.19.11 "@vitest/browser": 3.2.4(playwright@1.55.1)(vite@5.4.19(@types/node@20.19.11))(vitest@3.2.4) + happy-dom: 20.0.11 jsdom: 24.1.3 transitivePeerDependencies: - less @@ -20673,6 +21547,9 @@ snapshots: dependencies: iconv-lite: 0.6.3 + whatwg-mimetype@3.0.0: + optional: true + whatwg-mimetype@4.0.0: {} whatwg-url@14.2.0: @@ -20775,6 +21652,8 @@ snapshots: zod@3.25.76: {} + zod@4.1.13: {} + zustand@5.0.8(@types/react@18.3.24)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)): optionalDependencies: "@types/react": 18.3.24