@strapi/content-type-builder 5.29.0 → 5.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/components/AIChat/Chat.js +1 -0
- package/dist/admin/components/AIChat/Chat.js.map +1 -1
- package/dist/admin/components/AIChat/Chat.mjs +1 -0
- package/dist/admin/components/AIChat/Chat.mjs.map +1 -1
- package/dist/admin/components/AIChat/FeedbackModal.js.map +1 -1
- package/dist/admin/components/AIChat/FeedbackModal.mjs.map +1 -1
- package/dist/admin/components/AIChat/UploadFigmaModal.js +2 -1
- package/dist/admin/components/AIChat/UploadFigmaModal.js.map +1 -1
- package/dist/admin/components/AIChat/UploadFigmaModal.mjs +2 -1
- package/dist/admin/components/AIChat/UploadFigmaModal.mjs.map +1 -1
- package/dist/admin/components/AIChat/components/Base64Image.js.map +1 -1
- package/dist/admin/components/AIChat/components/Base64Image.mjs.map +1 -1
- package/dist/admin/components/AIChat/components/Collapsible.js.map +1 -1
- package/dist/admin/components/AIChat/components/Collapsible.mjs.map +1 -1
- package/dist/admin/components/AIChat/components/FullScreenImage.js.map +1 -1
- package/dist/admin/components/AIChat/components/FullScreenImage.mjs.map +1 -1
- package/dist/admin/components/AIChat/components/Messages/Message.js.map +1 -1
- package/dist/admin/components/AIChat/components/Messages/Message.mjs.map +1 -1
- package/dist/admin/components/AIChat/hooks/useAIFetch.js.map +1 -1
- package/dist/admin/components/AIChat/hooks/useAIFetch.mjs.map +1 -1
- package/dist/admin/components/AIChat/hooks/useCodeUpload.js.map +1 -1
- package/dist/admin/components/AIChat/hooks/useCodeUpload.mjs.map +1 -1
- package/dist/admin/components/AIChat/hooks/useFigmaUpload.js.map +1 -1
- package/dist/admin/components/AIChat/hooks/useFigmaUpload.mjs.map +1 -1
- package/dist/admin/components/AIChat/lib/aiClient.js.map +1 -1
- package/dist/admin/components/AIChat/lib/aiClient.mjs.map +1 -1
- package/dist/admin/components/AIChat/lib/constants.js.map +1 -1
- package/dist/admin/components/AIChat/lib/constants.mjs.map +1 -1
- package/dist/admin/components/AIChat/providers/SchemaProvider.js.map +1 -1
- package/dist/admin/components/AIChat/providers/SchemaProvider.mjs.map +1 -1
- package/dist/admin/components/AttributeOptions/AttributeOption.js.map +1 -1
- package/dist/admin/components/AttributeOptions/AttributeOption.mjs.map +1 -1
- package/dist/admin/components/AttributeOptions/AttributeOptions.js.map +1 -1
- package/dist/admin/components/AttributeOptions/AttributeOptions.mjs.map +1 -1
- package/dist/admin/components/AttributeOptions/EmptyAttributes.js.map +1 -1
- package/dist/admin/components/AttributeOptions/EmptyAttributes.mjs.map +1 -1
- package/dist/admin/components/AttributeRow.js.map +1 -1
- package/dist/admin/components/AttributeRow.mjs.map +1 -1
- package/dist/admin/components/CheckboxWithNumberField.js +2 -1
- package/dist/admin/components/CheckboxWithNumberField.js.map +1 -1
- package/dist/admin/components/CheckboxWithNumberField.mjs +2 -1
- package/dist/admin/components/CheckboxWithNumberField.mjs.map +1 -1
- package/dist/admin/components/ComponentCard/ComponentCard.js.map +1 -1
- package/dist/admin/components/ComponentCard/ComponentCard.mjs.map +1 -1
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.js.map +1 -1
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.js.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.mjs.map +1 -1
- package/dist/admin/components/DisplayedType.js.map +1 -1
- package/dist/admin/components/DisplayedType.mjs.map +1 -1
- package/dist/admin/components/DynamicZoneList.js.map +1 -1
- package/dist/admin/components/DynamicZoneList.mjs.map +1 -1
- package/dist/admin/components/Footers.js.map +1 -1
- package/dist/admin/components/Footers.mjs.map +1 -1
- package/dist/admin/components/FormModal/FormModal.js.map +1 -1
- package/dist/admin/components/FormModal/FormModal.mjs.map +1 -1
- package/dist/admin/components/FormModal/attributes/ConditionForm.js.map +1 -1
- package/dist/admin/components/FormModal/attributes/ConditionForm.mjs.map +1 -1
- package/dist/admin/components/FormModal/attributes/advancedForm.js.map +1 -1
- package/dist/admin/components/FormModal/attributes/advancedForm.mjs.map +1 -1
- package/dist/admin/components/FormModal/attributes/baseForm.js.map +1 -1
- package/dist/admin/components/FormModal/attributes/baseForm.mjs.map +1 -1
- package/dist/admin/components/FormModal/component/componentForm.js.map +1 -1
- package/dist/admin/components/FormModal/component/componentForm.mjs.map +1 -1
- package/dist/admin/components/FormModal/forms/utils/createCollectionName.js.map +1 -1
- package/dist/admin/components/FormModal/forms/utils/createCollectionName.mjs.map +1 -1
- package/dist/admin/components/FormModal/utils/createUid.js.map +1 -1
- package/dist/admin/components/FormModal/utils/createUid.mjs.map +1 -1
- package/dist/admin/components/FormModalHeader.js.map +1 -1
- package/dist/admin/components/FormModalHeader.mjs.map +1 -1
- package/dist/admin/components/FormModalSubHeader.js.map +1 -1
- package/dist/admin/components/FormModalSubHeader.mjs.map +1 -1
- package/dist/admin/components/IconPicker/constants.js +3 -0
- package/dist/admin/components/IconPicker/constants.js.map +1 -1
- package/dist/admin/components/IconPicker/constants.mjs +3 -0
- package/dist/admin/components/IconPicker/constants.mjs.map +1 -1
- package/dist/admin/components/List.js.map +1 -1
- package/dist/admin/components/List.mjs.map +1 -1
- package/dist/admin/components/PluralName.js +2 -1
- package/dist/admin/components/PluralName.js.map +1 -1
- package/dist/admin/components/PluralName.mjs +2 -1
- package/dist/admin/components/PluralName.mjs.map +1 -1
- package/dist/admin/components/Relation/RelationField/RelationTargetPicker/RelationTargetPicker.js.map +1 -1
- package/dist/admin/components/Relation/RelationField/RelationTargetPicker/RelationTargetPicker.mjs.map +1 -1
- package/dist/admin/components/Relation/RelationNaturePicker/RelationNaturePicker.js.map +1 -1
- package/dist/admin/components/Relation/RelationNaturePicker/RelationNaturePicker.mjs.map +1 -1
- package/dist/admin/components/SelectComponent.js.map +1 -1
- package/dist/admin/components/SelectComponent.mjs.map +1 -1
- package/dist/admin/components/SingularName.js +2 -1
- package/dist/admin/components/SingularName.js.map +1 -1
- package/dist/admin/components/SingularName.mjs +2 -1
- package/dist/admin/components/SingularName.mjs.map +1 -1
- package/dist/admin/components/TabForm.js.map +1 -1
- package/dist/admin/components/TabForm.mjs.map +1 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/pages/App/index.js.map +1 -1
- package/dist/admin/pages/App/index.mjs.map +1 -1
- package/dist/admin/pages/ListView/ListView.js.map +1 -1
- package/dist/admin/pages/ListView/ListView.mjs.map +1 -1
- package/dist/admin/utils/conditions.js.map +1 -1
- package/dist/admin/utils/conditions.mjs.map +1 -1
- package/dist/admin/utils/getTrad.js.map +1 -1
- package/dist/admin/utils/getTrad.mjs.map +1 -1
- package/dist/admin/utils/prefixPluginTranslations.js.map +1 -1
- package/dist/admin/utils/prefixPluginTranslations.mjs.map +1 -1
- package/dist/admin/utils/timeFormat.js.map +1 -1
- package/dist/admin/utils/timeFormat.mjs.map +1 -1
- package/dist/server/controllers/validation/common.js.map +1 -1
- package/dist/server/controllers/validation/common.mjs.map +1 -1
- package/dist/server/controllers/validation/content-type.js.map +1 -1
- package/dist/server/controllers/validation/content-type.mjs.map +1 -1
- package/dist/server/controllers/validation/model-schema.js.map +1 -1
- package/dist/server/controllers/validation/model-schema.mjs.map +1 -1
- package/dist/server/controllers/validation/relations.js.map +1 -1
- package/dist/server/controllers/validation/relations.mjs.map +1 -1
- package/dist/server/register.js +30 -89
- package/dist/server/register.js.map +1 -1
- package/dist/server/register.mjs +30 -89
- package/dist/server/register.mjs.map +1 -1
- package/dist/server/services/api-handler.js.map +1 -1
- package/dist/server/services/api-handler.mjs.map +1 -1
- package/dist/server/services/component-categories.js.map +1 -1
- package/dist/server/services/component-categories.mjs.map +1 -1
- package/dist/server/services/schema-builder/component-builder.js.map +1 -1
- package/dist/server/services/schema-builder/component-builder.mjs.map +1 -1
- package/dist/server/services/schema-builder/content-type-builder.js.map +1 -1
- package/dist/server/services/schema-builder/content-type-builder.mjs.map +1 -1
- package/dist/server/src/index.d.ts +3 -1
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/register.d.ts +4 -9
- package/dist/server/src/register.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Message.js","sources":["../../../../../../admin/src/components/AIChat/components/Messages/Message.tsx"],"sourcesContent":["import { Typography, Box, IconButton, Flex } from '@strapi/design-system';\nimport { ThumbUp, ThumbDown } from '@strapi/icons';\nimport Markdown from 'react-markdown';\nimport { styled } from 'styled-components';\n\nimport { useFeedbackModal } from '../../FeedbackModal';\nimport { useFeedback } from '../../hooks/useFeedback';\nimport {\n AIMessage,\n type UserMessage as UserMessageType,\n AssistantMessage as AssistantMessageType,\n type MarkerContent as MarkerContentType,\n} from '../../lib/types/messages';\nimport { AnimatedBox } from '../AnimatedBox';\nimport { AttachmentPreview } from '../Attachments/AttachmentPreview';\n\nimport { Marker } from './Marker';\n\nconst MarkdownStyles = styled(Typography)`\n max-width: 65ch;\n margin: 0 auto;\n\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n margin-top: 1.25em;\n margin-bottom: 0.5em;\n font-weight: bold;\n }\n\n p {\n margin-bottom: 1em;\n }\n\n ul,\n ol {\n padding-left: 1.5em; /* indentation for bullet points */\n margin-bottom: 1em;\n }\n\n li {\n margin-bottom: 0.5em;\n list-style-type: disc; /* or whatever style you prefer */\n }\n\n strong {\n font-weight: bold;\n }\n\n /* code blocks, blockquotes, etc. */\n code {\n background-color: ${({ theme }) => theme.colors.neutral100};\n padding: 0.2em 0.4em;\n border-radius: ${({ theme }) => theme.borderRadius};\n border-color: ${({ theme }) => theme.colors.neutral150};\n border-style: solid;\n font-family: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas,\n monospace;\n }\n\n /* links */\n a {\n color: ${({ theme }) => theme.colors.primary500};\n background-color: ${({ theme }) => theme.colors.neutral100};\n padding: 0.2em 0.4em;\n border-radius: ${({ theme }) => theme.borderRadius};\n border-color: ${({ theme }) => theme.colors.neutral150};\n border-style: solid;\n text-decoration: none;\n\n &:hover {\n text-decoration: underline;\n }\n }\n`;\n\n// ---------------------------\n// Tool: schemaGenerationTool helpers\n// ---------------------------\n\ntype SchemaToolSchema = {\n action?: 'create' | 'update' | 'remove';\n uid?: string;\n name?: string;\n category?: string;\n kind?: 'collectionType' | 'singleType' | 'component';\n modelType?: 'component' | 'collectionType' | 'singleType';\n};\n\ntype SchemaToolPart = {\n type: 'tool-schemaGenerationTool';\n input?: { schemas?: SchemaToolSchema[] };\n output?: { schemas?: SchemaToolSchema[]; error?: unknown };\n toolCallId?: string;\n};\n\nconst isSchemaToolPart = (part: any): part is SchemaToolPart =>\n part && typeof part === 'object' && part.type === 'tool-schemaGenerationTool';\n\nconst capitalize = (s?: string) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : '');\n\nconst getSchemaLink = (schema: SchemaToolSchema): string | undefined => {\n const isComponent = (schema.kind ?? schema.modelType) === 'component';\n if (!schema.uid) return undefined;\n return isComponent\n ? `/plugins/content-type-builder/component-categories/${schema.category ?? ''}/${schema.uid}`\n : `/plugins/content-type-builder/content-types/${schema.uid}`;\n};\n\nconst toMarkerFromSchemaTool = (part: SchemaToolPart): MarkerContentType => {\n const outSchemas = part.output?.schemas ?? [];\n const inSchemas = part.input?.schemas ?? [];\n\n const schemas = (outSchemas.length ? outSchemas : inSchemas) as SchemaToolSchema[];\n const numSchemas = schemas.length;\n\n const state: 'loading' | 'success' | 'error' = part.output\n ? part.output.error\n ? 'error'\n : 'success'\n : 'loading';\n\n const steps = schemas.map((schema, index) => ({\n id: `${part.toolCallId ?? 'schemaGenerationTool'}-${schema.uid ?? schema.name ?? index}`,\n description: capitalize(schema.name ?? schema.uid ?? 'Schema'),\n status:\n schema.action === 'create' || schema.action === 'update' || schema.action === 'remove'\n ? schema.action\n : ('update' as const),\n link: getSchemaLink(schema),\n }));\n\n const title =\n state === 'success'\n ? `Updated ${numSchemas} schema${numSchemas === 1 ? '' : 's'}`\n : state === 'error'\n ? `Failed to update schema${numSchemas === 1 ? '' : 's'}`\n : 'Updating schemas';\n\n return {\n type: 'marker',\n title,\n state,\n steps,\n };\n};\n\nconst MessageContent = ({\n part,\n}: {\n part: AIMessage['parts'][number];\n status?: 'loading' | 'success' | 'error';\n}) => {\n if (part.type === 'text') {\n return (\n <MarkdownStyles>\n <Markdown\n components={{\n a: ({ node, ...props }) => <a target=\"_blank\" rel=\"noopener noreferrer\" {...props} />,\n }}\n >\n {part.text}\n </Markdown>\n </MarkdownStyles>\n );\n }\n\n if (isSchemaToolPart(part)) {\n const marker = toMarkerFromSchemaTool(part);\n return <Marker {...marker} />;\n }\n\n return null;\n};\n\nconst UserMessage = ({ message }: { message: UserMessageType }) => {\n const hasText = message.parts.some(\n (content) => content.type === 'text' && content.text.trim() !== ''\n );\n const attachments = message.parts.filter((content) => content.type === 'file');\n\n return (\n <AnimatedBox\n as={Flex}\n direction=\"column\"\n alignItems=\"flex-end\"\n style={{ alignSelf: 'flex-end' }}\n gap={2}\n maxWidth=\"80%\"\n >\n {hasText ? (\n <Box background=\"neutral150\" borderStyle=\"none\" padding={['10px', '16px']} hasRadius>\n {message.parts.map((content, index) => {\n if (content.type !== 'text') return null;\n return <Typography key={index}>{content.text}</Typography>;\n })}\n </Box>\n ) : null}\n\n {/* Attachments */}\n {attachments.map((attachment, idx) => (\n <AttachmentPreview\n key={`${attachment.type === 'file' ? attachment.filename : attachment.type}-${idx}`}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n attachment={{ ...attachment, status: 'ready' } as any}\n />\n ))}\n </AnimatedBox>\n );\n};\n\nconst AssistantMessage = ({\n message,\n isLoading,\n}: {\n message: AssistantMessageType;\n isLoading?: boolean;\n}) => {\n const { upvoteMessage } = useFeedback();\n const { openFeedbackModal } = useFeedbackModal();\n\n return (\n <Box style={{ alignSelf: 'flex-start' }} maxWidth=\"90%\">\n {message.parts.map((content, index) => (\n <MessageContent key={index} part={content} />\n ))}\n {isLoading ? (\n <Flex gap={1}>\n <IconButton\n label=\"Upvote\"\n size=\"XS\"\n variant=\"ghost\"\n onClick={() => upvoteMessage(message.id)}\n >\n <ThumbUp />\n </IconButton>\n <IconButton\n label=\"Downvote\"\n size=\"XS\"\n variant=\"ghost\"\n // For downvoting, user must provide specific feedback\n onClick={() => openFeedbackModal(message.id)}\n >\n <ThumbDown />\n </IconButton>\n </Flex>\n ) : null}\n </Box>\n );\n};\n\nexport const ChatMessage = ({\n message,\n isLoading,\n}: {\n message: AIMessage;\n isLoading?: boolean;\n}) => {\n /**\n * IMPORTANT: Messages are rendered using react-markdown (heavy compute)\n * Component re-renders on each message update, but AI SDK v5 provides\n * throttling (experimental_throttle: 100ms) which batches updates and reduces\n * re-render frequency during streaming.\n */\n if (message.role === 'user') {\n return <UserMessage message={message as UserMessageType} />;\n }\n return <AssistantMessage message={message as AssistantMessageType} />;\n};\n"],"names":["MarkdownStyles","styled","Typography","theme","colors","neutral100","borderRadius","neutral150","primary500","isSchemaToolPart","part","type","capitalize","s","charAt","toUpperCase","slice","getSchemaLink","schema","isComponent","kind","modelType","uid","undefined","category","toMarkerFromSchemaTool","outSchemas","output","schemas","inSchemas","input","length","numSchemas","state","error","steps","map","index","id","toolCallId","name","description","status","action","link","title","MessageContent","_jsx","Markdown","components","a","node","props","target","rel","text","marker","Marker","UserMessage","message","hasText","parts","some","content","trim","attachments","filter","_jsxs","AnimatedBox","as","Flex","direction","alignItems","style","alignSelf","gap","maxWidth","Box","background","borderStyle","padding","hasRadius","attachment","idx","AttachmentPreview","filename","AssistantMessage","isLoading","upvoteMessage","useFeedback","openFeedbackModal","useFeedbackModal","IconButton","label","size","variant","onClick","ThumbUp","ThumbDown","ChatMessage","role"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Message.js","sources":["../../../../../../admin/src/components/AIChat/components/Messages/Message.tsx"],"sourcesContent":["import { Typography, Box, IconButton, Flex } from '@strapi/design-system';\nimport { ThumbUp, ThumbDown } from '@strapi/icons';\nimport Markdown from 'react-markdown';\nimport { styled } from 'styled-components';\n\nimport { useFeedbackModal } from '../../FeedbackModal';\nimport { useFeedback } from '../../hooks/useFeedback';\nimport {\n AIMessage,\n type UserMessage as UserMessageType,\n AssistantMessage as AssistantMessageType,\n type MarkerContent as MarkerContentType,\n} from '../../lib/types/messages';\nimport { AnimatedBox } from '../AnimatedBox';\nimport { AttachmentPreview } from '../Attachments/AttachmentPreview';\n\nimport { Marker } from './Marker';\n\nconst MarkdownStyles = styled(Typography)`\n max-width: 65ch;\n margin: 0 auto;\n\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n margin-top: 1.25em;\n margin-bottom: 0.5em;\n font-weight: bold;\n }\n\n p {\n margin-bottom: 1em;\n }\n\n ul,\n ol {\n padding-left: 1.5em; /* indentation for bullet points */\n margin-bottom: 1em;\n }\n\n li {\n margin-bottom: 0.5em;\n list-style-type: disc; /* or whatever style you prefer */\n }\n\n strong {\n font-weight: bold;\n }\n\n /* code blocks, blockquotes, etc. */\n code {\n background-color: ${({ theme }) => theme.colors.neutral100};\n padding: 0.2em 0.4em;\n border-radius: ${({ theme }) => theme.borderRadius};\n border-color: ${({ theme }) => theme.colors.neutral150};\n border-style: solid;\n font-family: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas,\n monospace;\n }\n\n /* links */\n a {\n color: ${({ theme }) => theme.colors.primary500};\n background-color: ${({ theme }) => theme.colors.neutral100};\n padding: 0.2em 0.4em;\n border-radius: ${({ theme }) => theme.borderRadius};\n border-color: ${({ theme }) => theme.colors.neutral150};\n border-style: solid;\n text-decoration: none;\n\n &:hover {\n text-decoration: underline;\n }\n }\n`;\n\n// ---------------------------\n// Tool: schemaGenerationTool helpers\n// ---------------------------\n\ntype SchemaToolSchema = {\n action?: 'create' | 'update' | 'remove';\n uid?: string;\n name?: string;\n category?: string;\n kind?: 'collectionType' | 'singleType' | 'component';\n modelType?: 'component' | 'collectionType' | 'singleType';\n};\n\ntype SchemaToolPart = {\n type: 'tool-schemaGenerationTool';\n input?: { schemas?: SchemaToolSchema[] };\n output?: { schemas?: SchemaToolSchema[]; error?: unknown };\n toolCallId?: string;\n};\n\nconst isSchemaToolPart = (part: any): part is SchemaToolPart =>\n part && typeof part === 'object' && part.type === 'tool-schemaGenerationTool';\n\nconst capitalize = (s?: string) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : '');\n\nconst getSchemaLink = (schema: SchemaToolSchema): string | undefined => {\n const isComponent = (schema.kind ?? schema.modelType) === 'component';\n if (!schema.uid) return undefined;\n return isComponent\n ? `/plugins/content-type-builder/component-categories/${schema.category ?? ''}/${schema.uid}`\n : `/plugins/content-type-builder/content-types/${schema.uid}`;\n};\n\nconst toMarkerFromSchemaTool = (part: SchemaToolPart): MarkerContentType => {\n const outSchemas = part.output?.schemas ?? [];\n const inSchemas = part.input?.schemas ?? [];\n\n const schemas = (outSchemas.length ? outSchemas : inSchemas) as SchemaToolSchema[];\n const numSchemas = schemas.length;\n\n const state: 'loading' | 'success' | 'error' = part.output\n ? part.output.error\n ? 'error'\n : 'success'\n : 'loading';\n\n const steps = schemas.map((schema, index) => ({\n id: `${part.toolCallId ?? 'schemaGenerationTool'}-${schema.uid ?? schema.name ?? index}`,\n description: capitalize(schema.name ?? schema.uid ?? 'Schema'),\n status:\n schema.action === 'create' || schema.action === 'update' || schema.action === 'remove'\n ? schema.action\n : ('update' as const),\n link: getSchemaLink(schema),\n }));\n\n const title =\n state === 'success'\n ? `Updated ${numSchemas} schema${numSchemas === 1 ? '' : 's'}`\n : state === 'error'\n ? `Failed to update schema${numSchemas === 1 ? '' : 's'}`\n : 'Updating schemas';\n\n return {\n type: 'marker',\n title,\n state,\n steps,\n };\n};\n\nconst MessageContent = ({\n part,\n}: {\n part: AIMessage['parts'][number];\n status?: 'loading' | 'success' | 'error';\n}) => {\n if (part.type === 'text') {\n return (\n <MarkdownStyles>\n <Markdown\n components={{\n a: ({ node, ...props }) => <a target=\"_blank\" rel=\"noopener noreferrer\" {...props} />,\n }}\n >\n {part.text}\n </Markdown>\n </MarkdownStyles>\n );\n }\n\n if (isSchemaToolPart(part)) {\n const marker = toMarkerFromSchemaTool(part);\n return <Marker {...marker} />;\n }\n\n return null;\n};\n\nconst UserMessage = ({ message }: { message: UserMessageType }) => {\n const hasText = message.parts.some(\n (content) => content.type === 'text' && content.text.trim() !== ''\n );\n const attachments = message.parts.filter((content) => content.type === 'file');\n\n return (\n <AnimatedBox\n as={Flex}\n direction=\"column\"\n alignItems=\"flex-end\"\n style={{ alignSelf: 'flex-end' }}\n gap={2}\n maxWidth=\"80%\"\n >\n {hasText ? (\n <Box background=\"neutral150\" borderStyle=\"none\" padding={['10px', '16px']} hasRadius>\n {message.parts.map((content, index) => {\n if (content.type !== 'text') return null;\n return <Typography key={index}>{content.text}</Typography>;\n })}\n </Box>\n ) : null}\n\n {/* Attachments */}\n {attachments.map((attachment, idx) => (\n <AttachmentPreview\n key={`${attachment.type === 'file' ? attachment.filename : attachment.type}-${idx}`}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n attachment={{ ...attachment, status: 'ready' } as any}\n />\n ))}\n </AnimatedBox>\n );\n};\n\nconst AssistantMessage = ({\n message,\n isLoading,\n}: {\n message: AssistantMessageType;\n isLoading?: boolean;\n}) => {\n const { upvoteMessage } = useFeedback();\n const { openFeedbackModal } = useFeedbackModal();\n\n return (\n <Box style={{ alignSelf: 'flex-start' }} maxWidth=\"90%\">\n {message.parts.map((content, index) => (\n <MessageContent key={index} part={content} />\n ))}\n {isLoading ? (\n <Flex gap={1}>\n <IconButton\n label=\"Upvote\"\n size=\"XS\"\n variant=\"ghost\"\n onClick={() => upvoteMessage(message.id)}\n >\n <ThumbUp />\n </IconButton>\n <IconButton\n label=\"Downvote\"\n size=\"XS\"\n variant=\"ghost\"\n // For downvoting, user must provide specific feedback\n onClick={() => openFeedbackModal(message.id)}\n >\n <ThumbDown />\n </IconButton>\n </Flex>\n ) : null}\n </Box>\n );\n};\n\nexport const ChatMessage = ({\n message,\n isLoading,\n}: {\n message: AIMessage;\n isLoading?: boolean;\n}) => {\n /**\n * IMPORTANT: Messages are rendered using react-markdown (heavy compute)\n * Component re-renders on each message update, but AI SDK v5 provides\n * throttling (experimental_throttle: 100ms) which batches updates and reduces\n * re-render frequency during streaming.\n */\n if (message.role === 'user') {\n return <UserMessage message={message as UserMessageType} />;\n }\n return <AssistantMessage message={message as AssistantMessageType} />;\n};\n"],"names":["MarkdownStyles","styled","Typography","theme","colors","neutral100","borderRadius","neutral150","primary500","isSchemaToolPart","part","type","capitalize","s","charAt","toUpperCase","slice","getSchemaLink","schema","isComponent","kind","modelType","uid","undefined","category","toMarkerFromSchemaTool","outSchemas","output","schemas","inSchemas","input","length","numSchemas","state","error","steps","map","index","id","toolCallId","name","description","status","action","link","title","MessageContent","_jsx","Markdown","components","a","node","props","target","rel","text","marker","Marker","UserMessage","message","hasText","parts","some","content","trim","attachments","filter","_jsxs","AnimatedBox","as","Flex","direction","alignItems","style","alignSelf","gap","maxWidth","Box","background","borderStyle","padding","hasRadius","attachment","idx","AttachmentPreview","filename","AssistantMessage","isLoading","upvoteMessage","useFeedback","openFeedbackModal","useFeedbackModal","IconButton","label","size","variant","onClick","ThumbUp","ThumbDown","ChatMessage","role"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Message.mjs","sources":["../../../../../../admin/src/components/AIChat/components/Messages/Message.tsx"],"sourcesContent":["import { Typography, Box, IconButton, Flex } from '@strapi/design-system';\nimport { ThumbUp, ThumbDown } from '@strapi/icons';\nimport Markdown from 'react-markdown';\nimport { styled } from 'styled-components';\n\nimport { useFeedbackModal } from '../../FeedbackModal';\nimport { useFeedback } from '../../hooks/useFeedback';\nimport {\n AIMessage,\n type UserMessage as UserMessageType,\n AssistantMessage as AssistantMessageType,\n type MarkerContent as MarkerContentType,\n} from '../../lib/types/messages';\nimport { AnimatedBox } from '../AnimatedBox';\nimport { AttachmentPreview } from '../Attachments/AttachmentPreview';\n\nimport { Marker } from './Marker';\n\nconst MarkdownStyles = styled(Typography)`\n max-width: 65ch;\n margin: 0 auto;\n\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n margin-top: 1.25em;\n margin-bottom: 0.5em;\n font-weight: bold;\n }\n\n p {\n margin-bottom: 1em;\n }\n\n ul,\n ol {\n padding-left: 1.5em; /* indentation for bullet points */\n margin-bottom: 1em;\n }\n\n li {\n margin-bottom: 0.5em;\n list-style-type: disc; /* or whatever style you prefer */\n }\n\n strong {\n font-weight: bold;\n }\n\n /* code blocks, blockquotes, etc. */\n code {\n background-color: ${({ theme }) => theme.colors.neutral100};\n padding: 0.2em 0.4em;\n border-radius: ${({ theme }) => theme.borderRadius};\n border-color: ${({ theme }) => theme.colors.neutral150};\n border-style: solid;\n font-family: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas,\n monospace;\n }\n\n /* links */\n a {\n color: ${({ theme }) => theme.colors.primary500};\n background-color: ${({ theme }) => theme.colors.neutral100};\n padding: 0.2em 0.4em;\n border-radius: ${({ theme }) => theme.borderRadius};\n border-color: ${({ theme }) => theme.colors.neutral150};\n border-style: solid;\n text-decoration: none;\n\n &:hover {\n text-decoration: underline;\n }\n }\n`;\n\n// ---------------------------\n// Tool: schemaGenerationTool helpers\n// ---------------------------\n\ntype SchemaToolSchema = {\n action?: 'create' | 'update' | 'remove';\n uid?: string;\n name?: string;\n category?: string;\n kind?: 'collectionType' | 'singleType' | 'component';\n modelType?: 'component' | 'collectionType' | 'singleType';\n};\n\ntype SchemaToolPart = {\n type: 'tool-schemaGenerationTool';\n input?: { schemas?: SchemaToolSchema[] };\n output?: { schemas?: SchemaToolSchema[]; error?: unknown };\n toolCallId?: string;\n};\n\nconst isSchemaToolPart = (part: any): part is SchemaToolPart =>\n part && typeof part === 'object' && part.type === 'tool-schemaGenerationTool';\n\nconst capitalize = (s?: string) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : '');\n\nconst getSchemaLink = (schema: SchemaToolSchema): string | undefined => {\n const isComponent = (schema.kind ?? schema.modelType) === 'component';\n if (!schema.uid) return undefined;\n return isComponent\n ? `/plugins/content-type-builder/component-categories/${schema.category ?? ''}/${schema.uid}`\n : `/plugins/content-type-builder/content-types/${schema.uid}`;\n};\n\nconst toMarkerFromSchemaTool = (part: SchemaToolPart): MarkerContentType => {\n const outSchemas = part.output?.schemas ?? [];\n const inSchemas = part.input?.schemas ?? [];\n\n const schemas = (outSchemas.length ? outSchemas : inSchemas) as SchemaToolSchema[];\n const numSchemas = schemas.length;\n\n const state: 'loading' | 'success' | 'error' = part.output\n ? part.output.error\n ? 'error'\n : 'success'\n : 'loading';\n\n const steps = schemas.map((schema, index) => ({\n id: `${part.toolCallId ?? 'schemaGenerationTool'}-${schema.uid ?? schema.name ?? index}`,\n description: capitalize(schema.name ?? schema.uid ?? 'Schema'),\n status:\n schema.action === 'create' || schema.action === 'update' || schema.action === 'remove'\n ? schema.action\n : ('update' as const),\n link: getSchemaLink(schema),\n }));\n\n const title =\n state === 'success'\n ? `Updated ${numSchemas} schema${numSchemas === 1 ? '' : 's'}`\n : state === 'error'\n ? `Failed to update schema${numSchemas === 1 ? '' : 's'}`\n : 'Updating schemas';\n\n return {\n type: 'marker',\n title,\n state,\n steps,\n };\n};\n\nconst MessageContent = ({\n part,\n}: {\n part: AIMessage['parts'][number];\n status?: 'loading' | 'success' | 'error';\n}) => {\n if (part.type === 'text') {\n return (\n <MarkdownStyles>\n <Markdown\n components={{\n a: ({ node, ...props }) => <a target=\"_blank\" rel=\"noopener noreferrer\" {...props} />,\n }}\n >\n {part.text}\n </Markdown>\n </MarkdownStyles>\n );\n }\n\n if (isSchemaToolPart(part)) {\n const marker = toMarkerFromSchemaTool(part);\n return <Marker {...marker} />;\n }\n\n return null;\n};\n\nconst UserMessage = ({ message }: { message: UserMessageType }) => {\n const hasText = message.parts.some(\n (content) => content.type === 'text' && content.text.trim() !== ''\n );\n const attachments = message.parts.filter((content) => content.type === 'file');\n\n return (\n <AnimatedBox\n as={Flex}\n direction=\"column\"\n alignItems=\"flex-end\"\n style={{ alignSelf: 'flex-end' }}\n gap={2}\n maxWidth=\"80%\"\n >\n {hasText ? (\n <Box background=\"neutral150\" borderStyle=\"none\" padding={['10px', '16px']} hasRadius>\n {message.parts.map((content, index) => {\n if (content.type !== 'text') return null;\n return <Typography key={index}>{content.text}</Typography>;\n })}\n </Box>\n ) : null}\n\n {/* Attachments */}\n {attachments.map((attachment, idx) => (\n <AttachmentPreview\n key={`${attachment.type === 'file' ? attachment.filename : attachment.type}-${idx}`}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n attachment={{ ...attachment, status: 'ready' } as any}\n />\n ))}\n </AnimatedBox>\n );\n};\n\nconst AssistantMessage = ({\n message,\n isLoading,\n}: {\n message: AssistantMessageType;\n isLoading?: boolean;\n}) => {\n const { upvoteMessage } = useFeedback();\n const { openFeedbackModal } = useFeedbackModal();\n\n return (\n <Box style={{ alignSelf: 'flex-start' }} maxWidth=\"90%\">\n {message.parts.map((content, index) => (\n <MessageContent key={index} part={content} />\n ))}\n {isLoading ? (\n <Flex gap={1}>\n <IconButton\n label=\"Upvote\"\n size=\"XS\"\n variant=\"ghost\"\n onClick={() => upvoteMessage(message.id)}\n >\n <ThumbUp />\n </IconButton>\n <IconButton\n label=\"Downvote\"\n size=\"XS\"\n variant=\"ghost\"\n // For downvoting, user must provide specific feedback\n onClick={() => openFeedbackModal(message.id)}\n >\n <ThumbDown />\n </IconButton>\n </Flex>\n ) : null}\n </Box>\n );\n};\n\nexport const ChatMessage = ({\n message,\n isLoading,\n}: {\n message: AIMessage;\n isLoading?: boolean;\n}) => {\n /**\n * IMPORTANT: Messages are rendered using react-markdown (heavy compute)\n * Component re-renders on each message update, but AI SDK v5 provides\n * throttling (experimental_throttle: 100ms) which batches updates and reduces\n * re-render frequency during streaming.\n */\n if (message.role === 'user') {\n return <UserMessage message={message as UserMessageType} />;\n }\n return <AssistantMessage message={message as AssistantMessageType} />;\n};\n"],"names":["MarkdownStyles","styled","Typography","theme","colors","neutral100","borderRadius","neutral150","primary500","isSchemaToolPart","part","type","capitalize","s","charAt","toUpperCase","slice","getSchemaLink","schema","isComponent","kind","modelType","uid","undefined","category","toMarkerFromSchemaTool","outSchemas","output","schemas","inSchemas","input","length","numSchemas","state","error","steps","map","index","id","toolCallId","name","description","status","action","link","title","MessageContent","_jsx","Markdown","components","a","node","props","target","rel","text","marker","Marker","UserMessage","message","hasText","parts","some","content","trim","attachments","filter","_jsxs","AnimatedBox","as","Flex","direction","alignItems","style","alignSelf","gap","maxWidth","Box","background","borderStyle","padding","hasRadius","attachment","idx","AttachmentPreview","filename","AssistantMessage","isLoading","upvoteMessage","useFeedback","openFeedbackModal","useFeedbackModal","IconButton","label","size","variant","onClick","ThumbUp","ThumbDown","ChatMessage","role"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Message.mjs","sources":["../../../../../../admin/src/components/AIChat/components/Messages/Message.tsx"],"sourcesContent":["import { Typography, Box, IconButton, Flex } from '@strapi/design-system';\nimport { ThumbUp, ThumbDown } from '@strapi/icons';\nimport Markdown from 'react-markdown';\nimport { styled } from 'styled-components';\n\nimport { useFeedbackModal } from '../../FeedbackModal';\nimport { useFeedback } from '../../hooks/useFeedback';\nimport {\n AIMessage,\n type UserMessage as UserMessageType,\n AssistantMessage as AssistantMessageType,\n type MarkerContent as MarkerContentType,\n} from '../../lib/types/messages';\nimport { AnimatedBox } from '../AnimatedBox';\nimport { AttachmentPreview } from '../Attachments/AttachmentPreview';\n\nimport { Marker } from './Marker';\n\nconst MarkdownStyles = styled(Typography)`\n max-width: 65ch;\n margin: 0 auto;\n\n h1,\n h2,\n h3,\n h4,\n h5,\n h6 {\n margin-top: 1.25em;\n margin-bottom: 0.5em;\n font-weight: bold;\n }\n\n p {\n margin-bottom: 1em;\n }\n\n ul,\n ol {\n padding-left: 1.5em; /* indentation for bullet points */\n margin-bottom: 1em;\n }\n\n li {\n margin-bottom: 0.5em;\n list-style-type: disc; /* or whatever style you prefer */\n }\n\n strong {\n font-weight: bold;\n }\n\n /* code blocks, blockquotes, etc. */\n code {\n background-color: ${({ theme }) => theme.colors.neutral100};\n padding: 0.2em 0.4em;\n border-radius: ${({ theme }) => theme.borderRadius};\n border-color: ${({ theme }) => theme.colors.neutral150};\n border-style: solid;\n font-family: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas,\n monospace;\n }\n\n /* links */\n a {\n color: ${({ theme }) => theme.colors.primary500};\n background-color: ${({ theme }) => theme.colors.neutral100};\n padding: 0.2em 0.4em;\n border-radius: ${({ theme }) => theme.borderRadius};\n border-color: ${({ theme }) => theme.colors.neutral150};\n border-style: solid;\n text-decoration: none;\n\n &:hover {\n text-decoration: underline;\n }\n }\n`;\n\n// ---------------------------\n// Tool: schemaGenerationTool helpers\n// ---------------------------\n\ntype SchemaToolSchema = {\n action?: 'create' | 'update' | 'remove';\n uid?: string;\n name?: string;\n category?: string;\n kind?: 'collectionType' | 'singleType' | 'component';\n modelType?: 'component' | 'collectionType' | 'singleType';\n};\n\ntype SchemaToolPart = {\n type: 'tool-schemaGenerationTool';\n input?: { schemas?: SchemaToolSchema[] };\n output?: { schemas?: SchemaToolSchema[]; error?: unknown };\n toolCallId?: string;\n};\n\nconst isSchemaToolPart = (part: any): part is SchemaToolPart =>\n part && typeof part === 'object' && part.type === 'tool-schemaGenerationTool';\n\nconst capitalize = (s?: string) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : '');\n\nconst getSchemaLink = (schema: SchemaToolSchema): string | undefined => {\n const isComponent = (schema.kind ?? schema.modelType) === 'component';\n if (!schema.uid) return undefined;\n return isComponent\n ? `/plugins/content-type-builder/component-categories/${schema.category ?? ''}/${schema.uid}`\n : `/plugins/content-type-builder/content-types/${schema.uid}`;\n};\n\nconst toMarkerFromSchemaTool = (part: SchemaToolPart): MarkerContentType => {\n const outSchemas = part.output?.schemas ?? [];\n const inSchemas = part.input?.schemas ?? [];\n\n const schemas = (outSchemas.length ? outSchemas : inSchemas) as SchemaToolSchema[];\n const numSchemas = schemas.length;\n\n const state: 'loading' | 'success' | 'error' = part.output\n ? part.output.error\n ? 'error'\n : 'success'\n : 'loading';\n\n const steps = schemas.map((schema, index) => ({\n id: `${part.toolCallId ?? 'schemaGenerationTool'}-${schema.uid ?? schema.name ?? index}`,\n description: capitalize(schema.name ?? schema.uid ?? 'Schema'),\n status:\n schema.action === 'create' || schema.action === 'update' || schema.action === 'remove'\n ? schema.action\n : ('update' as const),\n link: getSchemaLink(schema),\n }));\n\n const title =\n state === 'success'\n ? `Updated ${numSchemas} schema${numSchemas === 1 ? '' : 's'}`\n : state === 'error'\n ? `Failed to update schema${numSchemas === 1 ? '' : 's'}`\n : 'Updating schemas';\n\n return {\n type: 'marker',\n title,\n state,\n steps,\n };\n};\n\nconst MessageContent = ({\n part,\n}: {\n part: AIMessage['parts'][number];\n status?: 'loading' | 'success' | 'error';\n}) => {\n if (part.type === 'text') {\n return (\n <MarkdownStyles>\n <Markdown\n components={{\n a: ({ node, ...props }) => <a target=\"_blank\" rel=\"noopener noreferrer\" {...props} />,\n }}\n >\n {part.text}\n </Markdown>\n </MarkdownStyles>\n );\n }\n\n if (isSchemaToolPart(part)) {\n const marker = toMarkerFromSchemaTool(part);\n return <Marker {...marker} />;\n }\n\n return null;\n};\n\nconst UserMessage = ({ message }: { message: UserMessageType }) => {\n const hasText = message.parts.some(\n (content) => content.type === 'text' && content.text.trim() !== ''\n );\n const attachments = message.parts.filter((content) => content.type === 'file');\n\n return (\n <AnimatedBox\n as={Flex}\n direction=\"column\"\n alignItems=\"flex-end\"\n style={{ alignSelf: 'flex-end' }}\n gap={2}\n maxWidth=\"80%\"\n >\n {hasText ? (\n <Box background=\"neutral150\" borderStyle=\"none\" padding={['10px', '16px']} hasRadius>\n {message.parts.map((content, index) => {\n if (content.type !== 'text') return null;\n return <Typography key={index}>{content.text}</Typography>;\n })}\n </Box>\n ) : null}\n\n {/* Attachments */}\n {attachments.map((attachment, idx) => (\n <AttachmentPreview\n key={`${attachment.type === 'file' ? attachment.filename : attachment.type}-${idx}`}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n attachment={{ ...attachment, status: 'ready' } as any}\n />\n ))}\n </AnimatedBox>\n );\n};\n\nconst AssistantMessage = ({\n message,\n isLoading,\n}: {\n message: AssistantMessageType;\n isLoading?: boolean;\n}) => {\n const { upvoteMessage } = useFeedback();\n const { openFeedbackModal } = useFeedbackModal();\n\n return (\n <Box style={{ alignSelf: 'flex-start' }} maxWidth=\"90%\">\n {message.parts.map((content, index) => (\n <MessageContent key={index} part={content} />\n ))}\n {isLoading ? (\n <Flex gap={1}>\n <IconButton\n label=\"Upvote\"\n size=\"XS\"\n variant=\"ghost\"\n onClick={() => upvoteMessage(message.id)}\n >\n <ThumbUp />\n </IconButton>\n <IconButton\n label=\"Downvote\"\n size=\"XS\"\n variant=\"ghost\"\n // For downvoting, user must provide specific feedback\n onClick={() => openFeedbackModal(message.id)}\n >\n <ThumbDown />\n </IconButton>\n </Flex>\n ) : null}\n </Box>\n );\n};\n\nexport const ChatMessage = ({\n message,\n isLoading,\n}: {\n message: AIMessage;\n isLoading?: boolean;\n}) => {\n /**\n * IMPORTANT: Messages are rendered using react-markdown (heavy compute)\n * Component re-renders on each message update, but AI SDK v5 provides\n * throttling (experimental_throttle: 100ms) which batches updates and reduces\n * re-render frequency during streaming.\n */\n if (message.role === 'user') {\n return <UserMessage message={message as UserMessageType} />;\n }\n return <AssistantMessage message={message as AssistantMessageType} />;\n};\n"],"names":["MarkdownStyles","styled","Typography","theme","colors","neutral100","borderRadius","neutral150","primary500","isSchemaToolPart","part","type","capitalize","s","charAt","toUpperCase","slice","getSchemaLink","schema","isComponent","kind","modelType","uid","undefined","category","toMarkerFromSchemaTool","outSchemas","output","schemas","inSchemas","input","length","numSchemas","state","error","steps","map","index","id","toolCallId","name","description","status","action","link","title","MessageContent","_jsx","Markdown","components","a","node","props","target","rel","text","marker","Marker","UserMessage","message","hasText","parts","some","content","trim","attachments","filter","_jsxs","AnimatedBox","as","Flex","direction","alignItems","style","alignSelf","gap","maxWidth","Box","background","borderStyle","padding","hasRadius","attachment","idx","AttachmentPreview","filename","AssistantMessage","isLoading","upvoteMessage","useFeedback","openFeedbackModal","useFeedbackModal","IconButton","label","size","variant","onClick","ThumbUp","ThumbDown","ChatMessage","role"],"mappings":";;;;;;;;;;;AAkBA,MAAMA,cAAAA,GAAiBC,MAAOC,CAAAA,UAAAA,CAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAoCnB,EAAE,CAAC,EAAEC,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACC,UAAU,CAAC;;AAE5C,mBAAA,EAAE,CAAC,EAAEF,KAAK,EAAE,GAAKA,KAAAA,CAAMG,YAAY,CAAC;kBACrC,EAAE,CAAC,EAAEH,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACG,UAAU,CAAC;;;;;;;;WAQhD,EAAE,CAAC,EAAEJ,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACI,UAAU,CAAC;sBAC9B,EAAE,CAAC,EAAEL,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACC,UAAU,CAAC;;AAE5C,mBAAA,EAAE,CAAC,EAAEF,KAAK,EAAE,GAAKA,KAAAA,CAAMG,YAAY,CAAC;kBACrC,EAAE,CAAC,EAAEH,KAAK,EAAE,GAAKA,KAAMC,CAAAA,MAAM,CAACG,UAAU,CAAC;;;;;;;;AAQ3D,CAAC;AAsBD,MAAME,gBAAAA,GAAmB,CAACC,IACxBA,GAAAA,IAAAA,IAAQ,OAAOA,IAAS,KAAA,QAAA,IAAYA,IAAKC,CAAAA,IAAI,KAAK,2BAAA;AAEpD,MAAMC,UAAa,GAAA,CAACC,CAAgBA,GAAAA,CAAAA,GAAIA,CAAEC,CAAAA,MAAM,CAAC,CAAA,CAAA,CAAGC,WAAW,EAAA,GAAKF,CAAEG,CAAAA,KAAK,CAAC,CAAK,CAAA,GAAA,EAAA;AAEjF,MAAMC,gBAAgB,CAACC,MAAAA,GAAAA;IACrB,MAAMC,WAAAA,GAAc,CAACD,MAAAA,CAAOE,IAAI,IAAIF,MAAAA,CAAOG,SAAQ,MAAO,WAAA;AAC1D,IAAA,IAAI,CAACH,MAAAA,CAAOI,GAAG,EAAE,OAAOC,SAAAA;AACxB,IAAA,OAAOJ,cACH,CAAC,mDAAmD,EAAED,MAAOM,CAAAA,QAAQ,IAAI,EAAG,CAAA,CAAC,EAAEN,MAAOI,CAAAA,GAAG,EAAE,GAC3F,CAAC,4CAA4C,EAAEJ,MAAAA,CAAOI,GAAG,CAAE,CAAA;AACjE,CAAA;AAEA,MAAMG,yBAAyB,CAACf,IAAAA,GAAAA;AAC9B,IAAA,MAAMgB,UAAahB,GAAAA,IAAAA,CAAKiB,MAAM,EAAEC,WAAW,EAAE;AAC7C,IAAA,MAAMC,SAAYnB,GAAAA,IAAAA,CAAKoB,KAAK,EAAEF,WAAW,EAAE;AAE3C,IAAA,MAAMA,OAAWF,GAAAA,UAAAA,CAAWK,MAAM,GAAGL,UAAaG,GAAAA,SAAAA;IAClD,MAAMG,UAAAA,GAAaJ,QAAQG,MAAM;IAEjC,MAAME,KAAAA,GAAyCvB,IAAKiB,CAAAA,MAAM,GACtDjB,IAAAA,CAAKiB,MAAM,CAACO,KAAK,GACf,OAAA,GACA,SACF,GAAA,SAAA;AAEJ,IAAA,MAAMC,QAAQP,OAAQQ,CAAAA,GAAG,CAAC,CAAClB,MAAAA,EAAQmB,SAAW;AAC5CC,YAAAA,EAAAA,EAAI,CAAG5B,EAAAA,IAAAA,CAAK6B,UAAU,IAAI,sBAAuB,CAAA,CAAC,EAAErB,MAAAA,CAAOI,GAAG,IAAIJ,MAAOsB,CAAAA,IAAI,IAAIH,KAAO,CAAA,CAAA;AACxFI,YAAAA,WAAAA,EAAa7B,WAAWM,MAAOsB,CAAAA,IAAI,IAAItB,MAAAA,CAAOI,GAAG,IAAI,QAAA,CAAA;AACrDoB,YAAAA,MAAAA,EACExB,MAAOyB,CAAAA,MAAM,KAAK,QAAA,IAAYzB,OAAOyB,MAAM,KAAK,QAAYzB,IAAAA,MAAAA,CAAOyB,MAAM,KAAK,QAC1EzB,GAAAA,MAAAA,CAAOyB,MAAM,GACZ,QAAA;AACPC,YAAAA,IAAAA,EAAM3B,aAAcC,CAAAA,MAAAA;SACtB,CAAA,CAAA;IAEA,MAAM2B,KAAAA,GACJZ,UAAU,SACN,GAAA,CAAC,QAAQ,EAAED,UAAAA,CAAW,OAAO,EAAEA,UAAe,KAAA,CAAA,GAAI,KAAK,GAAK,CAAA,CAAA,GAC5DC,KAAU,KAAA,OAAA,GACR,CAAC,uBAAuB,EAAED,UAAe,KAAA,CAAA,GAAI,EAAK,GAAA,GAAA,CAAA,CAAK,GACvD,kBAAA;IAER,OAAO;QACLrB,IAAM,EAAA,QAAA;AACNkC,QAAAA,KAAAA;AACAZ,QAAAA,KAAAA;AACAE,QAAAA;AACF,KAAA;AACF,CAAA;AAEA,MAAMW,cAAiB,GAAA,CAAC,EACtBpC,IAAI,EAIL,GAAA;IACC,IAAIA,IAAAA,CAAKC,IAAI,KAAK,MAAQ,EAAA;AACxB,QAAA,qBACEoC,GAAC/C,CAAAA,cAAAA,EAAAA;AACC,YAAA,QAAA,gBAAA+C,GAACC,CAAAA,QAAAA,EAAAA;gBACCC,UAAY,EAAA;AACVC,oBAAAA,CAAAA,EAAG,CAAC,EAAEC,IAAI,EAAE,GAAGC,KAAAA,EAAO,iBAAKL,GAACG,CAAAA,GAAAA,EAAAA;4BAAEG,MAAO,EAAA,QAAA;4BAASC,GAAI,EAAA,qBAAA;AAAuB,4BAAA,GAAGF;;AAC9E,iBAAA;AAEC1C,gBAAAA,QAAAA,EAAAA,IAAAA,CAAK6C;;;AAId;AAEA,IAAA,IAAI9C,iBAAiBC,IAAO,CAAA,EAAA;AAC1B,QAAA,MAAM8C,SAAS/B,sBAAuBf,CAAAA,IAAAA,CAAAA;AACtC,QAAA,qBAAOqC,GAACU,CAAAA,MAAAA,EAAAA;AAAQ,YAAA,GAAGD;;AACrB;IAEA,OAAO,IAAA;AACT,CAAA;AAEA,MAAME,WAAc,GAAA,CAAC,EAAEC,OAAO,EAAgC,GAAA;AAC5D,IAAA,MAAMC,UAAUD,OAAQE,CAAAA,KAAK,CAACC,IAAI,CAChC,CAACC,OAAAA,GAAYA,OAAQpD,CAAAA,IAAI,KAAK,MAAUoD,IAAAA,OAAAA,CAAQR,IAAI,CAACS,IAAI,EAAO,KAAA,EAAA,CAAA;IAElE,MAAMC,WAAAA,GAAcN,OAAQE,CAAAA,KAAK,CAACK,MAAM,CAAC,CAACH,OAAAA,GAAYA,OAAQpD,CAAAA,IAAI,KAAK,MAAA,CAAA;AAEvE,IAAA,qBACEwD,IAACC,CAAAA,WAAAA,EAAAA;QACCC,EAAIC,EAAAA,IAAAA;QACJC,SAAU,EAAA,QAAA;QACVC,UAAW,EAAA,UAAA;QACXC,KAAO,EAAA;YAAEC,SAAW,EAAA;AAAW,SAAA;QAC/BC,GAAK,EAAA,CAAA;QACLC,QAAS,EAAA,KAAA;;AAERhB,YAAAA,OAAAA,iBACCb,GAAC8B,CAAAA,GAAAA,EAAAA;gBAAIC,UAAW,EAAA,YAAA;gBAAaC,WAAY,EAAA,MAAA;gBAAOC,OAAS,EAAA;AAAC,oBAAA,MAAA;AAAQ,oBAAA;AAAO,iBAAA;gBAAEC,SAAS,EAAA,IAAA;AACjFtB,gBAAAA,QAAAA,EAAAA,OAAAA,CAAQE,KAAK,CAACzB,GAAG,CAAC,CAAC2B,OAAS1B,EAAAA,KAAAA,GAAAA;AAC3B,oBAAA,IAAI0B,OAAQpD,CAAAA,IAAI,KAAK,MAAA,EAAQ,OAAO,IAAA;AACpC,oBAAA,qBAAOoC,GAAC7C,CAAAA,UAAAA,EAAAA;AAAwB6D,wBAAAA,QAAAA,EAAAA,OAAAA,CAAQR;AAAhBlB,qBAAAA,EAAAA,KAAAA,CAAAA;AAC1B,iBAAA;AAEA,aAAA,CAAA,GAAA,IAAA;AAGH4B,YAAAA,WAAAA,CAAY7B,GAAG,CAAC,CAAC8C,UAAAA,EAAYC,oBAC5BpC,GAACqC,CAAAA,iBAAAA,EAAAA;;oBAGCF,UAAY,EAAA;AAAE,wBAAA,GAAGA,UAAU;wBAAExC,MAAQ,EAAA;AAAQ;AAFxC,iBAAA,EAAA,CAAA,EAAGwC,UAAWvE,CAAAA,IAAI,KAAK,MAAA,GAASuE,UAAWG,CAAAA,QAAQ,GAAGH,UAAAA,CAAWvE,IAAI,CAAC,CAAC,EAAEwE,GAAK,CAAA,CAAA,CAAA;;;AAO7F,CAAA;AAEA,MAAMG,mBAAmB,CAAC,EACxB3B,OAAO,EACP4B,SAAS,EAIV,GAAA;IACC,MAAM,EAAEC,aAAa,EAAE,GAAGC,WAAAA,EAAAA;IAC1B,MAAM,EAAEC,iBAAiB,EAAE,GAAGC,gBAAAA,EAAAA;AAE9B,IAAA,qBACExB,IAACU,CAAAA,GAAAA,EAAAA;QAAIJ,KAAO,EAAA;YAAEC,SAAW,EAAA;AAAa,SAAA;QAAGE,QAAS,EAAA,KAAA;;AAC/CjB,YAAAA,OAAAA,CAAQE,KAAK,CAACzB,GAAG,CAAC,CAAC2B,OAAAA,EAAS1B,sBAC3BU,GAACD,CAAAA,cAAAA,EAAAA;oBAA2BpC,IAAMqD,EAAAA;AAAb1B,iBAAAA,EAAAA,KAAAA,CAAAA,CAAAA;AAEtBkD,YAAAA,SAAAA,iBACCpB,IAACG,CAAAA,IAAAA,EAAAA;gBAAKK,GAAK,EAAA,CAAA;;kCACT5B,GAAC6C,CAAAA,UAAAA,EAAAA;wBACCC,KAAM,EAAA,QAAA;wBACNC,IAAK,EAAA,IAAA;wBACLC,OAAQ,EAAA,OAAA;wBACRC,OAAS,EAAA,IAAMR,aAAc7B,CAAAA,OAAAA,CAAQrB,EAAE,CAAA;AAEvC,wBAAA,QAAA,gBAAAS,GAACkD,CAAAA,OAAAA,EAAAA,EAAAA;;kCAEHlD,GAAC6C,CAAAA,UAAAA,EAAAA;wBACCC,KAAM,EAAA,UAAA;wBACNC,IAAK,EAAA,IAAA;wBACLC,OAAQ,EAAA,OAAA;;wBAERC,OAAS,EAAA,IAAMN,iBAAkB/B,CAAAA,OAAAA,CAAQrB,EAAE,CAAA;AAE3C,wBAAA,QAAA,gBAAAS,GAACmD,CAAAA,SAAAA,EAAAA,EAAAA;;;AAGH,aAAA,CAAA,GAAA;;;AAGV,CAAA;MAEaC,WAAc,GAAA,CAAC,EAC1BxC,OAAO,EACP4B,SAAS,EAIV,GAAA;AACC;;;;;AAKC,MACD,IAAI5B,OAAAA,CAAQyC,IAAI,KAAK,MAAQ,EAAA;AAC3B,QAAA,qBAAOrD,GAACW,CAAAA,WAAAA,EAAAA;YAAYC,OAASA,EAAAA;;AAC/B;AACA,IAAA,qBAAOZ,GAACuC,CAAAA,gBAAAA,EAAAA;QAAiB3B,OAASA,EAAAA;;AACpC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAIFetch.js","sources":["../../../../../admin/src/components/AIChat/hooks/useAIFetch.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-namespace */\n\n/**\n * In charge of fetching data from Strapi AI endpoints\n */\n\nimport { useState } from 'react';\n\nimport { UIMessage, useChat } from '@ai-sdk/react';\nimport { useAppInfo } from '@strapi/admin/strapi-admin';\nimport { useGetAIUsageQuery } from '@strapi/admin/strapi-admin/ee';\nimport { DefaultChatTransport } from 'ai';\n\nimport { fetchAI, makeChatFetch, safeParseJson } from '../lib/aiClient';\nimport { STRAPI_AI_CHAT_URL, STRAPI_AI_URL } from '../lib/constants';\nimport { Attachment } from '../lib/types/attachments';\nimport { Schema } from '../lib/types/schema';\n\n/* -------------------------------------------------------------------------------------------------\n * Types\n * -----------------------------------------------------------------------------------------------*/\n/**\n * Chat title\n */\nexport namespace GenerateTitle {\n export interface Request {\n body: {\n chatId: string;\n message: string;\n };\n }\n export interface Response {\n data: {\n title: string;\n };\n error?: string;\n }\n}\n\n/**\n * Upload a project to the chat\n */\nexport namespace UploadProject {\n export interface Request {\n body: {\n chatId: string;\n name: string;\n type: 'code';\n files: {\n path: string;\n content: string;\n }[];\n };\n }\n export interface Response {\n data: Attachment;\n error?: string;\n }\n}\n\n/**\n * Send chat feedback\n */\nexport type FeedbackReasonIds =\n | 'invalid_schema'\n | 'bad_recommendation'\n | 'slow'\n | 'instructions_ignored'\n | 'being_lazy'\n | 'other';\n\nnamespace SendFeedback {\n export interface Request {\n body: {\n chatId: string;\n type: 'upvote' | 'downvote';\n feedback?: string;\n reasons?: FeedbackReasonIds[];\n messageId: string;\n messages: UIMessage[];\n schemas: Schema[];\n };\n }\n}\n\n/**\n * Upload media\n */\nexport namespace UploadMedia {\n export interface Request {\n body: {\n url: string; // base64 image\n filename: string;\n chatId: string;\n };\n }\n export interface Response {\n data: Attachment;\n error?: string;\n }\n}\n\n/**\n * Collection of API endpoints and their corresponding request/response types\n */\ntype AIEndpoints = {\n '/schemas/chat/generate-title': {\n request: GenerateTitle.Request;\n response: GenerateTitle.Response;\n };\n '/schemas/chat/attachment': {\n request: UploadProject.Request;\n response: UploadProject.Response;\n };\n '/schemas/chat/feedback': {\n request: SendFeedback.Request;\n response: void;\n };\n '/media/upload': {\n request: UploadMedia.Request;\n response: UploadMedia.Response;\n };\n};\n\n// Helper type to extract the request type for a given endpoint\ntype RequestType<T extends keyof AIEndpoints> = AIEndpoints[T]['request'];\n\n// Helper type to extract the response type for a given endpoint\ntype ResponseType<T extends keyof AIEndpoints> = AIEndpoints[T]['response'];\n\n/* -------------------------------------------------------------------------------------------------\n * Hooks\n * -----------------------------------------------------------------------------------------------*/\n\nexport const TOO_MANY_REQUESTS_ERROR = 'Too many requests';\nexport const LICENSE_LIMIT_REACHED_ERROR = 'License limit';\nexport const LICENSE_LIMIT_EXCEEDED_ERROR = 'AI credit limit exceeded';\nexport const CHAT_TOO_LONG_ERROR = 'Chat too long';\nexport const ATTACHMENT_TOO_BIG_ERROR = 'Attachment too big';\nexport const ATTACHMENT_NOT_FOUND_ERROR = 'Attachment not found';\nexport const INVALID_REQUEST_ERROR = 'Invalid request';\n\n/**\n * Base hook factory for making type-safe API calls to Strapi AI endpoints.\n * Creates a hook specific to a single endpoint.\n */\nexport const createAIFetchHook = <T extends keyof AIEndpoints>(endpoint: T) => {\n return () => {\n const strapiVersion = useAppInfo('useAIFetch', (state) => state.strapiVersion);\n const projectId = useAppInfo('useAIFetch', (state) => state.projectId);\n const userId = useAppInfo('useAIFetch-user', (state) => state.userId);\n const aiUsage = useGetAIUsageQuery(undefined, { refetchOnMountOrArgChange: true });\n\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n /**\n * Make a type-safe API call to the specified Strapi AI endpoint with retry logic\n */\n const fetchData = async (\n options: Omit<RequestInit, 'body'> & Partial<RequestType<T>> & { formData?: FormData } = {}\n ): Promise<ResponseType<T> | null> => {\n setIsPending(true);\n setError(null);\n\n try {\n const fullUrl = `${STRAPI_AI_URL}${endpoint}`;\n const isJson = !!options.body && !options.formData;\n\n const response = await fetchAI(fullUrl, {\n method: 'POST',\n headers: isJson\n ? { 'Content-Type': 'application/json', ...(options.headers || {}) }\n : options.headers,\n body: options.formData\n ? options.formData\n : isJson\n ? JSON.stringify(options.body || {})\n : undefined,\n ctx: { strapiVersion, projectId, userId },\n });\n // refetch ai usage data on every successful request\n aiUsage.refetch();\n\n const body = await safeParseJson(response);\n\n if (!response.ok) {\n throw new Error(`Error: ${response.statusText}`);\n }\n return body as ResponseType<T>;\n } catch (err) {\n setError(err instanceof Error ? err.message : `Failed to fetch data from ${endpoint}`);\n return null;\n } finally {\n setIsPending(false);\n }\n };\n\n return {\n isPending,\n error,\n fetch: fetchData,\n };\n };\n};\n\n// Create specific hooks for each endpoint\nexport const useFetchGenerateTitle = createAIFetchHook('/schemas/chat/generate-title');\nexport const useFetchUploadProject = createAIFetchHook('/schemas/chat/attachment');\nexport const useFetchSendFeedback = createAIFetchHook('/schemas/chat/feedback');\nexport const useFetchUploadMedia = createAIFetchHook('/media/upload');\n\n/**\n * Hook wrapper for AI SDK's useChat with Strapi-specific configuration\n */\nexport const useAIChat: typeof useChat = (props) => {\n const strapiVersion = useAppInfo('useAIChat', (state) => state.strapiVersion);\n const projectId = useAppInfo('useAIFetch', (state) => state.projectId);\n const userId = useAppInfo('useAIChat-user', (state) => state.userId);\n\n const customFetch = makeChatFetch({ strapiVersion, projectId, userId });\n\n return useChat({\n ...props,\n transport: new DefaultChatTransport({\n api: STRAPI_AI_CHAT_URL,\n fetch: customFetch,\n }),\n });\n};\n"],"names":["TOO_MANY_REQUESTS_ERROR","LICENSE_LIMIT_REACHED_ERROR","LICENSE_LIMIT_EXCEEDED_ERROR","CHAT_TOO_LONG_ERROR","createAIFetchHook","endpoint","strapiVersion","useAppInfo","state","projectId","userId","aiUsage","useGetAIUsageQuery","undefined","refetchOnMountOrArgChange","isPending","setIsPending","useState","error","setError","fetchData","options","fullUrl","STRAPI_AI_URL","isJson","body","formData","response","fetchAI","method","headers","JSON","stringify","ctx","refetch","safeParseJson","ok","Error","statusText","err","message","fetch","useFetchGenerateTitle","useFetchUploadProject","useFetchSendFeedback","useFetchUploadMedia","useAIChat","props","customFetch","makeChatFetch","useChat","transport","DefaultChatTransport","api","STRAPI_AI_CHAT_URL"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useAIFetch.js","sources":["../../../../../admin/src/components/AIChat/hooks/useAIFetch.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-namespace */\n\n/**\n * In charge of fetching data from Strapi AI endpoints\n */\n\nimport { useState } from 'react';\n\nimport { UIMessage, useChat } from '@ai-sdk/react';\nimport { useAppInfo } from '@strapi/admin/strapi-admin';\nimport { useGetAIUsageQuery } from '@strapi/admin/strapi-admin/ee';\nimport { DefaultChatTransport } from 'ai';\n\nimport { fetchAI, makeChatFetch, safeParseJson } from '../lib/aiClient';\nimport { STRAPI_AI_CHAT_URL, STRAPI_AI_URL } from '../lib/constants';\nimport { Attachment } from '../lib/types/attachments';\nimport { Schema } from '../lib/types/schema';\n\n/* -------------------------------------------------------------------------------------------------\n * Types\n * -----------------------------------------------------------------------------------------------*/\n/**\n * Chat title\n */\nexport namespace GenerateTitle {\n export interface Request {\n body: {\n chatId: string;\n message: string;\n };\n }\n export interface Response {\n data: {\n title: string;\n };\n error?: string;\n }\n}\n\n/**\n * Upload a project to the chat\n */\nexport namespace UploadProject {\n export interface Request {\n body: {\n chatId: string;\n name: string;\n type: 'code';\n files: {\n path: string;\n content: string;\n }[];\n };\n }\n export interface Response {\n data: Attachment;\n error?: string;\n }\n}\n\n/**\n * Send chat feedback\n */\nexport type FeedbackReasonIds =\n | 'invalid_schema'\n | 'bad_recommendation'\n | 'slow'\n | 'instructions_ignored'\n | 'being_lazy'\n | 'other';\n\nnamespace SendFeedback {\n export interface Request {\n body: {\n chatId: string;\n type: 'upvote' | 'downvote';\n feedback?: string;\n reasons?: FeedbackReasonIds[];\n messageId: string;\n messages: UIMessage[];\n schemas: Schema[];\n };\n }\n}\n\n/**\n * Upload media\n */\nexport namespace UploadMedia {\n export interface Request {\n body: {\n url: string; // base64 image\n filename: string;\n chatId: string;\n };\n }\n export interface Response {\n data: Attachment;\n error?: string;\n }\n}\n\n/**\n * Collection of API endpoints and their corresponding request/response types\n */\ntype AIEndpoints = {\n '/schemas/chat/generate-title': {\n request: GenerateTitle.Request;\n response: GenerateTitle.Response;\n };\n '/schemas/chat/attachment': {\n request: UploadProject.Request;\n response: UploadProject.Response;\n };\n '/schemas/chat/feedback': {\n request: SendFeedback.Request;\n response: void;\n };\n '/media/upload': {\n request: UploadMedia.Request;\n response: UploadMedia.Response;\n };\n};\n\n// Helper type to extract the request type for a given endpoint\ntype RequestType<T extends keyof AIEndpoints> = AIEndpoints[T]['request'];\n\n// Helper type to extract the response type for a given endpoint\ntype ResponseType<T extends keyof AIEndpoints> = AIEndpoints[T]['response'];\n\n/* -------------------------------------------------------------------------------------------------\n * Hooks\n * -----------------------------------------------------------------------------------------------*/\n\nexport const TOO_MANY_REQUESTS_ERROR = 'Too many requests';\nexport const LICENSE_LIMIT_REACHED_ERROR = 'License limit';\nexport const LICENSE_LIMIT_EXCEEDED_ERROR = 'AI credit limit exceeded';\nexport const CHAT_TOO_LONG_ERROR = 'Chat too long';\nexport const ATTACHMENT_TOO_BIG_ERROR = 'Attachment too big';\nexport const ATTACHMENT_NOT_FOUND_ERROR = 'Attachment not found';\nexport const INVALID_REQUEST_ERROR = 'Invalid request';\n\n/**\n * Base hook factory for making type-safe API calls to Strapi AI endpoints.\n * Creates a hook specific to a single endpoint.\n */\nexport const createAIFetchHook = <T extends keyof AIEndpoints>(endpoint: T) => {\n return () => {\n const strapiVersion = useAppInfo('useAIFetch', (state) => state.strapiVersion);\n const projectId = useAppInfo('useAIFetch', (state) => state.projectId);\n const userId = useAppInfo('useAIFetch-user', (state) => state.userId);\n const aiUsage = useGetAIUsageQuery(undefined, { refetchOnMountOrArgChange: true });\n\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n /**\n * Make a type-safe API call to the specified Strapi AI endpoint with retry logic\n */\n const fetchData = async (\n options: Omit<RequestInit, 'body'> & Partial<RequestType<T>> & { formData?: FormData } = {}\n ): Promise<ResponseType<T> | null> => {\n setIsPending(true);\n setError(null);\n\n try {\n const fullUrl = `${STRAPI_AI_URL}${endpoint}`;\n const isJson = !!options.body && !options.formData;\n\n const response = await fetchAI(fullUrl, {\n method: 'POST',\n headers: isJson\n ? { 'Content-Type': 'application/json', ...(options.headers || {}) }\n : options.headers,\n body: options.formData\n ? options.formData\n : isJson\n ? JSON.stringify(options.body || {})\n : undefined,\n ctx: { strapiVersion, projectId, userId },\n });\n // refetch ai usage data on every successful request\n aiUsage.refetch();\n\n const body = await safeParseJson(response);\n\n if (!response.ok) {\n throw new Error(`Error: ${response.statusText}`);\n }\n return body as ResponseType<T>;\n } catch (err) {\n setError(err instanceof Error ? err.message : `Failed to fetch data from ${endpoint}`);\n return null;\n } finally {\n setIsPending(false);\n }\n };\n\n return {\n isPending,\n error,\n fetch: fetchData,\n };\n };\n};\n\n// Create specific hooks for each endpoint\nexport const useFetchGenerateTitle = createAIFetchHook('/schemas/chat/generate-title');\nexport const useFetchUploadProject = createAIFetchHook('/schemas/chat/attachment');\nexport const useFetchSendFeedback = createAIFetchHook('/schemas/chat/feedback');\nexport const useFetchUploadMedia = createAIFetchHook('/media/upload');\n\n/**\n * Hook wrapper for AI SDK's useChat with Strapi-specific configuration\n */\nexport const useAIChat: typeof useChat = (props) => {\n const strapiVersion = useAppInfo('useAIChat', (state) => state.strapiVersion);\n const projectId = useAppInfo('useAIFetch', (state) => state.projectId);\n const userId = useAppInfo('useAIChat-user', (state) => state.userId);\n\n const customFetch = makeChatFetch({ strapiVersion, projectId, userId });\n\n return useChat({\n ...props,\n transport: new DefaultChatTransport({\n api: STRAPI_AI_CHAT_URL,\n fetch: customFetch,\n }),\n });\n};\n"],"names":["TOO_MANY_REQUESTS_ERROR","LICENSE_LIMIT_REACHED_ERROR","LICENSE_LIMIT_EXCEEDED_ERROR","CHAT_TOO_LONG_ERROR","createAIFetchHook","endpoint","strapiVersion","useAppInfo","state","projectId","userId","aiUsage","useGetAIUsageQuery","undefined","refetchOnMountOrArgChange","isPending","setIsPending","useState","error","setError","fetchData","options","fullUrl","STRAPI_AI_URL","isJson","body","formData","response","fetchAI","method","headers","JSON","stringify","ctx","refetch","safeParseJson","ok","Error","statusText","err","message","fetch","useFetchGenerateTitle","useFetchUploadProject","useFetchSendFeedback","useFetchUploadMedia","useAIChat","props","customFetch","makeChatFetch","useChat","transport","DefaultChatTransport","api","STRAPI_AI_CHAT_URL"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAIFetch.mjs","sources":["../../../../../admin/src/components/AIChat/hooks/useAIFetch.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-namespace */\n\n/**\n * In charge of fetching data from Strapi AI endpoints\n */\n\nimport { useState } from 'react';\n\nimport { UIMessage, useChat } from '@ai-sdk/react';\nimport { useAppInfo } from '@strapi/admin/strapi-admin';\nimport { useGetAIUsageQuery } from '@strapi/admin/strapi-admin/ee';\nimport { DefaultChatTransport } from 'ai';\n\nimport { fetchAI, makeChatFetch, safeParseJson } from '../lib/aiClient';\nimport { STRAPI_AI_CHAT_URL, STRAPI_AI_URL } from '../lib/constants';\nimport { Attachment } from '../lib/types/attachments';\nimport { Schema } from '../lib/types/schema';\n\n/* -------------------------------------------------------------------------------------------------\n * Types\n * -----------------------------------------------------------------------------------------------*/\n/**\n * Chat title\n */\nexport namespace GenerateTitle {\n export interface Request {\n body: {\n chatId: string;\n message: string;\n };\n }\n export interface Response {\n data: {\n title: string;\n };\n error?: string;\n }\n}\n\n/**\n * Upload a project to the chat\n */\nexport namespace UploadProject {\n export interface Request {\n body: {\n chatId: string;\n name: string;\n type: 'code';\n files: {\n path: string;\n content: string;\n }[];\n };\n }\n export interface Response {\n data: Attachment;\n error?: string;\n }\n}\n\n/**\n * Send chat feedback\n */\nexport type FeedbackReasonIds =\n | 'invalid_schema'\n | 'bad_recommendation'\n | 'slow'\n | 'instructions_ignored'\n | 'being_lazy'\n | 'other';\n\nnamespace SendFeedback {\n export interface Request {\n body: {\n chatId: string;\n type: 'upvote' | 'downvote';\n feedback?: string;\n reasons?: FeedbackReasonIds[];\n messageId: string;\n messages: UIMessage[];\n schemas: Schema[];\n };\n }\n}\n\n/**\n * Upload media\n */\nexport namespace UploadMedia {\n export interface Request {\n body: {\n url: string; // base64 image\n filename: string;\n chatId: string;\n };\n }\n export interface Response {\n data: Attachment;\n error?: string;\n }\n}\n\n/**\n * Collection of API endpoints and their corresponding request/response types\n */\ntype AIEndpoints = {\n '/schemas/chat/generate-title': {\n request: GenerateTitle.Request;\n response: GenerateTitle.Response;\n };\n '/schemas/chat/attachment': {\n request: UploadProject.Request;\n response: UploadProject.Response;\n };\n '/schemas/chat/feedback': {\n request: SendFeedback.Request;\n response: void;\n };\n '/media/upload': {\n request: UploadMedia.Request;\n response: UploadMedia.Response;\n };\n};\n\n// Helper type to extract the request type for a given endpoint\ntype RequestType<T extends keyof AIEndpoints> = AIEndpoints[T]['request'];\n\n// Helper type to extract the response type for a given endpoint\ntype ResponseType<T extends keyof AIEndpoints> = AIEndpoints[T]['response'];\n\n/* -------------------------------------------------------------------------------------------------\n * Hooks\n * -----------------------------------------------------------------------------------------------*/\n\nexport const TOO_MANY_REQUESTS_ERROR = 'Too many requests';\nexport const LICENSE_LIMIT_REACHED_ERROR = 'License limit';\nexport const LICENSE_LIMIT_EXCEEDED_ERROR = 'AI credit limit exceeded';\nexport const CHAT_TOO_LONG_ERROR = 'Chat too long';\nexport const ATTACHMENT_TOO_BIG_ERROR = 'Attachment too big';\nexport const ATTACHMENT_NOT_FOUND_ERROR = 'Attachment not found';\nexport const INVALID_REQUEST_ERROR = 'Invalid request';\n\n/**\n * Base hook factory for making type-safe API calls to Strapi AI endpoints.\n * Creates a hook specific to a single endpoint.\n */\nexport const createAIFetchHook = <T extends keyof AIEndpoints>(endpoint: T) => {\n return () => {\n const strapiVersion = useAppInfo('useAIFetch', (state) => state.strapiVersion);\n const projectId = useAppInfo('useAIFetch', (state) => state.projectId);\n const userId = useAppInfo('useAIFetch-user', (state) => state.userId);\n const aiUsage = useGetAIUsageQuery(undefined, { refetchOnMountOrArgChange: true });\n\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n /**\n * Make a type-safe API call to the specified Strapi AI endpoint with retry logic\n */\n const fetchData = async (\n options: Omit<RequestInit, 'body'> & Partial<RequestType<T>> & { formData?: FormData } = {}\n ): Promise<ResponseType<T> | null> => {\n setIsPending(true);\n setError(null);\n\n try {\n const fullUrl = `${STRAPI_AI_URL}${endpoint}`;\n const isJson = !!options.body && !options.formData;\n\n const response = await fetchAI(fullUrl, {\n method: 'POST',\n headers: isJson\n ? { 'Content-Type': 'application/json', ...(options.headers || {}) }\n : options.headers,\n body: options.formData\n ? options.formData\n : isJson\n ? JSON.stringify(options.body || {})\n : undefined,\n ctx: { strapiVersion, projectId, userId },\n });\n // refetch ai usage data on every successful request\n aiUsage.refetch();\n\n const body = await safeParseJson(response);\n\n if (!response.ok) {\n throw new Error(`Error: ${response.statusText}`);\n }\n return body as ResponseType<T>;\n } catch (err) {\n setError(err instanceof Error ? err.message : `Failed to fetch data from ${endpoint}`);\n return null;\n } finally {\n setIsPending(false);\n }\n };\n\n return {\n isPending,\n error,\n fetch: fetchData,\n };\n };\n};\n\n// Create specific hooks for each endpoint\nexport const useFetchGenerateTitle = createAIFetchHook('/schemas/chat/generate-title');\nexport const useFetchUploadProject = createAIFetchHook('/schemas/chat/attachment');\nexport const useFetchSendFeedback = createAIFetchHook('/schemas/chat/feedback');\nexport const useFetchUploadMedia = createAIFetchHook('/media/upload');\n\n/**\n * Hook wrapper for AI SDK's useChat with Strapi-specific configuration\n */\nexport const useAIChat: typeof useChat = (props) => {\n const strapiVersion = useAppInfo('useAIChat', (state) => state.strapiVersion);\n const projectId = useAppInfo('useAIFetch', (state) => state.projectId);\n const userId = useAppInfo('useAIChat-user', (state) => state.userId);\n\n const customFetch = makeChatFetch({ strapiVersion, projectId, userId });\n\n return useChat({\n ...props,\n transport: new DefaultChatTransport({\n api: STRAPI_AI_CHAT_URL,\n fetch: customFetch,\n }),\n });\n};\n"],"names":["TOO_MANY_REQUESTS_ERROR","LICENSE_LIMIT_REACHED_ERROR","LICENSE_LIMIT_EXCEEDED_ERROR","CHAT_TOO_LONG_ERROR","createAIFetchHook","endpoint","strapiVersion","useAppInfo","state","projectId","userId","aiUsage","useGetAIUsageQuery","undefined","refetchOnMountOrArgChange","isPending","setIsPending","useState","error","setError","fetchData","options","fullUrl","STRAPI_AI_URL","isJson","body","formData","response","fetchAI","method","headers","JSON","stringify","ctx","refetch","safeParseJson","ok","Error","statusText","err","message","fetch","useFetchGenerateTitle","useFetchUploadProject","useFetchSendFeedback","useFetchUploadMedia","useAIChat","props","customFetch","makeChatFetch","useChat","transport","DefaultChatTransport","api","STRAPI_AI_CHAT_URL"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useAIFetch.mjs","sources":["../../../../../admin/src/components/AIChat/hooks/useAIFetch.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-namespace */\n\n/**\n * In charge of fetching data from Strapi AI endpoints\n */\n\nimport { useState } from 'react';\n\nimport { UIMessage, useChat } from '@ai-sdk/react';\nimport { useAppInfo } from '@strapi/admin/strapi-admin';\nimport { useGetAIUsageQuery } from '@strapi/admin/strapi-admin/ee';\nimport { DefaultChatTransport } from 'ai';\n\nimport { fetchAI, makeChatFetch, safeParseJson } from '../lib/aiClient';\nimport { STRAPI_AI_CHAT_URL, STRAPI_AI_URL } from '../lib/constants';\nimport { Attachment } from '../lib/types/attachments';\nimport { Schema } from '../lib/types/schema';\n\n/* -------------------------------------------------------------------------------------------------\n * Types\n * -----------------------------------------------------------------------------------------------*/\n/**\n * Chat title\n */\nexport namespace GenerateTitle {\n export interface Request {\n body: {\n chatId: string;\n message: string;\n };\n }\n export interface Response {\n data: {\n title: string;\n };\n error?: string;\n }\n}\n\n/**\n * Upload a project to the chat\n */\nexport namespace UploadProject {\n export interface Request {\n body: {\n chatId: string;\n name: string;\n type: 'code';\n files: {\n path: string;\n content: string;\n }[];\n };\n }\n export interface Response {\n data: Attachment;\n error?: string;\n }\n}\n\n/**\n * Send chat feedback\n */\nexport type FeedbackReasonIds =\n | 'invalid_schema'\n | 'bad_recommendation'\n | 'slow'\n | 'instructions_ignored'\n | 'being_lazy'\n | 'other';\n\nnamespace SendFeedback {\n export interface Request {\n body: {\n chatId: string;\n type: 'upvote' | 'downvote';\n feedback?: string;\n reasons?: FeedbackReasonIds[];\n messageId: string;\n messages: UIMessage[];\n schemas: Schema[];\n };\n }\n}\n\n/**\n * Upload media\n */\nexport namespace UploadMedia {\n export interface Request {\n body: {\n url: string; // base64 image\n filename: string;\n chatId: string;\n };\n }\n export interface Response {\n data: Attachment;\n error?: string;\n }\n}\n\n/**\n * Collection of API endpoints and their corresponding request/response types\n */\ntype AIEndpoints = {\n '/schemas/chat/generate-title': {\n request: GenerateTitle.Request;\n response: GenerateTitle.Response;\n };\n '/schemas/chat/attachment': {\n request: UploadProject.Request;\n response: UploadProject.Response;\n };\n '/schemas/chat/feedback': {\n request: SendFeedback.Request;\n response: void;\n };\n '/media/upload': {\n request: UploadMedia.Request;\n response: UploadMedia.Response;\n };\n};\n\n// Helper type to extract the request type for a given endpoint\ntype RequestType<T extends keyof AIEndpoints> = AIEndpoints[T]['request'];\n\n// Helper type to extract the response type for a given endpoint\ntype ResponseType<T extends keyof AIEndpoints> = AIEndpoints[T]['response'];\n\n/* -------------------------------------------------------------------------------------------------\n * Hooks\n * -----------------------------------------------------------------------------------------------*/\n\nexport const TOO_MANY_REQUESTS_ERROR = 'Too many requests';\nexport const LICENSE_LIMIT_REACHED_ERROR = 'License limit';\nexport const LICENSE_LIMIT_EXCEEDED_ERROR = 'AI credit limit exceeded';\nexport const CHAT_TOO_LONG_ERROR = 'Chat too long';\nexport const ATTACHMENT_TOO_BIG_ERROR = 'Attachment too big';\nexport const ATTACHMENT_NOT_FOUND_ERROR = 'Attachment not found';\nexport const INVALID_REQUEST_ERROR = 'Invalid request';\n\n/**\n * Base hook factory for making type-safe API calls to Strapi AI endpoints.\n * Creates a hook specific to a single endpoint.\n */\nexport const createAIFetchHook = <T extends keyof AIEndpoints>(endpoint: T) => {\n return () => {\n const strapiVersion = useAppInfo('useAIFetch', (state) => state.strapiVersion);\n const projectId = useAppInfo('useAIFetch', (state) => state.projectId);\n const userId = useAppInfo('useAIFetch-user', (state) => state.userId);\n const aiUsage = useGetAIUsageQuery(undefined, { refetchOnMountOrArgChange: true });\n\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n /**\n * Make a type-safe API call to the specified Strapi AI endpoint with retry logic\n */\n const fetchData = async (\n options: Omit<RequestInit, 'body'> & Partial<RequestType<T>> & { formData?: FormData } = {}\n ): Promise<ResponseType<T> | null> => {\n setIsPending(true);\n setError(null);\n\n try {\n const fullUrl = `${STRAPI_AI_URL}${endpoint}`;\n const isJson = !!options.body && !options.formData;\n\n const response = await fetchAI(fullUrl, {\n method: 'POST',\n headers: isJson\n ? { 'Content-Type': 'application/json', ...(options.headers || {}) }\n : options.headers,\n body: options.formData\n ? options.formData\n : isJson\n ? JSON.stringify(options.body || {})\n : undefined,\n ctx: { strapiVersion, projectId, userId },\n });\n // refetch ai usage data on every successful request\n aiUsage.refetch();\n\n const body = await safeParseJson(response);\n\n if (!response.ok) {\n throw new Error(`Error: ${response.statusText}`);\n }\n return body as ResponseType<T>;\n } catch (err) {\n setError(err instanceof Error ? err.message : `Failed to fetch data from ${endpoint}`);\n return null;\n } finally {\n setIsPending(false);\n }\n };\n\n return {\n isPending,\n error,\n fetch: fetchData,\n };\n };\n};\n\n// Create specific hooks for each endpoint\nexport const useFetchGenerateTitle = createAIFetchHook('/schemas/chat/generate-title');\nexport const useFetchUploadProject = createAIFetchHook('/schemas/chat/attachment');\nexport const useFetchSendFeedback = createAIFetchHook('/schemas/chat/feedback');\nexport const useFetchUploadMedia = createAIFetchHook('/media/upload');\n\n/**\n * Hook wrapper for AI SDK's useChat with Strapi-specific configuration\n */\nexport const useAIChat: typeof useChat = (props) => {\n const strapiVersion = useAppInfo('useAIChat', (state) => state.strapiVersion);\n const projectId = useAppInfo('useAIFetch', (state) => state.projectId);\n const userId = useAppInfo('useAIChat-user', (state) => state.userId);\n\n const customFetch = makeChatFetch({ strapiVersion, projectId, userId });\n\n return useChat({\n ...props,\n transport: new DefaultChatTransport({\n api: STRAPI_AI_CHAT_URL,\n fetch: customFetch,\n }),\n });\n};\n"],"names":["TOO_MANY_REQUESTS_ERROR","LICENSE_LIMIT_REACHED_ERROR","LICENSE_LIMIT_EXCEEDED_ERROR","CHAT_TOO_LONG_ERROR","createAIFetchHook","endpoint","strapiVersion","useAppInfo","state","projectId","userId","aiUsage","useGetAIUsageQuery","undefined","refetchOnMountOrArgChange","isPending","setIsPending","useState","error","setError","fetchData","options","fullUrl","STRAPI_AI_URL","isJson","body","formData","response","fetchAI","method","headers","JSON","stringify","ctx","refetch","safeParseJson","ok","Error","statusText","err","message","fetch","useFetchGenerateTitle","useFetchUploadProject","useFetchSendFeedback","useFetchUploadMedia","useAIChat","props","customFetch","makeChatFetch","useChat","transport","DefaultChatTransport","api","STRAPI_AI_CHAT_URL"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCodeUpload.js","sources":["../../../../../admin/src/components/AIChat/hooks/useCodeUpload.ts"],"sourcesContent":["import { useState } from 'react';\n\nimport JSZip from 'jszip';\nimport micromatch from 'micromatch';\n\nimport { generateId } from '../lib/misc';\nimport { Attachment } from '../lib/types/attachments';\nimport { useStrapiChat } from '../providers/ChatProvider';\n\nimport { useFetchUploadProject } from './useAIFetch';\n\nexport interface ProjectFile {\n path: string;\n content: string;\n}\n\nconst ALLOWED_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.md', '.json'];\nconst MAX_LINES_PER_FILE = 5000; // Maximum number of lines per file\n\n// Common patterns to ignore\nconst DEFAULT_IGNORE_PATTERNS = [\n '**/node_modules/**',\n '**/.git/**',\n '**/.next/**',\n '**/dist/**',\n '**/build/**',\n '**/.cache/**',\n '**/coverage/**',\n '**/test/**',\n '**/__tests__/**',\n '**/*.test.*',\n '**/*.spec.*',\n];\n\nconst isAllowedFile = (filename: string, ignorePatterns: string[] = []) => {\n // Check if file matches any ignore pattern\n if (micromatch.isMatch(filename, [...DEFAULT_IGNORE_PATTERNS, ...ignorePatterns])) {\n return false;\n }\n\n // Check if file has allowed extension\n return ALLOWED_EXTENSIONS.some((ext) => filename.toLowerCase().endsWith(ext));\n};\n\n/**\n * Prunes file content if it exceeds MAX_LINES\n */\nconst pruneFileContent = (content: string): string => {\n const lines = content.split('\\n');\n\n if (lines.length <= MAX_LINES_PER_FILE) {\n return content;\n }\n\n const truncated = lines.slice(0, MAX_LINES_PER_FILE).join('\\n');\n\n return `${truncated}\\n\\n// ... [${lines.length - MAX_LINES_PER_FILE} lines truncated, file too long] ...\\n\\n`;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * File processing options\n * -----------------------------------------------------------------------------------------------*/\nexport interface ProcessOptions {\n /**\n * Additional glob patterns to ignore\n */\n ignorePatterns?: string[];\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Zip file processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function openZipFile(\n file: File,\n options: ProcessOptions = {}\n): Promise<ProjectFile[]> {\n const zip = new JSZip();\n const contents = await zip.loadAsync(file);\n const processedFiles: ProjectFile[] = [];\n\n // Process all files in parallel\n await Promise.all(\n Object.keys(contents.files).map(async (filename) => {\n const zipEntry = contents.files[filename];\n\n // Skip directories and non-allowed files\n if (zipEntry.dir || !isAllowedFile(filename, options.ignorePatterns)) {\n return;\n }\n\n try {\n const content = await zipEntry.async('string');\n processedFiles.push({\n path: filename,\n content: pruneFileContent(content),\n });\n } catch (err) {\n console.warn(`Failed to read file ${filename}:`, err);\n }\n })\n );\n\n // Sort files by path for consistency\n return processedFiles.sort((a, b) => a.path.localeCompare(b.path));\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Folder processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function processFolder(\n files: FileList | File[],\n options: ProcessOptions = {}\n): Promise<{ files: ProjectFile[]; projectName: string }> {\n const processedFiles: ProjectFile[] = [];\n let folderName = 'Project';\n\n // Extract folder name from the first file's path\n if (files.length > 0) {\n const firstFile = files[0];\n const folderPath = firstFile.webkitRelativePath || '';\n const pathParts = folderPath.split('/');\n if (pathParts.length > 0 && pathParts[0]) {\n folderName = pathParts[0];\n }\n }\n\n // Process all files in parallel\n await Promise.all(\n Array.from(files).map(async (file) => {\n const filePath = file.webkitRelativePath || file.name;\n\n // Skip non-allowed files\n if (!isAllowedFile(filePath, options.ignorePatterns)) {\n return;\n }\n\n try {\n const content = await file.text();\n processedFiles.push({\n // Remove the root folder name from the path\n path: filePath.includes('/') ? filePath.substring(filePath.indexOf('/') + 1) : filePath,\n content: pruneFileContent(content),\n });\n } catch (err) {\n console.warn(`Failed to read file ${filePath}:`, err);\n }\n })\n );\n\n // Sort files by path for consistency\n return {\n files: processedFiles.sort((a, b) => a.path.localeCompare(b.path)),\n projectName: folderName,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Zip file processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function processZipFile(\n file: File,\n options: ProcessOptions = {}\n): Promise<{ files: ProjectFile[]; projectName: string }> {\n const projectName = file.name.replace('.zip', '');\n const files = await openZipFile(file, options);\n\n return {\n files,\n projectName,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Upload files\n * -----------------------------------------------------------------------------------------------*/\n\ninterface UseCodeUploadOptions {\n onSuccess?: (attachment: Attachment, projectName: string) => void;\n onError?: (error: string) => void;\n}\n\nexport function useCodeUpload({ onSuccess, onError }: UseCodeUploadOptions = {}) {\n const [error, setError] = useState<string | null>(null);\n const [isProcessing, setIsProcessing] = useState(false);\n const {\n fetch: fetchUploadProject,\n isPending: isFetching,\n error: fetchError,\n } = useFetchUploadProject();\n const { id: chatId } = useStrapiChat();\n\n /**\n * Upload processed files to the server\n */\n const processFiles = async (projectName: string, processedFiles: ProjectFile[]) => {\n // Upload to server\n const result = await fetchUploadProject({\n body: {\n chatId,\n name: projectName,\n type: 'code',\n files: processedFiles,\n },\n });\n\n if (!result?.data) {\n throw new Error('Failed to upload project');\n }\n\n return result.data;\n };\n\n const handleZipFile = async (file: File) => {\n try {\n setError(null);\n setIsProcessing(true);\n\n const { files: processedFiles, projectName } = await processZipFile(file, {\n ignorePatterns: ['**/node_modules/**'],\n });\n\n const projectAttachment = await processFiles(projectName, processedFiles);\n\n onSuccess?.({ ...projectAttachment, id: generateId(), status: 'ready' }, projectName);\n return projectAttachment;\n } catch (err) {\n setError('Failed to process zip file');\n onError?.('Failed to process zip file');\n console.error('Error processing zip:', err);\n throw err;\n } finally {\n setIsProcessing(false);\n }\n };\n\n const handleFolder = async (files: FileList | File[]) => {\n try {\n setError(null);\n setIsProcessing(true);\n\n const { files: processedFiles, projectName } = await processFolder(files, {\n ignorePatterns: ['**/node_modules/**'],\n });\n\n const projectAttachment = await processFiles(projectName, processedFiles);\n\n onSuccess?.({ ...projectAttachment, id: generateId(), status: 'ready' }, projectName);\n return projectAttachment;\n } catch (err) {\n setError('Failed to process folder');\n onError?.('Failed to process folder');\n console.error('Error processing folder:', err);\n throw err;\n } finally {\n setIsProcessing(false);\n }\n };\n\n return {\n processZipFile: handleZipFile,\n processFolder: handleFolder,\n isLoading: isProcessing || isFetching,\n error: fetchError || error,\n };\n}\n"],"names":["ALLOWED_EXTENSIONS","MAX_LINES_PER_FILE","DEFAULT_IGNORE_PATTERNS","isAllowedFile","filename","ignorePatterns","micromatch","isMatch","some","ext","toLowerCase","endsWith","pruneFileContent","content","lines","split","length","truncated","slice","join","openZipFile","file","options","zip","JSZip","contents","loadAsync","processedFiles","Promise","all","Object","keys","files","map","zipEntry","dir","async","push","path","err","console","warn","sort","a","b","localeCompare","processFolder","folderName","firstFile","folderPath","webkitRelativePath","pathParts","Array","from","filePath","name","text","includes","substring","indexOf","projectName","processZipFile","replace","useCodeUpload","onSuccess","onError","error","setError","useState","isProcessing","setIsProcessing","fetch","fetchUploadProject","isPending","isFetching","fetchError","useFetchUploadProject","id","chatId","useStrapiChat","processFiles","result","body","type","data","Error","handleZipFile","projectAttachment","generateId","status","handleFolder","isLoading"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useCodeUpload.js","sources":["../../../../../admin/src/components/AIChat/hooks/useCodeUpload.ts"],"sourcesContent":["import { useState } from 'react';\n\nimport JSZip from 'jszip';\nimport micromatch from 'micromatch';\n\nimport { generateId } from '../lib/misc';\nimport { Attachment } from '../lib/types/attachments';\nimport { useStrapiChat } from '../providers/ChatProvider';\n\nimport { useFetchUploadProject } from './useAIFetch';\n\nexport interface ProjectFile {\n path: string;\n content: string;\n}\n\nconst ALLOWED_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.md', '.json'];\nconst MAX_LINES_PER_FILE = 5000; // Maximum number of lines per file\n\n// Common patterns to ignore\nconst DEFAULT_IGNORE_PATTERNS = [\n '**/node_modules/**',\n '**/.git/**',\n '**/.next/**',\n '**/dist/**',\n '**/build/**',\n '**/.cache/**',\n '**/coverage/**',\n '**/test/**',\n '**/__tests__/**',\n '**/*.test.*',\n '**/*.spec.*',\n];\n\nconst isAllowedFile = (filename: string, ignorePatterns: string[] = []) => {\n // Check if file matches any ignore pattern\n if (micromatch.isMatch(filename, [...DEFAULT_IGNORE_PATTERNS, ...ignorePatterns])) {\n return false;\n }\n\n // Check if file has allowed extension\n return ALLOWED_EXTENSIONS.some((ext) => filename.toLowerCase().endsWith(ext));\n};\n\n/**\n * Prunes file content if it exceeds MAX_LINES\n */\nconst pruneFileContent = (content: string): string => {\n const lines = content.split('\\n');\n\n if (lines.length <= MAX_LINES_PER_FILE) {\n return content;\n }\n\n const truncated = lines.slice(0, MAX_LINES_PER_FILE).join('\\n');\n\n return `${truncated}\\n\\n// ... [${lines.length - MAX_LINES_PER_FILE} lines truncated, file too long] ...\\n\\n`;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * File processing options\n * -----------------------------------------------------------------------------------------------*/\nexport interface ProcessOptions {\n /**\n * Additional glob patterns to ignore\n */\n ignorePatterns?: string[];\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Zip file processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function openZipFile(\n file: File,\n options: ProcessOptions = {}\n): Promise<ProjectFile[]> {\n const zip = new JSZip();\n const contents = await zip.loadAsync(file);\n const processedFiles: ProjectFile[] = [];\n\n // Process all files in parallel\n await Promise.all(\n Object.keys(contents.files).map(async (filename) => {\n const zipEntry = contents.files[filename];\n\n // Skip directories and non-allowed files\n if (zipEntry.dir || !isAllowedFile(filename, options.ignorePatterns)) {\n return;\n }\n\n try {\n const content = await zipEntry.async('string');\n processedFiles.push({\n path: filename,\n content: pruneFileContent(content),\n });\n } catch (err) {\n console.warn(`Failed to read file ${filename}:`, err);\n }\n })\n );\n\n // Sort files by path for consistency\n return processedFiles.sort((a, b) => a.path.localeCompare(b.path));\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Folder processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function processFolder(\n files: FileList | File[],\n options: ProcessOptions = {}\n): Promise<{ files: ProjectFile[]; projectName: string }> {\n const processedFiles: ProjectFile[] = [];\n let folderName = 'Project';\n\n // Extract folder name from the first file's path\n if (files.length > 0) {\n const firstFile = files[0];\n const folderPath = firstFile.webkitRelativePath || '';\n const pathParts = folderPath.split('/');\n if (pathParts.length > 0 && pathParts[0]) {\n folderName = pathParts[0];\n }\n }\n\n // Process all files in parallel\n await Promise.all(\n Array.from(files).map(async (file) => {\n const filePath = file.webkitRelativePath || file.name;\n\n // Skip non-allowed files\n if (!isAllowedFile(filePath, options.ignorePatterns)) {\n return;\n }\n\n try {\n const content = await file.text();\n processedFiles.push({\n // Remove the root folder name from the path\n path: filePath.includes('/') ? filePath.substring(filePath.indexOf('/') + 1) : filePath,\n content: pruneFileContent(content),\n });\n } catch (err) {\n console.warn(`Failed to read file ${filePath}:`, err);\n }\n })\n );\n\n // Sort files by path for consistency\n return {\n files: processedFiles.sort((a, b) => a.path.localeCompare(b.path)),\n projectName: folderName,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Zip file processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function processZipFile(\n file: File,\n options: ProcessOptions = {}\n): Promise<{ files: ProjectFile[]; projectName: string }> {\n const projectName = file.name.replace('.zip', '');\n const files = await openZipFile(file, options);\n\n return {\n files,\n projectName,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Upload files\n * -----------------------------------------------------------------------------------------------*/\n\ninterface UseCodeUploadOptions {\n onSuccess?: (attachment: Attachment, projectName: string) => void;\n onError?: (error: string) => void;\n}\n\nexport function useCodeUpload({ onSuccess, onError }: UseCodeUploadOptions = {}) {\n const [error, setError] = useState<string | null>(null);\n const [isProcessing, setIsProcessing] = useState(false);\n const {\n fetch: fetchUploadProject,\n isPending: isFetching,\n error: fetchError,\n } = useFetchUploadProject();\n const { id: chatId } = useStrapiChat();\n\n /**\n * Upload processed files to the server\n */\n const processFiles = async (projectName: string, processedFiles: ProjectFile[]) => {\n // Upload to server\n const result = await fetchUploadProject({\n body: {\n chatId,\n name: projectName,\n type: 'code',\n files: processedFiles,\n },\n });\n\n if (!result?.data) {\n throw new Error('Failed to upload project');\n }\n\n return result.data;\n };\n\n const handleZipFile = async (file: File) => {\n try {\n setError(null);\n setIsProcessing(true);\n\n const { files: processedFiles, projectName } = await processZipFile(file, {\n ignorePatterns: ['**/node_modules/**'],\n });\n\n const projectAttachment = await processFiles(projectName, processedFiles);\n\n onSuccess?.({ ...projectAttachment, id: generateId(), status: 'ready' }, projectName);\n return projectAttachment;\n } catch (err) {\n setError('Failed to process zip file');\n onError?.('Failed to process zip file');\n console.error('Error processing zip:', err);\n throw err;\n } finally {\n setIsProcessing(false);\n }\n };\n\n const handleFolder = async (files: FileList | File[]) => {\n try {\n setError(null);\n setIsProcessing(true);\n\n const { files: processedFiles, projectName } = await processFolder(files, {\n ignorePatterns: ['**/node_modules/**'],\n });\n\n const projectAttachment = await processFiles(projectName, processedFiles);\n\n onSuccess?.({ ...projectAttachment, id: generateId(), status: 'ready' }, projectName);\n return projectAttachment;\n } catch (err) {\n setError('Failed to process folder');\n onError?.('Failed to process folder');\n console.error('Error processing folder:', err);\n throw err;\n } finally {\n setIsProcessing(false);\n }\n };\n\n return {\n processZipFile: handleZipFile,\n processFolder: handleFolder,\n isLoading: isProcessing || isFetching,\n error: fetchError || error,\n };\n}\n"],"names":["ALLOWED_EXTENSIONS","MAX_LINES_PER_FILE","DEFAULT_IGNORE_PATTERNS","isAllowedFile","filename","ignorePatterns","micromatch","isMatch","some","ext","toLowerCase","endsWith","pruneFileContent","content","lines","split","length","truncated","slice","join","openZipFile","file","options","zip","JSZip","contents","loadAsync","processedFiles","Promise","all","Object","keys","files","map","zipEntry","dir","async","push","path","err","console","warn","sort","a","b","localeCompare","processFolder","folderName","firstFile","folderPath","webkitRelativePath","pathParts","Array","from","filePath","name","text","includes","substring","indexOf","projectName","processZipFile","replace","useCodeUpload","onSuccess","onError","error","setError","useState","isProcessing","setIsProcessing","fetch","fetchUploadProject","isPending","isFetching","fetchError","useFetchUploadProject","id","chatId","useStrapiChat","processFiles","result","body","type","data","Error","handleZipFile","projectAttachment","generateId","status","handleFolder","isLoading"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCodeUpload.mjs","sources":["../../../../../admin/src/components/AIChat/hooks/useCodeUpload.ts"],"sourcesContent":["import { useState } from 'react';\n\nimport JSZip from 'jszip';\nimport micromatch from 'micromatch';\n\nimport { generateId } from '../lib/misc';\nimport { Attachment } from '../lib/types/attachments';\nimport { useStrapiChat } from '../providers/ChatProvider';\n\nimport { useFetchUploadProject } from './useAIFetch';\n\nexport interface ProjectFile {\n path: string;\n content: string;\n}\n\nconst ALLOWED_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.md', '.json'];\nconst MAX_LINES_PER_FILE = 5000; // Maximum number of lines per file\n\n// Common patterns to ignore\nconst DEFAULT_IGNORE_PATTERNS = [\n '**/node_modules/**',\n '**/.git/**',\n '**/.next/**',\n '**/dist/**',\n '**/build/**',\n '**/.cache/**',\n '**/coverage/**',\n '**/test/**',\n '**/__tests__/**',\n '**/*.test.*',\n '**/*.spec.*',\n];\n\nconst isAllowedFile = (filename: string, ignorePatterns: string[] = []) => {\n // Check if file matches any ignore pattern\n if (micromatch.isMatch(filename, [...DEFAULT_IGNORE_PATTERNS, ...ignorePatterns])) {\n return false;\n }\n\n // Check if file has allowed extension\n return ALLOWED_EXTENSIONS.some((ext) => filename.toLowerCase().endsWith(ext));\n};\n\n/**\n * Prunes file content if it exceeds MAX_LINES\n */\nconst pruneFileContent = (content: string): string => {\n const lines = content.split('\\n');\n\n if (lines.length <= MAX_LINES_PER_FILE) {\n return content;\n }\n\n const truncated = lines.slice(0, MAX_LINES_PER_FILE).join('\\n');\n\n return `${truncated}\\n\\n// ... [${lines.length - MAX_LINES_PER_FILE} lines truncated, file too long] ...\\n\\n`;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * File processing options\n * -----------------------------------------------------------------------------------------------*/\nexport interface ProcessOptions {\n /**\n * Additional glob patterns to ignore\n */\n ignorePatterns?: string[];\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Zip file processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function openZipFile(\n file: File,\n options: ProcessOptions = {}\n): Promise<ProjectFile[]> {\n const zip = new JSZip();\n const contents = await zip.loadAsync(file);\n const processedFiles: ProjectFile[] = [];\n\n // Process all files in parallel\n await Promise.all(\n Object.keys(contents.files).map(async (filename) => {\n const zipEntry = contents.files[filename];\n\n // Skip directories and non-allowed files\n if (zipEntry.dir || !isAllowedFile(filename, options.ignorePatterns)) {\n return;\n }\n\n try {\n const content = await zipEntry.async('string');\n processedFiles.push({\n path: filename,\n content: pruneFileContent(content),\n });\n } catch (err) {\n console.warn(`Failed to read file ${filename}:`, err);\n }\n })\n );\n\n // Sort files by path for consistency\n return processedFiles.sort((a, b) => a.path.localeCompare(b.path));\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Folder processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function processFolder(\n files: FileList | File[],\n options: ProcessOptions = {}\n): Promise<{ files: ProjectFile[]; projectName: string }> {\n const processedFiles: ProjectFile[] = [];\n let folderName = 'Project';\n\n // Extract folder name from the first file's path\n if (files.length > 0) {\n const firstFile = files[0];\n const folderPath = firstFile.webkitRelativePath || '';\n const pathParts = folderPath.split('/');\n if (pathParts.length > 0 && pathParts[0]) {\n folderName = pathParts[0];\n }\n }\n\n // Process all files in parallel\n await Promise.all(\n Array.from(files).map(async (file) => {\n const filePath = file.webkitRelativePath || file.name;\n\n // Skip non-allowed files\n if (!isAllowedFile(filePath, options.ignorePatterns)) {\n return;\n }\n\n try {\n const content = await file.text();\n processedFiles.push({\n // Remove the root folder name from the path\n path: filePath.includes('/') ? filePath.substring(filePath.indexOf('/') + 1) : filePath,\n content: pruneFileContent(content),\n });\n } catch (err) {\n console.warn(`Failed to read file ${filePath}:`, err);\n }\n })\n );\n\n // Sort files by path for consistency\n return {\n files: processedFiles.sort((a, b) => a.path.localeCompare(b.path)),\n projectName: folderName,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Zip file processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function processZipFile(\n file: File,\n options: ProcessOptions = {}\n): Promise<{ files: ProjectFile[]; projectName: string }> {\n const projectName = file.name.replace('.zip', '');\n const files = await openZipFile(file, options);\n\n return {\n files,\n projectName,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Upload files\n * -----------------------------------------------------------------------------------------------*/\n\ninterface UseCodeUploadOptions {\n onSuccess?: (attachment: Attachment, projectName: string) => void;\n onError?: (error: string) => void;\n}\n\nexport function useCodeUpload({ onSuccess, onError }: UseCodeUploadOptions = {}) {\n const [error, setError] = useState<string | null>(null);\n const [isProcessing, setIsProcessing] = useState(false);\n const {\n fetch: fetchUploadProject,\n isPending: isFetching,\n error: fetchError,\n } = useFetchUploadProject();\n const { id: chatId } = useStrapiChat();\n\n /**\n * Upload processed files to the server\n */\n const processFiles = async (projectName: string, processedFiles: ProjectFile[]) => {\n // Upload to server\n const result = await fetchUploadProject({\n body: {\n chatId,\n name: projectName,\n type: 'code',\n files: processedFiles,\n },\n });\n\n if (!result?.data) {\n throw new Error('Failed to upload project');\n }\n\n return result.data;\n };\n\n const handleZipFile = async (file: File) => {\n try {\n setError(null);\n setIsProcessing(true);\n\n const { files: processedFiles, projectName } = await processZipFile(file, {\n ignorePatterns: ['**/node_modules/**'],\n });\n\n const projectAttachment = await processFiles(projectName, processedFiles);\n\n onSuccess?.({ ...projectAttachment, id: generateId(), status: 'ready' }, projectName);\n return projectAttachment;\n } catch (err) {\n setError('Failed to process zip file');\n onError?.('Failed to process zip file');\n console.error('Error processing zip:', err);\n throw err;\n } finally {\n setIsProcessing(false);\n }\n };\n\n const handleFolder = async (files: FileList | File[]) => {\n try {\n setError(null);\n setIsProcessing(true);\n\n const { files: processedFiles, projectName } = await processFolder(files, {\n ignorePatterns: ['**/node_modules/**'],\n });\n\n const projectAttachment = await processFiles(projectName, processedFiles);\n\n onSuccess?.({ ...projectAttachment, id: generateId(), status: 'ready' }, projectName);\n return projectAttachment;\n } catch (err) {\n setError('Failed to process folder');\n onError?.('Failed to process folder');\n console.error('Error processing folder:', err);\n throw err;\n } finally {\n setIsProcessing(false);\n }\n };\n\n return {\n processZipFile: handleZipFile,\n processFolder: handleFolder,\n isLoading: isProcessing || isFetching,\n error: fetchError || error,\n };\n}\n"],"names":["ALLOWED_EXTENSIONS","MAX_LINES_PER_FILE","DEFAULT_IGNORE_PATTERNS","isAllowedFile","filename","ignorePatterns","micromatch","isMatch","some","ext","toLowerCase","endsWith","pruneFileContent","content","lines","split","length","truncated","slice","join","openZipFile","file","options","zip","JSZip","contents","loadAsync","processedFiles","Promise","all","Object","keys","files","map","zipEntry","dir","async","push","path","err","console","warn","sort","a","b","localeCompare","processFolder","folderName","firstFile","folderPath","webkitRelativePath","pathParts","Array","from","filePath","name","text","includes","substring","indexOf","projectName","processZipFile","replace","useCodeUpload","onSuccess","onError","error","setError","useState","isProcessing","setIsProcessing","fetch","fetchUploadProject","isPending","isFetching","fetchError","useFetchUploadProject","id","chatId","useStrapiChat","processFiles","result","body","type","data","Error","handleZipFile","projectAttachment","generateId","status","handleFolder","isLoading"],"mappings":";;;;;;;AAgBA,MAAMA,kBAAqB,GAAA;AAAC,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA;AAAQ,CAAA;AACzE,MAAMC,kBAAAA,GAAqB;AAE3B;AACA,MAAMC,uBAA0B,GAAA;AAC9B,IAAA,oBAAA;AACA,IAAA,YAAA;AACA,IAAA,aAAA;AACA,IAAA,YAAA;AACA,IAAA,aAAA;AACA,IAAA,cAAA;AACA,IAAA,gBAAA;AACA,IAAA,YAAA;AACA,IAAA,iBAAA;AACA,IAAA,aAAA;AACA,IAAA;AACD,CAAA;AAED,MAAMC,aAAgB,GAAA,CAACC,QAAkBC,EAAAA,cAAAA,GAA2B,EAAE,GAAA;;IAEpE,IAAIC,UAAAA,CAAWC,OAAO,CAACH,QAAU,EAAA;AAAIF,QAAAA,GAAAA,uBAAAA;AAA4BG,QAAAA,GAAAA;KAAe,CAAG,EAAA;QACjF,OAAO,KAAA;AACT;;IAGA,OAAOL,kBAAAA,CAAmBQ,IAAI,CAAC,CAACC,MAAQL,QAASM,CAAAA,WAAW,EAAGC,CAAAA,QAAQ,CAACF,GAAAA,CAAAA,CAAAA;AAC1E,CAAA;AAEA;;IAGA,MAAMG,mBAAmB,CAACC,OAAAA,GAAAA;IACxB,MAAMC,KAAAA,GAAQD,OAAQE,CAAAA,KAAK,CAAC,IAAA,CAAA;IAE5B,IAAID,KAAAA,CAAME,MAAM,IAAIf,kBAAoB,EAAA;QACtC,OAAOY,OAAAA;AACT;AAEA,IAAA,MAAMI,YAAYH,KAAMI,CAAAA,KAAK,CAAC,CAAGjB,EAAAA,kBAAAA,CAAAA,CAAoBkB,IAAI,CAAC,IAAA,CAAA;IAE1D,OAAO,CAAC,EAAEF,SAAAA,CAAU,YAAY,EAAEH,MAAME,MAAM,GAAGf,kBAAmB,CAAA,wCAAwC,CAAC;AAC/G,CAAA;AAYA;;AAEkG,qGAC3F,eAAemB,WAAAA,CACpBC,IAAU,EACVC,OAAAA,GAA0B,EAAE,EAAA;AAE5B,IAAA,MAAMC,MAAM,IAAIC,KAAAA,EAAAA;AAChB,IAAA,MAAMC,QAAW,GAAA,MAAMF,GAAIG,CAAAA,SAAS,CAACL,IAAAA,CAAAA;AACrC,IAAA,MAAMM,iBAAgC,EAAE;;IAGxC,MAAMC,OAAAA,CAAQC,GAAG,CACfC,MAAOC,CAAAA,IAAI,CAACN,QAAAA,CAASO,KAAK,CAAA,CAAEC,GAAG,CAAC,OAAO7B,QAAAA,GAAAA;AACrC,QAAA,MAAM8B,QAAWT,GAAAA,QAAAA,CAASO,KAAK,CAAC5B,QAAS,CAAA;;QAGzC,IAAI8B,QAAAA,CAASC,GAAG,IAAI,CAAChC,cAAcC,QAAUkB,EAAAA,OAAAA,CAAQjB,cAAc,CAAG,EAAA;AACpE,YAAA;AACF;QAEA,IAAI;AACF,YAAA,MAAMQ,OAAU,GAAA,MAAMqB,QAASE,CAAAA,KAAK,CAAC,QAAA,CAAA;AACrCT,YAAAA,cAAAA,CAAeU,IAAI,CAAC;gBAClBC,IAAMlC,EAAAA,QAAAA;AACNS,gBAAAA,OAAAA,EAASD,gBAAiBC,CAAAA,OAAAA;AAC5B,aAAA,CAAA;AACF,SAAA,CAAE,OAAO0B,GAAK,EAAA;YACZC,OAAQC,CAAAA,IAAI,CAAC,CAAC,oBAAoB,EAAErC,QAAS,CAAA,CAAC,CAAC,EAAEmC,GAAAA,CAAAA;AACnD;AACF,KAAA,CAAA,CAAA;;AAIF,IAAA,OAAOZ,cAAee,CAAAA,IAAI,CAAC,CAACC,CAAGC,EAAAA,CAAAA,GAAMD,CAAEL,CAAAA,IAAI,CAACO,aAAa,CAACD,CAAAA,CAAEN,IAAI,CAAA,CAAA;AAClE;AAEA;;AAEkG,qGAC3F,eAAeQ,aAAAA,CACpBd,KAAwB,EACxBV,OAAAA,GAA0B,EAAE,EAAA;AAE5B,IAAA,MAAMK,iBAAgC,EAAE;AACxC,IAAA,IAAIoB,UAAa,GAAA,SAAA;;IAGjB,IAAIf,KAAAA,CAAMhB,MAAM,GAAG,CAAG,EAAA;QACpB,MAAMgC,SAAAA,GAAYhB,KAAK,CAAC,CAAE,CAAA;QAC1B,MAAMiB,UAAAA,GAAaD,SAAUE,CAAAA,kBAAkB,IAAI,EAAA;QACnD,MAAMC,SAAAA,GAAYF,UAAWlC,CAAAA,KAAK,CAAC,GAAA,CAAA;AACnC,QAAA,IAAIoC,UAAUnC,MAAM,GAAG,KAAKmC,SAAS,CAAC,EAAE,EAAE;YACxCJ,UAAaI,GAAAA,SAAS,CAAC,CAAE,CAAA;AAC3B;AACF;;IAGA,MAAMvB,OAAAA,CAAQC,GAAG,CACfuB,KAAAA,CAAMC,IAAI,CAACrB,KAAAA,CAAAA,CAAOC,GAAG,CAAC,OAAOZ,IAAAA,GAAAA;AAC3B,QAAA,MAAMiC,QAAWjC,GAAAA,IAAAA,CAAK6B,kBAAkB,IAAI7B,KAAKkC,IAAI;;AAGrD,QAAA,IAAI,CAACpD,aAAAA,CAAcmD,QAAUhC,EAAAA,OAAAA,CAAQjB,cAAc,CAAG,EAAA;AACpD,YAAA;AACF;QAEA,IAAI;YACF,MAAMQ,OAAAA,GAAU,MAAMQ,IAAAA,CAAKmC,IAAI,EAAA;AAC/B7B,YAAAA,cAAAA,CAAeU,IAAI,CAAC;;gBAElBC,IAAMgB,EAAAA,QAAAA,CAASG,QAAQ,CAAC,GAAOH,CAAAA,GAAAA,QAAAA,CAASI,SAAS,CAACJ,QAASK,CAAAA,OAAO,CAAC,GAAA,CAAA,GAAO,CAAKL,CAAAA,GAAAA,QAAAA;AAC/EzC,gBAAAA,OAAAA,EAASD,gBAAiBC,CAAAA,OAAAA;AAC5B,aAAA,CAAA;AACF,SAAA,CAAE,OAAO0B,GAAK,EAAA;YACZC,OAAQC,CAAAA,IAAI,CAAC,CAAC,oBAAoB,EAAEa,QAAS,CAAA,CAAC,CAAC,EAAEf,GAAAA,CAAAA;AACnD;AACF,KAAA,CAAA,CAAA;;IAIF,OAAO;AACLP,QAAAA,KAAAA,EAAOL,cAAee,CAAAA,IAAI,CAAC,CAACC,CAAGC,EAAAA,CAAAA,GAAMD,CAAEL,CAAAA,IAAI,CAACO,aAAa,CAACD,CAAAA,CAAEN,IAAI,CAAA,CAAA;QAChEsB,WAAab,EAAAA;AACf,KAAA;AACF;AAEA;;AAEkG,qGAC3F,eAAec,cAAAA,CACpBxC,IAAU,EACVC,OAAAA,GAA0B,EAAE,EAAA;AAE5B,IAAA,MAAMsC,cAAcvC,IAAKkC,CAAAA,IAAI,CAACO,OAAO,CAAC,MAAQ,EAAA,EAAA,CAAA;IAC9C,MAAM9B,KAAAA,GAAQ,MAAMZ,WAAAA,CAAYC,IAAMC,EAAAA,OAAAA,CAAAA;IAEtC,OAAO;AACLU,QAAAA,KAAAA;AACA4B,QAAAA;AACF,KAAA;AACF;AAWO,SAASG,cAAc,EAAEC,SAAS,EAAEC,OAAO,EAAwB,GAAG,EAAE,EAAA;AAC7E,IAAA,MAAM,CAACC,KAAAA,EAAOC,QAAS,CAAA,GAAGC,QAAwB,CAAA,IAAA,CAAA;AAClD,IAAA,MAAM,CAACC,YAAAA,EAAcC,eAAgB,CAAA,GAAGF,QAAS,CAAA,KAAA,CAAA;IACjD,MAAM,EACJG,KAAOC,EAAAA,kBAAkB,EACzBC,SAAAA,EAAWC,UAAU,EACrBR,KAAAA,EAAOS,UAAU,EAClB,GAAGC,qBAAAA,EAAAA;AACJ,IAAA,MAAM,EAAEC,EAAAA,EAAIC,MAAM,EAAE,GAAGC,aAAAA,EAAAA;AAEvB;;MAGA,MAAMC,YAAe,GAAA,OAAOpB,WAAqBjC,EAAAA,cAAAA,GAAAA;;QAE/C,MAAMsD,MAAAA,GAAS,MAAMT,kBAAmB,CAAA;YACtCU,IAAM,EAAA;AACJJ,gBAAAA,MAAAA;gBACAvB,IAAMK,EAAAA,WAAAA;gBACNuB,IAAM,EAAA,MAAA;gBACNnD,KAAOL,EAAAA;AACT;AACF,SAAA,CAAA;QAEA,IAAI,CAACsD,QAAQG,IAAM,EAAA;AACjB,YAAA,MAAM,IAAIC,KAAM,CAAA,0BAAA,CAAA;AAClB;AAEA,QAAA,OAAOJ,OAAOG,IAAI;AACpB,KAAA;AAEA,IAAA,MAAME,gBAAgB,OAAOjE,IAAAA,GAAAA;QAC3B,IAAI;YACF8C,QAAS,CAAA,IAAA,CAAA;YACTG,eAAgB,CAAA,IAAA,CAAA;YAEhB,MAAM,EAAEtC,OAAOL,cAAc,EAAEiC,WAAW,EAAE,GAAG,MAAMC,cAAAA,CAAexC,IAAM,EAAA;gBACxEhB,cAAgB,EAAA;AAAC,oBAAA;AAAqB;AACxC,aAAA,CAAA;YAEA,MAAMkF,iBAAAA,GAAoB,MAAMP,YAAAA,CAAapB,WAAajC,EAAAA,cAAAA,CAAAA;YAE1DqC,SAAY,GAAA;AAAE,gBAAA,GAAGuB,iBAAiB;gBAAEV,EAAIW,EAAAA,UAAAA,EAAAA;gBAAcC,MAAQ,EAAA;aAAW7B,EAAAA,WAAAA,CAAAA;YACzE,OAAO2B,iBAAAA;AACT,SAAA,CAAE,OAAOhD,GAAK,EAAA;YACZ4B,QAAS,CAAA,4BAAA,CAAA;YACTF,OAAU,GAAA,4BAAA,CAAA;YACVzB,OAAQ0B,CAAAA,KAAK,CAAC,uBAAyB3B,EAAAA,GAAAA,CAAAA;YACvC,MAAMA,GAAAA;SACE,QAAA;YACR+B,eAAgB,CAAA,KAAA,CAAA;AAClB;AACF,KAAA;AAEA,IAAA,MAAMoB,eAAe,OAAO1D,KAAAA,GAAAA;QAC1B,IAAI;YACFmC,QAAS,CAAA,IAAA,CAAA;YACTG,eAAgB,CAAA,IAAA,CAAA;YAEhB,MAAM,EAAEtC,OAAOL,cAAc,EAAEiC,WAAW,EAAE,GAAG,MAAMd,aAAAA,CAAcd,KAAO,EAAA;gBACxE3B,cAAgB,EAAA;AAAC,oBAAA;AAAqB;AACxC,aAAA,CAAA;YAEA,MAAMkF,iBAAAA,GAAoB,MAAMP,YAAAA,CAAapB,WAAajC,EAAAA,cAAAA,CAAAA;YAE1DqC,SAAY,GAAA;AAAE,gBAAA,GAAGuB,iBAAiB;gBAAEV,EAAIW,EAAAA,UAAAA,EAAAA;gBAAcC,MAAQ,EAAA;aAAW7B,EAAAA,WAAAA,CAAAA;YACzE,OAAO2B,iBAAAA;AACT,SAAA,CAAE,OAAOhD,GAAK,EAAA;YACZ4B,QAAS,CAAA,0BAAA,CAAA;YACTF,OAAU,GAAA,0BAAA,CAAA;YACVzB,OAAQ0B,CAAAA,KAAK,CAAC,0BAA4B3B,EAAAA,GAAAA,CAAAA;YAC1C,MAAMA,GAAAA;SACE,QAAA;YACR+B,eAAgB,CAAA,KAAA,CAAA;AAClB;AACF,KAAA;IAEA,OAAO;QACLT,cAAgByB,EAAAA,aAAAA;QAChBxC,aAAe4C,EAAAA,YAAAA;AACfC,QAAAA,SAAAA,EAAWtB,YAAgBK,IAAAA,UAAAA;AAC3BR,QAAAA,KAAAA,EAAOS,UAAcT,IAAAA;AACvB,KAAA;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"useCodeUpload.mjs","sources":["../../../../../admin/src/components/AIChat/hooks/useCodeUpload.ts"],"sourcesContent":["import { useState } from 'react';\n\nimport JSZip from 'jszip';\nimport micromatch from 'micromatch';\n\nimport { generateId } from '../lib/misc';\nimport { Attachment } from '../lib/types/attachments';\nimport { useStrapiChat } from '../providers/ChatProvider';\n\nimport { useFetchUploadProject } from './useAIFetch';\n\nexport interface ProjectFile {\n path: string;\n content: string;\n}\n\nconst ALLOWED_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.md', '.json'];\nconst MAX_LINES_PER_FILE = 5000; // Maximum number of lines per file\n\n// Common patterns to ignore\nconst DEFAULT_IGNORE_PATTERNS = [\n '**/node_modules/**',\n '**/.git/**',\n '**/.next/**',\n '**/dist/**',\n '**/build/**',\n '**/.cache/**',\n '**/coverage/**',\n '**/test/**',\n '**/__tests__/**',\n '**/*.test.*',\n '**/*.spec.*',\n];\n\nconst isAllowedFile = (filename: string, ignorePatterns: string[] = []) => {\n // Check if file matches any ignore pattern\n if (micromatch.isMatch(filename, [...DEFAULT_IGNORE_PATTERNS, ...ignorePatterns])) {\n return false;\n }\n\n // Check if file has allowed extension\n return ALLOWED_EXTENSIONS.some((ext) => filename.toLowerCase().endsWith(ext));\n};\n\n/**\n * Prunes file content if it exceeds MAX_LINES\n */\nconst pruneFileContent = (content: string): string => {\n const lines = content.split('\\n');\n\n if (lines.length <= MAX_LINES_PER_FILE) {\n return content;\n }\n\n const truncated = lines.slice(0, MAX_LINES_PER_FILE).join('\\n');\n\n return `${truncated}\\n\\n// ... [${lines.length - MAX_LINES_PER_FILE} lines truncated, file too long] ...\\n\\n`;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * File processing options\n * -----------------------------------------------------------------------------------------------*/\nexport interface ProcessOptions {\n /**\n * Additional glob patterns to ignore\n */\n ignorePatterns?: string[];\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Zip file processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function openZipFile(\n file: File,\n options: ProcessOptions = {}\n): Promise<ProjectFile[]> {\n const zip = new JSZip();\n const contents = await zip.loadAsync(file);\n const processedFiles: ProjectFile[] = [];\n\n // Process all files in parallel\n await Promise.all(\n Object.keys(contents.files).map(async (filename) => {\n const zipEntry = contents.files[filename];\n\n // Skip directories and non-allowed files\n if (zipEntry.dir || !isAllowedFile(filename, options.ignorePatterns)) {\n return;\n }\n\n try {\n const content = await zipEntry.async('string');\n processedFiles.push({\n path: filename,\n content: pruneFileContent(content),\n });\n } catch (err) {\n console.warn(`Failed to read file ${filename}:`, err);\n }\n })\n );\n\n // Sort files by path for consistency\n return processedFiles.sort((a, b) => a.path.localeCompare(b.path));\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Folder processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function processFolder(\n files: FileList | File[],\n options: ProcessOptions = {}\n): Promise<{ files: ProjectFile[]; projectName: string }> {\n const processedFiles: ProjectFile[] = [];\n let folderName = 'Project';\n\n // Extract folder name from the first file's path\n if (files.length > 0) {\n const firstFile = files[0];\n const folderPath = firstFile.webkitRelativePath || '';\n const pathParts = folderPath.split('/');\n if (pathParts.length > 0 && pathParts[0]) {\n folderName = pathParts[0];\n }\n }\n\n // Process all files in parallel\n await Promise.all(\n Array.from(files).map(async (file) => {\n const filePath = file.webkitRelativePath || file.name;\n\n // Skip non-allowed files\n if (!isAllowedFile(filePath, options.ignorePatterns)) {\n return;\n }\n\n try {\n const content = await file.text();\n processedFiles.push({\n // Remove the root folder name from the path\n path: filePath.includes('/') ? filePath.substring(filePath.indexOf('/') + 1) : filePath,\n content: pruneFileContent(content),\n });\n } catch (err) {\n console.warn(`Failed to read file ${filePath}:`, err);\n }\n })\n );\n\n // Sort files by path for consistency\n return {\n files: processedFiles.sort((a, b) => a.path.localeCompare(b.path)),\n projectName: folderName,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Zip file processing\n * -----------------------------------------------------------------------------------------------*/\nexport async function processZipFile(\n file: File,\n options: ProcessOptions = {}\n): Promise<{ files: ProjectFile[]; projectName: string }> {\n const projectName = file.name.replace('.zip', '');\n const files = await openZipFile(file, options);\n\n return {\n files,\n projectName,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Upload files\n * -----------------------------------------------------------------------------------------------*/\n\ninterface UseCodeUploadOptions {\n onSuccess?: (attachment: Attachment, projectName: string) => void;\n onError?: (error: string) => void;\n}\n\nexport function useCodeUpload({ onSuccess, onError }: UseCodeUploadOptions = {}) {\n const [error, setError] = useState<string | null>(null);\n const [isProcessing, setIsProcessing] = useState(false);\n const {\n fetch: fetchUploadProject,\n isPending: isFetching,\n error: fetchError,\n } = useFetchUploadProject();\n const { id: chatId } = useStrapiChat();\n\n /**\n * Upload processed files to the server\n */\n const processFiles = async (projectName: string, processedFiles: ProjectFile[]) => {\n // Upload to server\n const result = await fetchUploadProject({\n body: {\n chatId,\n name: projectName,\n type: 'code',\n files: processedFiles,\n },\n });\n\n if (!result?.data) {\n throw new Error('Failed to upload project');\n }\n\n return result.data;\n };\n\n const handleZipFile = async (file: File) => {\n try {\n setError(null);\n setIsProcessing(true);\n\n const { files: processedFiles, projectName } = await processZipFile(file, {\n ignorePatterns: ['**/node_modules/**'],\n });\n\n const projectAttachment = await processFiles(projectName, processedFiles);\n\n onSuccess?.({ ...projectAttachment, id: generateId(), status: 'ready' }, projectName);\n return projectAttachment;\n } catch (err) {\n setError('Failed to process zip file');\n onError?.('Failed to process zip file');\n console.error('Error processing zip:', err);\n throw err;\n } finally {\n setIsProcessing(false);\n }\n };\n\n const handleFolder = async (files: FileList | File[]) => {\n try {\n setError(null);\n setIsProcessing(true);\n\n const { files: processedFiles, projectName } = await processFolder(files, {\n ignorePatterns: ['**/node_modules/**'],\n });\n\n const projectAttachment = await processFiles(projectName, processedFiles);\n\n onSuccess?.({ ...projectAttachment, id: generateId(), status: 'ready' }, projectName);\n return projectAttachment;\n } catch (err) {\n setError('Failed to process folder');\n onError?.('Failed to process folder');\n console.error('Error processing folder:', err);\n throw err;\n } finally {\n setIsProcessing(false);\n }\n };\n\n return {\n processZipFile: handleZipFile,\n processFolder: handleFolder,\n isLoading: isProcessing || isFetching,\n error: fetchError || error,\n };\n}\n"],"names":["ALLOWED_EXTENSIONS","MAX_LINES_PER_FILE","DEFAULT_IGNORE_PATTERNS","isAllowedFile","filename","ignorePatterns","micromatch","isMatch","some","ext","toLowerCase","endsWith","pruneFileContent","content","lines","split","length","truncated","slice","join","openZipFile","file","options","zip","JSZip","contents","loadAsync","processedFiles","Promise","all","Object","keys","files","map","zipEntry","dir","async","push","path","err","console","warn","sort","a","b","localeCompare","processFolder","folderName","firstFile","folderPath","webkitRelativePath","pathParts","Array","from","filePath","name","text","includes","substring","indexOf","projectName","processZipFile","replace","useCodeUpload","onSuccess","onError","error","setError","useState","isProcessing","setIsProcessing","fetch","fetchUploadProject","isPending","isFetching","fetchError","useFetchUploadProject","id","chatId","useStrapiChat","processFiles","result","body","type","data","Error","handleZipFile","projectAttachment","generateId","status","handleFolder","isLoading"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFigmaUpload.js","sources":["../../../../../admin/src/components/AIChat/hooks/useFigmaUpload.ts"],"sourcesContent":["import { useState } from 'react';\n\nimport type { Attachment } from '../lib/types/attachments';\n\n/**================================================================================\n * Constants\n *================================================================================*/\nexport const FIGMA_TOKEN_STORAGE_KEY = 'strapi-ai-figma-token';\n\n/**================================================================================\n * Types\n *================================================================================*/\nexport interface FigmaNodeData {\n id: string;\n name: string;\n type: string;\n children?: FigmaNodeData[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any; // For other properties that Figma nodes may have\n}\n\nexport interface FigmaFileData {\n document: FigmaNodeData;\n schemaVersion: number;\n name: string;\n lastModified: string;\n thumbnailUrl: string;\n version: string;\n role: string;\n}\n\nexport interface FigmaImage extends Attachment {}\n\ninterface UseFigmaUploadOptions {\n onSuccess?: (attachments: FigmaImage[]) => void;\n onError?: (error: string) => void;\n}\n\n/**================================================================================\n * Token Storage Utils\n *================================================================================*/\n\n/**\n * Get Figma token from localStorage\n */\nexport const getFigmaToken = (): string => {\n try {\n return localStorage.getItem(FIGMA_TOKEN_STORAGE_KEY) || '';\n } catch (error) {\n console.error('Error accessing localStorage:', error);\n return '';\n }\n};\n\n/**\n * Save Figma token to localStorage\n */\nexport const saveFigmaToken = (token: string): void => {\n try {\n localStorage.setItem(FIGMA_TOKEN_STORAGE_KEY, token);\n } catch (error) {\n console.error('Error saving to localStorage:', error);\n }\n};\n\n/**\n * Check if Figma token exists in localStorage\n */\nexport const hasFigmaToken = (): boolean => {\n return !!getFigmaToken();\n};\n\n/**================================================================================\n * Utils\n *================================================================================*/\n\n/**\n * Extract file key and node ID from Figma URL\n * @param figmaUrl - Figma URL (e.g., https://www.figma.com/file/KEY/Title)\n */\nconst extractNodeFromFigmaUrl = (figmaUrl: string) => {\n const figmaUrlPattern = /figma\\.com\\/(?:file|design)\\/([a-zA-Z0-9]+)\\/.*[?&]node-id=([^&]+)/;\n const match = figmaUrl.match(figmaUrlPattern);\n\n if (!match) {\n throw new Error('Invalid Figma URL');\n }\n\n const fileKey = match[1];\n const nodeId = decodeURIComponent(match[2]).replace(/-/g, ':');\n\n return { fileKey, nodeId };\n};\n\n/**\n * Get token and validate it's available\n * @throws Error if token is not available\n */\nconst getValidToken = (): string => {\n const token = getFigmaToken();\n if (!token) {\n throw new Error('Figma API token is required');\n }\n return token;\n};\n\n/**\n * Fetch Figma file data using the API\n * @param fileKey - Figma file key\n * @param nodeId - Figma node ID\n */\nconst fetchFigmaNode = async (fileKey: string, nodeId: string): Promise<FigmaFileData> => {\n const token = getValidToken();\n\n try {\n const apiUrl = `https://api.figma.com/v1/files/${fileKey}/nodes?ids=${nodeId}`;\n\n const response = await fetch(apiUrl, {\n headers: {\n 'X-Figma-Token': token,\n },\n });\n\n if (!response.ok) {\n throw new Error(`Figma API error: ${response.status} ${response.statusText}`);\n }\n\n const nodes = await response.json();\n\n return nodes.nodes[nodeId];\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch Figma data';\n throw new Error(errorMessage);\n }\n};\n\n/**\n * Recursively searches the node tree for FRAME nodes.\n * It stops searching within a branch once a FRAME is found.\n * @param node - The current FigmaNodeData to inspect.\n */\ninterface FrameInfo {\n id: string;\n name: string;\n}\n\nconst findFramesInNode = (node: FigmaNodeData): FrameInfo[] => {\n const frames: FrameInfo[] = [];\n if (node.type === 'FRAME') {\n frames.push({\n id: node.id,\n name: node.name,\n });\n return frames;\n }\n\n if (node.children && node.children.length > 0) {\n for (const child of node.children) {\n // Continue searching in children if the current node is not a FRAME\n frames.push(...findFramesInNode(child));\n }\n }\n\n return frames;\n};\n\n/**\n * Fetch images for specific nodes from the Figma API\n * @param fileKey - Figma file key\n * @param nodeIds - Array of node IDs to render\n */\nconst fetchFigmaNodeImages = async (\n fileKey: string,\n nodeIds: string[]\n): Promise<{ images: Record<string, string> }> => {\n const token = getValidToken();\n\n if (nodeIds.length === 0) {\n return { images: {} };\n }\n try {\n // Max 50 node IDs per request according to Figma API docs\n // We might need to chunk requests if nodeIds is very large\n const idsQueryParam = nodeIds.slice(0, 50).join(',');\n const apiUrl = `https://api.figma.com/v1/images/${fileKey}?ids=${idsQueryParam}&format=png&scale=0.4`;\n\n const response = await fetch(apiUrl, {\n headers: { 'X-Figma-Token': token },\n });\n\n if (!response.ok) {\n const errorData = await response.text();\n throw new Error(\n `Figma API image error: ${response.status} ${response.statusText} - ${errorData}`\n );\n }\n\n const result = await response.json();\n if (result.err) {\n throw new Error(`Figma API image error: ${result.err}`);\n }\n\n return result as { images: Record<string, string> };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch Figma node images';\n throw new Error(errorMessage);\n }\n};\n\n/**================================================================================\n * Hooks\n *================================================================================*/\nexport function useFigmaUpload({ onSuccess, onError }: UseFigmaUploadOptions = {}) {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n /**\n * Main method to process a Figma URL\n * @param figmaUrl - Figma URL to process\n */\n const processFigmaUrl = async (figmaUrl: string) => {\n try {\n // Check if token exists before proceeding\n if (!hasFigmaToken()) {\n const errorMessage = 'Figma API token is required';\n setError(errorMessage);\n onError?.(errorMessage);\n throw new Error(errorMessage);\n }\n\n setIsLoading(true);\n setError(null);\n\n // 1. Extract file key from URL\n const { fileKey, nodeId: selectedNode } = extractNodeFromFigmaUrl(figmaUrl);\n\n // 2. Fetch base data from Figma API to get structure\n const figmaData = await fetchFigmaNode(fileKey, selectedNode);\n if (!figmaData.document) return;\n\n // 3. Find frame nodes with their names\n const frames = findFramesInNode(figmaData.document);\n // Create a map of ID to name for later use\n const frameNameMap = new Map(frames.map((frame) => [frame.id, frame.name]));\n // Get just the IDs for the API call\n const frameIds = frames.map((frame) => frame.id);\n\n // 4. Fetch images for the identified nodes\n const imageResponse = await fetchFigmaNodeImages(fileKey, frameIds);\n const images = imageResponse.images;\n\n // Use the name from our map instead of just the ID\n const figmaImages = Object.entries(images).map(\n ([id, url]) =>\n ({\n id,\n type: 'file',\n filename: frameNameMap.get(id),\n mediaType: 'image/png',\n url,\n status: 'ready',\n }) satisfies FigmaImage\n );\n\n onSuccess?.(figmaImages);\n return figmaImages;\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : 'Unknown error processing Figma URL';\n setError(errorMessage);\n onError?.(errorMessage);\n console.error('Error processing Figma URL:', err);\n throw err;\n } finally {\n setIsLoading(false);\n }\n };\n\n return {\n processFigmaUrl,\n isLoading: isLoading,\n error: error,\n };\n}\n"],"names":["FIGMA_TOKEN_STORAGE_KEY","getFigmaToken","localStorage","getItem","error","console","saveFigmaToken","token","setItem","hasFigmaToken","extractNodeFromFigmaUrl","figmaUrl","figmaUrlPattern","match","Error","fileKey","nodeId","decodeURIComponent","replace","getValidToken","fetchFigmaNode","apiUrl","response","fetch","headers","ok","status","statusText","nodes","json","err","errorMessage","message","findFramesInNode","node","frames","type","push","id","name","children","length","child","fetchFigmaNodeImages","nodeIds","images","idsQueryParam","slice","join","errorData","text","result","useFigmaUpload","onSuccess","onError","isLoading","setIsLoading","useState","setError","processFigmaUrl","selectedNode","figmaData","document","frameNameMap","Map","map","frame","frameIds","imageResponse","figmaImages","Object","entries","url","filename","get","mediaType"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useFigmaUpload.js","sources":["../../../../../admin/src/components/AIChat/hooks/useFigmaUpload.ts"],"sourcesContent":["import { useState } from 'react';\n\nimport type { Attachment } from '../lib/types/attachments';\n\n/**================================================================================\n * Constants\n *================================================================================*/\nexport const FIGMA_TOKEN_STORAGE_KEY = 'strapi-ai-figma-token';\n\n/**================================================================================\n * Types\n *================================================================================*/\nexport interface FigmaNodeData {\n id: string;\n name: string;\n type: string;\n children?: FigmaNodeData[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any; // For other properties that Figma nodes may have\n}\n\nexport interface FigmaFileData {\n document: FigmaNodeData;\n schemaVersion: number;\n name: string;\n lastModified: string;\n thumbnailUrl: string;\n version: string;\n role: string;\n}\n\nexport interface FigmaImage extends Attachment {}\n\ninterface UseFigmaUploadOptions {\n onSuccess?: (attachments: FigmaImage[]) => void;\n onError?: (error: string) => void;\n}\n\n/**================================================================================\n * Token Storage Utils\n *================================================================================*/\n\n/**\n * Get Figma token from localStorage\n */\nexport const getFigmaToken = (): string => {\n try {\n return localStorage.getItem(FIGMA_TOKEN_STORAGE_KEY) || '';\n } catch (error) {\n console.error('Error accessing localStorage:', error);\n return '';\n }\n};\n\n/**\n * Save Figma token to localStorage\n */\nexport const saveFigmaToken = (token: string): void => {\n try {\n localStorage.setItem(FIGMA_TOKEN_STORAGE_KEY, token);\n } catch (error) {\n console.error('Error saving to localStorage:', error);\n }\n};\n\n/**\n * Check if Figma token exists in localStorage\n */\nexport const hasFigmaToken = (): boolean => {\n return !!getFigmaToken();\n};\n\n/**================================================================================\n * Utils\n *================================================================================*/\n\n/**\n * Extract file key and node ID from Figma URL\n * @param figmaUrl - Figma URL (e.g., https://www.figma.com/file/KEY/Title)\n */\nconst extractNodeFromFigmaUrl = (figmaUrl: string) => {\n const figmaUrlPattern = /figma\\.com\\/(?:file|design)\\/([a-zA-Z0-9]+)\\/.*[?&]node-id=([^&]+)/;\n const match = figmaUrl.match(figmaUrlPattern);\n\n if (!match) {\n throw new Error('Invalid Figma URL');\n }\n\n const fileKey = match[1];\n const nodeId = decodeURIComponent(match[2]).replace(/-/g, ':');\n\n return { fileKey, nodeId };\n};\n\n/**\n * Get token and validate it's available\n * @throws Error if token is not available\n */\nconst getValidToken = (): string => {\n const token = getFigmaToken();\n if (!token) {\n throw new Error('Figma API token is required');\n }\n return token;\n};\n\n/**\n * Fetch Figma file data using the API\n * @param fileKey - Figma file key\n * @param nodeId - Figma node ID\n */\nconst fetchFigmaNode = async (fileKey: string, nodeId: string): Promise<FigmaFileData> => {\n const token = getValidToken();\n\n try {\n const apiUrl = `https://api.figma.com/v1/files/${fileKey}/nodes?ids=${nodeId}`;\n\n const response = await fetch(apiUrl, {\n headers: {\n 'X-Figma-Token': token,\n },\n });\n\n if (!response.ok) {\n throw new Error(`Figma API error: ${response.status} ${response.statusText}`);\n }\n\n const nodes = await response.json();\n\n return nodes.nodes[nodeId];\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch Figma data';\n throw new Error(errorMessage);\n }\n};\n\n/**\n * Recursively searches the node tree for FRAME nodes.\n * It stops searching within a branch once a FRAME is found.\n * @param node - The current FigmaNodeData to inspect.\n */\ninterface FrameInfo {\n id: string;\n name: string;\n}\n\nconst findFramesInNode = (node: FigmaNodeData): FrameInfo[] => {\n const frames: FrameInfo[] = [];\n if (node.type === 'FRAME') {\n frames.push({\n id: node.id,\n name: node.name,\n });\n return frames;\n }\n\n if (node.children && node.children.length > 0) {\n for (const child of node.children) {\n // Continue searching in children if the current node is not a FRAME\n frames.push(...findFramesInNode(child));\n }\n }\n\n return frames;\n};\n\n/**\n * Fetch images for specific nodes from the Figma API\n * @param fileKey - Figma file key\n * @param nodeIds - Array of node IDs to render\n */\nconst fetchFigmaNodeImages = async (\n fileKey: string,\n nodeIds: string[]\n): Promise<{ images: Record<string, string> }> => {\n const token = getValidToken();\n\n if (nodeIds.length === 0) {\n return { images: {} };\n }\n try {\n // Max 50 node IDs per request according to Figma API docs\n // We might need to chunk requests if nodeIds is very large\n const idsQueryParam = nodeIds.slice(0, 50).join(',');\n const apiUrl = `https://api.figma.com/v1/images/${fileKey}?ids=${idsQueryParam}&format=png&scale=0.4`;\n\n const response = await fetch(apiUrl, {\n headers: { 'X-Figma-Token': token },\n });\n\n if (!response.ok) {\n const errorData = await response.text();\n throw new Error(\n `Figma API image error: ${response.status} ${response.statusText} - ${errorData}`\n );\n }\n\n const result = await response.json();\n if (result.err) {\n throw new Error(`Figma API image error: ${result.err}`);\n }\n\n return result as { images: Record<string, string> };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to fetch Figma node images';\n throw new Error(errorMessage);\n }\n};\n\n/**================================================================================\n * Hooks\n *================================================================================*/\nexport function useFigmaUpload({ onSuccess, onError }: UseFigmaUploadOptions = {}) {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n /**\n * Main method to process a Figma URL\n * @param figmaUrl - Figma URL to process\n */\n const processFigmaUrl = async (figmaUrl: string) => {\n try {\n // Check if token exists before proceeding\n if (!hasFigmaToken()) {\n const errorMessage = 'Figma API token is required';\n setError(errorMessage);\n onError?.(errorMessage);\n throw new Error(errorMessage);\n }\n\n setIsLoading(true);\n setError(null);\n\n // 1. Extract file key from URL\n const { fileKey, nodeId: selectedNode } = extractNodeFromFigmaUrl(figmaUrl);\n\n // 2. Fetch base data from Figma API to get structure\n const figmaData = await fetchFigmaNode(fileKey, selectedNode);\n if (!figmaData.document) return;\n\n // 3. Find frame nodes with their names\n const frames = findFramesInNode(figmaData.document);\n // Create a map of ID to name for later use\n const frameNameMap = new Map(frames.map((frame) => [frame.id, frame.name]));\n // Get just the IDs for the API call\n const frameIds = frames.map((frame) => frame.id);\n\n // 4. Fetch images for the identified nodes\n const imageResponse = await fetchFigmaNodeImages(fileKey, frameIds);\n const images = imageResponse.images;\n\n // Use the name from our map instead of just the ID\n const figmaImages = Object.entries(images).map(\n ([id, url]) =>\n ({\n id,\n type: 'file',\n filename: frameNameMap.get(id),\n mediaType: 'image/png',\n url,\n status: 'ready',\n }) satisfies FigmaImage\n );\n\n onSuccess?.(figmaImages);\n return figmaImages;\n } catch (err) {\n const errorMessage =\n err instanceof Error ? err.message : 'Unknown error processing Figma URL';\n setError(errorMessage);\n onError?.(errorMessage);\n console.error('Error processing Figma URL:', err);\n throw err;\n } finally {\n setIsLoading(false);\n }\n };\n\n return {\n processFigmaUrl,\n isLoading: isLoading,\n error: error,\n };\n}\n"],"names":["FIGMA_TOKEN_STORAGE_KEY","getFigmaToken","localStorage","getItem","error","console","saveFigmaToken","token","setItem","hasFigmaToken","extractNodeFromFigmaUrl","figmaUrl","figmaUrlPattern","match","Error","fileKey","nodeId","decodeURIComponent","replace","getValidToken","fetchFigmaNode","apiUrl","response","fetch","headers","ok","status","statusText","nodes","json","err","errorMessage","message","findFramesInNode","node","frames","type","push","id","name","children","length","child","fetchFigmaNodeImages","nodeIds","images","idsQueryParam","slice","join","errorData","text","result","useFigmaUpload","onSuccess","onError","isLoading","setIsLoading","useState","setError","processFigmaUrl","selectedNode","figmaData","document","frameNameMap","Map","map","frame","frameIds","imageResponse","figmaImages","Object","entries","url","filename","get","mediaType"],"mappings":"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"}
|