├── .gitignore ├── LICENSE ├── README.md ├── examples ├── iframe │ ├── 2.html │ ├── cloudflared-config.yml │ ├── index.html │ └── package.json ├── javascript │ ├── build.html │ ├── index.html │ ├── package.json │ └── script-tag-v2.html ├── next-frontend-functions │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── next.config.mjs │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── next.svg │ │ └── vercel.svg │ ├── src │ │ └── app │ │ │ ├── audio-thread │ │ │ ├── page.tsx │ │ │ ├── primitives │ │ │ │ └── page.tsx │ │ │ └── webrtc-audio-runtime │ │ │ │ └── page.tsx │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ ├── page.tsx │ │ │ ├── suggestions │ │ │ ├── MarkdownProvider │ │ │ │ ├── Code.tsx │ │ │ │ └── index.tsx │ │ │ └── page.tsx │ │ │ ├── thread-dialog │ │ │ └── page.tsx │ │ │ └── thread │ │ │ ├── annotations │ │ │ └── page.tsx │ │ │ ├── customize-components │ │ │ └── page.tsx │ │ │ ├── image-upload │ │ │ └── page.tsx │ │ │ └── page.tsx │ └── tsconfig.json ├── next-multi-assistant │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── next.config.mjs │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── app │ │ │ ├── assistants │ │ │ │ └── [assistantId] │ │ │ │ │ ├── MarkdownProvider │ │ │ │ │ ├── Code.tsx │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Menu.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ └── page.tsx │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ └── lib │ │ │ └── assistants.ts │ └── tsconfig.json ├── next │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── next.config.mjs │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── next.svg │ │ └── vercel.svg │ ├── src │ │ └── app │ │ │ ├── api │ │ │ └── openai │ │ │ │ └── route.ts │ │ │ ├── assistant-provider │ │ │ └── page.tsx │ │ │ ├── avatars │ │ │ └── page.tsx │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ ├── page.tsx │ │ │ ├── reset-thread │ │ │ └── page.tsx │ │ │ ├── suggestions │ │ │ ├── MarkdownProvider │ │ │ │ ├── Code.tsx │ │ │ │ └── index.tsx │ │ │ └── page.tsx │ │ │ └── videos │ │ │ ├── MarkdownProvider │ │ │ ├── Link.tsx │ │ │ └── index.tsx │ │ │ └── page.tsx │ └── tsconfig.json ├── standalone │ ├── README.md │ ├── example.html │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── src │ │ ├── AudioThread.tsx │ │ ├── AudioThreadDialog.tsx │ │ ├── Thread.tsx │ │ ├── ThreadDialog.tsx │ │ └── components │ │ │ └── Providers │ │ │ ├── components │ │ │ └── index.tsx │ │ │ ├── index.tsx │ │ │ ├── reset.css │ │ │ └── styles.css │ ├── tsconfig.json │ └── tsup.config.ts └── vite-react-ts │ ├── .gitignore │ ├── README.md │ ├── eslint.config.js │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── public │ └── vite.svg │ ├── src │ ├── App.tsx │ ├── assets │ │ └── react.svg │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── package-lock.json ├── package.json ├── packages ├── javascript │ ├── package.json │ ├── postcss.config.js │ ├── src │ │ ├── AudioThread.tsx │ │ ├── AudioThreadDialog.tsx │ │ ├── AudioThreadDialogWebrtcAudioRuntime.tsx │ │ ├── AudioThreadWebrtcAudioRuntime.tsx │ │ ├── Thread.tsx │ │ ├── ThreadAnnotationsComponentDisabled.tsx │ │ ├── ThreadAnnotationsComponentSource.tsx │ │ ├── ThreadDialog.tsx │ │ ├── ThreadDialogAnnotationsComponentDisabled.tsx │ │ ├── ThreadDialogAnnotationsComponentSource.tsx │ │ ├── ThreadDialogFilesEnabled.tsx │ │ ├── ThreadDialogFilesEnabledAnnotationsComponentDisabled.tsx │ │ ├── ThreadDialogFilesEnabledAnnotationsComponentSource.tsx │ │ ├── ThreadFilesEnabled.tsx │ │ ├── ThreadFilesEnabledAnnotationsComponentDisabled.tsx │ │ ├── ThreadFilesEnabledAnnotationsComponentSource.tsx │ │ ├── components │ │ │ └── Providers │ │ │ │ ├── ThemeProvider.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── reset.css │ │ │ │ └── styles.css │ │ └── lib │ │ │ └── superinterfaceContext │ │ │ ├── currentScriptSuperinterfaceContext.ts │ │ │ ├── index.ts │ │ │ ├── isValidSuperinterfaceContext.ts │ │ │ └── windowSuperinterfaceContext.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── react │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── annotations │ │ │ │ ├── FilePathAnnotation.tsx │ │ │ │ └── SourceAnnotation │ │ │ │ │ ├── FileCitation │ │ │ │ │ ├── Content.tsx │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ ├── assistants │ │ │ │ └── AssistantProvider │ │ │ │ │ ├── Code.tsx │ │ │ │ │ └── index.tsx │ │ │ ├── audioRuntimes │ │ │ │ ├── TtsAudioRuntimeProvider.tsx │ │ │ │ └── WebrtcAudioRuntimeProvider.tsx │ │ │ ├── avatars │ │ │ │ └── Avatar.tsx │ │ │ ├── components │ │ │ │ └── ComponentsProvider.tsx │ │ │ ├── contents │ │ │ │ ├── ImageFileContent.tsx │ │ │ │ └── TextContent.tsx │ │ │ ├── core │ │ │ │ └── SuperinterfaceProvider │ │ │ │ │ └── index.tsx │ │ │ ├── functions │ │ │ │ ├── Function │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── lib │ │ │ │ │ │ └── title.ts │ │ │ │ └── FunctionBase │ │ │ │ │ ├── Content │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── lib │ │ │ │ │ │ └── formattedJsonOrRaw.ts │ │ │ │ │ ├── Icon.tsx │ │ │ │ │ └── index.tsx │ │ │ ├── iconAvatars │ │ │ │ └── IconAvatar.tsx │ │ │ ├── imageAvatars │ │ │ │ └── ImageAvatar │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── lib │ │ │ │ │ └── optimizedSrc │ │ │ │ │ ├── host.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── path.ts │ │ │ ├── images │ │ │ │ └── Image.tsx │ │ │ ├── markdown │ │ │ │ └── MarkdownProvider │ │ │ │ │ └── index.tsx │ │ │ ├── media │ │ │ │ ├── MediaContainer.tsx │ │ │ │ ├── PlayButton.tsx │ │ │ │ ├── Time.tsx │ │ │ │ └── VolumeButton.tsx │ │ │ ├── messageGroups │ │ │ │ └── MessageGroup │ │ │ │ │ ├── AssistantAvatar.tsx │ │ │ │ │ ├── Messages.tsx │ │ │ │ │ ├── Name.tsx │ │ │ │ │ ├── Root.tsx │ │ │ │ │ ├── UserAvatar.tsx │ │ │ │ │ └── index.tsx │ │ │ ├── messages │ │ │ │ ├── MessageAttachments.tsx │ │ │ │ └── MessageContent │ │ │ │ │ ├── ContentPart │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ ├── runSteps │ │ │ │ ├── RunStep │ │ │ │ │ ├── ToolCalls │ │ │ │ │ │ ├── ToolCall │ │ │ │ │ │ │ ├── CodeInterpreter.tsx │ │ │ │ │ │ │ ├── Fallback.tsx │ │ │ │ │ │ │ ├── FileSearch.tsx │ │ │ │ │ │ │ ├── Fn.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ │ └── RunSteps │ │ │ │ │ └── index.tsx │ │ │ ├── skeletons │ │ │ │ ├── MessagesSkeleton │ │ │ │ │ └── index.tsx │ │ │ │ ├── StartingContentSkeleton │ │ │ │ │ └── index.tsx │ │ │ │ └── StartingSkeleton │ │ │ │ │ └── index.tsx │ │ │ ├── suggestions │ │ │ │ └── Suggestions │ │ │ │ │ ├── Content.tsx │ │ │ │ │ ├── Item.tsx │ │ │ │ │ └── index.tsx │ │ │ ├── textareas │ │ │ │ └── TextareaBase │ │ │ │ │ └── index.tsx │ │ │ ├── threads │ │ │ │ ├── AudioThread │ │ │ │ │ ├── BarsVisualizer │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Form │ │ │ │ │ │ ├── ActionButton │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── MicIcon.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Root │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Status │ │ │ │ │ │ ├── StatusMessages.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Visualization │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── AudioThreadDialog │ │ │ │ │ └── index.tsx │ │ │ │ ├── Thread │ │ │ │ │ ├── Message │ │ │ │ │ │ ├── Attachments │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── Provider.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── MessageForm │ │ │ │ │ │ ├── Field │ │ │ │ │ │ │ ├── Control.tsx │ │ │ │ │ │ │ ├── Files │ │ │ │ │ │ │ │ ├── Control.tsx │ │ │ │ │ │ │ │ ├── Preview.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── Root │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── lib │ │ │ │ │ │ │ │ └── formOptions.ts │ │ │ │ │ │ ├── Submit │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Messages │ │ │ │ │ │ ├── Content │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── NextPageSkeleton.tsx │ │ │ │ │ │ ├── Progress │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── Root │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Provider │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Root │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ │ └── ThreadDialog │ │ │ │ │ ├── Close │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Content │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Provider │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Root │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Trigger │ │ │ │ │ ├── Button.tsx │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ ├── toasts │ │ │ │ └── ToastsProvider │ │ │ │ │ ├── CustomToast.tsx │ │ │ │ │ └── index.tsx │ │ │ └── toolCalls │ │ │ │ ├── CodeInterpreterToolCall.tsx │ │ │ │ ├── FallbackToolCall.tsx │ │ │ │ ├── FileSearchToolCall.tsx │ │ │ │ ├── StartingToolCalls.tsx │ │ │ │ └── ToolCallBase │ │ │ │ ├── ToolCallIcon.tsx │ │ │ │ ├── ToolCallTitle.tsx │ │ │ │ └── index.tsx │ │ ├── contexts │ │ │ ├── assistants │ │ │ │ ├── AssistantAvatarContext │ │ │ │ │ └── index.tsx │ │ │ │ └── AssistantNameContext │ │ │ │ │ └── index.tsx │ │ │ ├── components │ │ │ │ └── ComponentsContext │ │ │ │ │ └── index.tsx │ │ │ ├── core │ │ │ │ └── SuperinterfaceContext │ │ │ │ │ └── index.tsx │ │ │ ├── functions │ │ │ │ └── FunctionComponentsContext │ │ │ │ │ └── index.tsx │ │ │ ├── markdown │ │ │ │ └── MarkdownContext │ │ │ │ │ ├── index.ts │ │ │ │ │ └── lib │ │ │ │ │ ├── components │ │ │ │ │ ├── Annotation │ │ │ │ │ │ ├── AnnotationBase.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Code.tsx │ │ │ │ │ ├── Img │ │ │ │ │ │ ├── Audio │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── Video │ │ │ │ │ │ │ ├── FullscreenButton.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── lib │ │ │ │ │ │ │ ├── isAudioSrc.ts │ │ │ │ │ │ │ └── isVideoSrc.ts │ │ │ │ │ ├── Link.tsx │ │ │ │ │ ├── ListItem.tsx │ │ │ │ │ ├── OrderedList.tsx │ │ │ │ │ ├── Paragraph.tsx │ │ │ │ │ ├── Pre.tsx │ │ │ │ │ ├── Strong.tsx │ │ │ │ │ ├── UnorderedList.tsx │ │ │ │ │ └── index.tsx │ │ │ │ │ └── getRemarkPlugins.ts │ │ │ ├── messages │ │ │ │ ├── MessageContext │ │ │ │ │ └── index.ts │ │ │ │ └── MessageFormContext │ │ │ │ │ └── index.ts │ │ │ ├── threads │ │ │ │ ├── AudioThreadContext │ │ │ │ │ └── index.ts │ │ │ │ └── ThreadDialogContext │ │ │ │ │ └── index.ts │ │ │ ├── toasts │ │ │ │ └── ToastsContext │ │ │ │ │ └── index.ts │ │ │ └── users │ │ │ │ └── UserAvatarContext │ │ │ │ └── index.tsx │ │ ├── hooks │ │ │ ├── assistants │ │ │ │ └── useAssistant │ │ │ │ │ ├── index.ts │ │ │ │ │ └── lib │ │ │ │ │ └── queryOptions │ │ │ │ │ ├── index.ts │ │ │ │ │ └── queryFn.ts │ │ │ ├── audioRuntimes │ │ │ │ ├── useTtsAudioRuntime │ │ │ │ │ ├── blobToData.ts │ │ │ │ │ └── index.ts │ │ │ │ └── useWebrtcAudioRuntime │ │ │ │ │ └── index.ts │ │ │ ├── audioThreads │ │ │ │ ├── useMessageAudio │ │ │ │ │ ├── index.ts │ │ │ │ │ └── lib │ │ │ │ │ │ ├── input.ts │ │ │ │ │ │ └── isHtmlAudioSupported.ts │ │ │ │ ├── useRecorder │ │ │ │ │ └── index.ts │ │ │ │ └── useStatus │ │ │ │ │ ├── index.ts │ │ │ │ │ └── lib │ │ │ │ │ └── statusMessages.ts │ │ │ ├── components │ │ │ │ └── useComponents.ts │ │ │ ├── core │ │ │ │ └── useSuperinterfaceContext │ │ │ │ │ └── index.ts │ │ │ ├── files │ │ │ │ └── useCreateFile │ │ │ │ │ ├── index.ts │ │ │ │ │ └── lib │ │ │ │ │ └── mutationOptions │ │ │ │ │ ├── index.ts │ │ │ │ │ └── mutationFn │ │ │ │ │ ├── body │ │ │ │ │ ├── formData.ts │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ ├── markdown │ │ │ │ └── useMarkdownContext │ │ │ │ │ └── index.ts │ │ │ ├── messageGroups │ │ │ │ └── useMessageGroups │ │ │ │ │ ├── index.ts │ │ │ │ │ └── lib │ │ │ │ │ └── messageGroups │ │ │ │ │ ├── index.ts │ │ │ │ │ └── newGroup │ │ │ │ │ ├── index.ts │ │ │ │ │ └── newGroupItem.ts │ │ │ ├── messages │ │ │ │ ├── useCreateMessage │ │ │ │ │ ├── index.ts │ │ │ │ │ └── lib │ │ │ │ │ │ └── mutationOptions │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── mutationFn │ │ │ │ │ │ ├── body.ts │ │ │ │ │ │ ├── handleResponse │ │ │ │ │ │ │ ├── handlers │ │ │ │ │ │ │ │ ├── extendMessage.ts │ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ │ ├── threadCreated.ts │ │ │ │ │ │ │ │ ├── threadMessageCompleted.ts │ │ │ │ │ │ │ │ ├── threadMessageCreated.ts │ │ │ │ │ │ │ │ ├── threadMessageDelta.ts │ │ │ │ │ │ │ │ ├── threadRunCreated.ts │ │ │ │ │ │ │ │ ├── threadRunFailed.ts │ │ │ │ │ │ │ │ ├── threadRunRequiresAction.ts │ │ │ │ │ │ │ │ ├── threadRunStepCompleted.ts │ │ │ │ │ │ │ │ ├── threadRunStepCreated.ts │ │ │ │ │ │ │ │ └── threadRunStepDelta.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── onMutate │ │ │ │ │ │ ├── data.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── useIsMutatingMessage │ │ │ │ │ └── index.ts │ │ │ │ ├── useLatestMessage │ │ │ │ │ └── index.ts │ │ │ │ ├── useMessageContext │ │ │ │ │ └── index.ts │ │ │ │ ├── useMessageFormContext │ │ │ │ │ └── index.ts │ │ │ │ └── useMessages │ │ │ │ │ └── index.tsx │ │ │ ├── misc │ │ │ │ ├── useInfiniteScroll │ │ │ │ │ └── index.tsx │ │ │ │ ├── useInterval.ts │ │ │ │ ├── usePermission │ │ │ │ │ ├── index.ts │ │ │ │ │ └── util.ts │ │ │ │ ├── usePrevious.ts │ │ │ │ └── useThrottledEffect │ │ │ │ │ └── index.tsx │ │ │ ├── threads │ │ │ │ ├── useAudioThreadContext │ │ │ │ │ └── index.ts │ │ │ │ ├── useThreadContext │ │ │ │ │ └── index.ts │ │ │ │ └── useThreadDialogContext │ │ │ │ │ └── index.ts │ │ │ └── toasts │ │ │ │ └── useToasts │ │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── lib │ │ │ ├── ai │ │ │ │ └── index.ts │ │ │ ├── enums │ │ │ │ └── index.ts │ │ │ ├── errors │ │ │ │ └── createMessageDefaultOnError.ts │ │ │ ├── iconAvatars │ │ │ │ └── iconAvatarComponents.ts │ │ │ ├── iframes │ │ │ │ └── isIframe.ts │ │ │ ├── markdown │ │ │ │ └── escapeInvalidTagNames.ts │ │ │ ├── messages │ │ │ │ ├── createMessageResponse │ │ │ │ │ ├── actionsStream.ts │ │ │ │ │ ├── handleStream.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── extendMessage.ts │ │ │ │ ├── messagesQueryOptions.ts │ │ │ │ ├── messagesResponse │ │ │ │ │ ├── data │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── messages │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── runMessages │ │ │ │ │ │ │ ├── getLatestRun.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── hasNextPage.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── limit.ts │ │ │ │ ├── order.ts │ │ │ │ └── serializeMessage.ts │ │ │ ├── misc │ │ │ │ └── merge │ │ │ │ │ ├── customizer.ts │ │ │ │ │ └── index.ts │ │ │ ├── optimistic │ │ │ │ ├── isOptimistic.ts │ │ │ │ └── optimisticId.ts │ │ │ ├── recma │ │ │ │ └── recmaFallbackComponentPlugin.ts │ │ │ ├── remark │ │ │ │ ├── remarkAnnotation.ts │ │ │ │ └── remarkPureLiteralPlugin.ts │ │ │ ├── runSteps │ │ │ │ ├── getRunSteps │ │ │ │ │ └── index.ts │ │ │ │ └── serializeRunStep.ts │ │ │ ├── runs │ │ │ │ └── serializeRun.ts │ │ │ ├── streams │ │ │ │ └── enqueueJson.ts │ │ │ ├── superinterfaceCloud │ │ │ │ └── baseUrl.ts │ │ │ ├── threadIdStorage │ │ │ │ ├── cookieOptions │ │ │ │ │ ├── get.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── remove.ts │ │ │ │ │ └── set.ts │ │ │ │ ├── key.ts │ │ │ │ └── localStorageOptions │ │ │ │ │ ├── get.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── remove.ts │ │ │ │ │ └── set.ts │ │ │ └── threads │ │ │ │ └── queryOptions │ │ │ │ ├── index.ts │ │ │ │ └── variableParams.ts │ │ ├── server.ts │ │ ├── types │ │ │ └── index.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── tsup.config.ts └── root-element │ ├── package.json │ ├── src │ ├── index.ts │ └── lib │ │ └── rootElement │ │ ├── index.ts │ │ ├── manualElement.ts │ │ └── scriptTagId.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── tsconfig.json └── turbo.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .turbo 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Supercorp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Superinterface](https://superinterface.ai/opengraph-image.png?06e0509e551c6593) 2 | 3 | # Superinterface 4 | 5 | Superinterface is an AI assistants library for building AI capabilities into your app or website. 6 | You use React components and hooks to build AI-first assistants-based interfaces like chats and wizards. 7 | 8 | **Docs are in the process of being written.** 9 | 10 | More info about the project: https://superinterface.ai 11 | 12 | Examples are hosted here: https://examples-next.superinterface.ai (see code [here](https://github.com/supercorp-ai/superinterface/tree/main/examples/next)) 13 | -------------------------------------------------------------------------------- /examples/iframe/cloudflared-config.yml: -------------------------------------------------------------------------------- 1 | tunnel: 7171dd8d-9e40-45e0-93a8-40f2ca04ecc1 2 | credentials-file: /Users/domas/.cloudflared/7171dd8d-9e40-45e0-93a8-40f2ca04ecc1.json 3 | warp-routing: 4 | enabled: true 5 | ingress: 6 | - hostname: superinterface-examples-iframe.supercorp.ai 7 | service: http://localhost:3006 8 | - service: http_status:404 9 | -------------------------------------------------------------------------------- /examples/iframe/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@superinterface/iframe-example", 3 | "version": "1.0.0", 4 | "keywords": [], 5 | "license": "ISC", 6 | "scripts": { 7 | "serve": "npx serve . -p 3006", 8 | "tunnel": "cloudflared tunnel --config cloudflared-config.yml run" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/javascript/build.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 13 | 14 | 15 | Hello JavaScript build! 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/javascript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@superinterface/javascript-example", 3 | "version": "1.0.0", 4 | "keywords": [], 5 | "license": "ISC", 6 | "scripts": { 7 | "serve": "npx serve . -p 3006" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/javascript/script-tag-v2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 17 | 18 | 19 | Hello JavaScript v2! 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/next-frontend-functions/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /examples/next-frontend-functions/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /examples/next-frontend-functions/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /examples/next-frontend-functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@superinterface/react": "file:../../packages/react", 13 | "@tanstack/react-query": "file:../../packages/react/node_modules/@tanstack/react-query", 14 | "next": "14.2.5", 15 | "react": "^18", 16 | "react-dom": "^18" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^20", 20 | "@types/react": "^18", 21 | "@types/react-dom": "^18", 22 | "eslint": "^8", 23 | "eslint-config-next": "14.2.5", 24 | "typescript": "^5" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/next-frontend-functions/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/next-frontend-functions/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/next-frontend-functions/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supercorp-ai/superinterface/70b16812be1d48622c52768d9269190caa826df8/examples/next-frontend-functions/src/app/favicon.ico -------------------------------------------------------------------------------- /examples/next-frontend-functions/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Inter } from "next/font/google"; 3 | import "./globals.css"; 4 | 5 | const inter = Inter({ subsets: ["latin"] }); 6 | 7 | export const metadata: Metadata = { 8 | title: "Create Next App", 9 | description: "Generated by create next app", 10 | }; 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: Readonly<{ 15 | children: React.ReactNode; 16 | }>) { 17 | return ( 18 | 19 | {children} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /examples/next-frontend-functions/src/app/suggestions/MarkdownProvider/Code.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import { 3 | useMarkdownContext, 4 | useMessageContext, 5 | Suggestions, 6 | } from '@superinterface/react' 7 | 8 | export const Code = ({ 9 | children, 10 | className, 11 | markdownContext, 12 | }: { 13 | children: string, 14 | className: string, 15 | markdownContext: ReturnType 16 | }) => { 17 | const messageContext = useMessageContext() 18 | 19 | const isAssistantMessage = useMemo(() => ( 20 | messageContext.message?.role === 'assistant' 21 | ), [messageContext]) 22 | 23 | if (!isAssistantMessage || className !== 'language-suggestions') { 24 | return markdownContext.components.code({ children, className }) 25 | } 26 | 27 | return {children} 28 | } 29 | -------------------------------------------------------------------------------- /examples/next-frontend-functions/src/app/suggestions/MarkdownProvider/index.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import { 3 | MarkdownProvider as SuperinterfaceMarkdownProvider, 4 | useMarkdownContext, 5 | } from '@superinterface/react' 6 | import { Code } from './Code' 7 | 8 | type Args = { 9 | children: React.ReactNode 10 | } 11 | 12 | export const MarkdownProvider = ({ 13 | children, 14 | }: Args) => { 15 | const markdownContext = useMarkdownContext() 16 | 17 | const components = useMemo(() => ({ 18 | code: (props: JSX.IntrinsicElements['code']) => ( 19 | // @ts-ignore-next-line 20 | 24 | ), 25 | }), [markdownContext]) 26 | 27 | return ( 28 | 32 | {children} 33 | 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /examples/next-frontend-functions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "next/typescript"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-multi-assistant", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@radix-ui/themes": "^3.1.3", 13 | "@superinterface/react": "^2.19.3", 14 | "@tanstack/react-query": "^5.54.1", 15 | "next": "14.2.8", 16 | "react": "^18", 17 | "react-dom": "^18" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^20", 21 | "@types/react": "^18", 22 | "@types/react-dom": "^18", 23 | "eslint": "^8", 24 | "eslint-config-next": "14.2.8", 25 | "typescript": "^5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/src/app/assistants/[assistantId]/MarkdownProvider/Code.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import { 3 | useMarkdownContext, 4 | useMessageContext, 5 | Suggestions, 6 | } from '@superinterface/react' 7 | 8 | export const Code = ({ 9 | children, 10 | className, 11 | markdownContext, 12 | }: { 13 | children: string, 14 | className: string, 15 | markdownContext: ReturnType 16 | }) => { 17 | const messageContext = useMessageContext() 18 | 19 | const isAssistantMessage = useMemo(() => ( 20 | messageContext.message?.role === 'assistant' 21 | ), [messageContext]) 22 | 23 | if (!isAssistantMessage || className !== 'language-suggestions') { 24 | return markdownContext.components.code({ children, className }) 25 | } 26 | 27 | return {children} 28 | } 29 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/src/app/assistants/[assistantId]/MarkdownProvider/index.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import { 3 | MarkdownProvider as SuperinterfaceMarkdownProvider, 4 | useMarkdownContext, 5 | } from '@superinterface/react' 6 | import { Code } from './Code' 7 | 8 | type Args = { 9 | children: React.ReactNode 10 | } 11 | 12 | export const MarkdownProvider = ({ 13 | children, 14 | }: Args) => { 15 | const markdownContext = useMarkdownContext() 16 | 17 | const components = useMemo(() => ({ 18 | code: (props: JSX.IntrinsicElements['code']) => ( 19 | // @ts-expect-error broad types 20 | 24 | ), 25 | }), [markdownContext]) 26 | 27 | return ( 28 | 32 | {children} 33 | 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/src/app/assistants/[assistantId]/Menu.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | import { 3 | Flex, 4 | Text, 5 | Card, 6 | } from '@radix-ui/themes' 7 | import { assistants } from '@/lib/assistants' 8 | 9 | const Item = ({ 10 | assistant, 11 | }: { 12 | assistant: { 13 | id: string 14 | name: string 15 | }, 16 | }) => ( 17 | 21 | 25 | 29 | 34 | {assistant.name} 35 | 36 | 37 | 38 | 39 | ) 40 | 41 | export const Menu = () => ( 42 | 54 | {assistants.map((assistant) => ( 55 | 59 | ))} 60 | 61 | ) 62 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supercorp-ai/superinterface/70b16812be1d48622c52768d9269190caa826df8/examples/next-multi-assistant/src/app/favicon.ico -------------------------------------------------------------------------------- /examples/next-multi-assistant/src/app/globals.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Arial, Helvetica, sans-serif; 3 | -webkit-font-smoothing: antialiased; 4 | -moz-osx-font-smoothing: grayscale; 5 | } 6 | 7 | * { 8 | box-sizing: border-box; 9 | padding: 0; 10 | margin: 0; 11 | } 12 | 13 | a { 14 | color: inherit; 15 | text-decoration: none; 16 | } 17 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | import { Inter } from 'next/font/google' 3 | import './globals.css' 4 | import '@radix-ui/themes/styles.css' 5 | 6 | const inter = Inter({ subsets: ['latin'] }) 7 | 8 | export const metadata: Metadata = { 9 | title: 'Create Next App', 10 | description: 'Generated by create next app', 11 | } 12 | 13 | export default function RootLayout({ 14 | children, 15 | }: Readonly<{ 16 | children: React.ReactNode 17 | }>) { 18 | return ( 19 | 20 | 21 | {children} 22 | 23 | 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation' 2 | import { assistants } from '@/lib/assistants' 3 | 4 | export default function Page() { 5 | redirect(`/assistants/${assistants[0].id}`) 6 | } 7 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/src/lib/assistants.ts: -------------------------------------------------------------------------------- 1 | export const assistants = [ 2 | { 3 | id: '26518c2b-07e4-44a7-bc62-36b0b3922bc7', 4 | name: 'Next Example Assistant', 5 | }, 6 | { 7 | id: '1bcb2f56-6aa5-41bd-8e71-e077331520ce', 8 | name: 'Next Example Suggestions Assistant', 9 | }, 10 | ] 11 | -------------------------------------------------------------------------------- /examples/next-multi-assistant/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /examples/next/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /examples/next/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | .env 38 | -------------------------------------------------------------------------------- /examples/next/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /examples/next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@superinterface/react": "^2.25.2", 13 | "@tanstack/react-query": "^5.59.20", 14 | "js-cookie": "^3.0.5", 15 | "next": "14.2.5", 16 | "react": "^18", 17 | "react-dom": "^18" 18 | }, 19 | "devDependencies": { 20 | "@types/js-cookie": "^3.0.6", 21 | "@types/node": "^20", 22 | "@types/react": "^18", 23 | "@types/react-dom": "^18", 24 | "eslint": "^8", 25 | "eslint-config-next": "14.2.5", 26 | "typescript": "^5" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/next/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/next/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/next/src/app/api/openai/route.ts: -------------------------------------------------------------------------------- 1 | import { type NextRequest, NextResponse } from 'next/server' 2 | import OpenAI from 'openai' 3 | import { 4 | messagesResponse, 5 | } from '@superinterface/react/server' 6 | 7 | export const GET = async () => { 8 | try { 9 | const client = new OpenAI({ 10 | apiKey: 'sk-proj-11111111111111111111', 11 | }) 12 | 13 | const pageParam = null 14 | 15 | const r = await messagesResponse({ 16 | threadId: 'thread_BWZSFgxf4o7x1psewUjwhitt', 17 | client, 18 | ...(pageParam ? { pageParam } : {}), 19 | }) 20 | 21 | return NextResponse.json(r) 22 | } catch (e) { 23 | return NextResponse.json({ 24 | error: 'Provide a valid API key', 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/next/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supercorp-ai/superinterface/70b16812be1d48622c52768d9269190caa826df8/examples/next/src/app/favicon.ico -------------------------------------------------------------------------------- /examples/next/src/app/globals.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | padding: 0; 4 | margin: 0; 5 | } 6 | -------------------------------------------------------------------------------- /examples/next/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Inter } from "next/font/google"; 3 | import "./globals.css"; 4 | 5 | const inter = Inter({ subsets: ["latin"] }); 6 | 7 | export const metadata: Metadata = { 8 | title: "Create Next App", 9 | description: "Generated by create next app", 10 | }; 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: Readonly<{ 15 | children: React.ReactNode; 16 | }>) { 17 | return ( 18 | 19 | {children} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /examples/next/src/app/suggestions/MarkdownProvider/Code.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import { 3 | useMarkdownContext, 4 | useMessageContext, 5 | Suggestions, 6 | } from '@superinterface/react' 7 | 8 | export const Code = ({ 9 | children, 10 | className, 11 | markdownContext, 12 | }: { 13 | children: string, 14 | className: string, 15 | markdownContext: ReturnType 16 | }) => { 17 | const messageContext = useMessageContext() 18 | 19 | const isAssistantMessage = useMemo(() => ( 20 | messageContext.message?.role === 'assistant' 21 | ), [messageContext]) 22 | 23 | if (!isAssistantMessage || className !== 'language-suggestions') { 24 | return markdownContext.components.code({ children, className }) 25 | } 26 | 27 | return {children} 28 | } 29 | -------------------------------------------------------------------------------- /examples/next/src/app/suggestions/MarkdownProvider/index.tsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import { 3 | MarkdownProvider as SuperinterfaceMarkdownProvider, 4 | useMarkdownContext, 5 | } from '@superinterface/react' 6 | import { Code } from './Code' 7 | 8 | type Args = { 9 | children: React.ReactNode 10 | } 11 | 12 | export const MarkdownProvider = ({ 13 | children, 14 | }: Args) => { 15 | const markdownContext = useMarkdownContext() 16 | 17 | const components = useMemo(() => ({ 18 | code: (props: JSX.IntrinsicElements['code']) => ( 19 | // @ts-ignore-next-line 20 | 24 | ), 25 | }), [markdownContext]) 26 | 27 | return ( 28 | 32 | {children} 33 | 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /examples/next/src/app/videos/MarkdownProvider/Link.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | useMarkdownContext, 3 | } from '@superinterface/react' 4 | 5 | const isYoutube = ({ url }: { url: string }): boolean => { 6 | try { 7 | const parsedUrl = new URL(url) 8 | return parsedUrl.hostname === 'www.youtube.com' || parsedUrl.hostname === 'youtube.com' || parsedUrl.hostname === 'youtu.be' 9 | } catch (e) { 10 | return false 11 | } 12 | } 13 | 14 | 15 | export const Link = ({ 16 | children, 17 | href, 18 | markdownContext, 19 | }: { 20 | children?: React.ReactNode, 21 | href?: string, 22 | markdownContext: ReturnType 23 | }) => { 24 | if (!href || !isYoutube({ url: href })) { 25 | return markdownContext.components.a({ children, href }) 26 | } 27 | 28 | return ( 29 |