diff --git a/web/.env.example b/web/.env.example index 13ea01a2c7..4316bc76ea 100644 --- a/web/.env.example +++ b/web/.env.example @@ -10,6 +10,8 @@ NEXT_PUBLIC_API_PREFIX=http://localhost:5001/console/api # console or api domain. # example: http://udify.app/api NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api +# The URL for MARKETPLACE +NEXT_PUBLIC_MARKETPLACE_API_PREFIX=http://localhost:5002/api # SENTRY NEXT_PUBLIC_SENTRY_DSN= diff --git a/web/app/components/plugins/plugin-page/index.tsx b/web/app/components/plugins/plugin-page/index.tsx index fc15fdc81a..80492d0c18 100644 --- a/web/app/components/plugins/plugin-page/index.tsx +++ b/web/app/components/plugins/plugin-page/index.tsx @@ -30,12 +30,12 @@ import { useSearchParams, } from 'next/navigation' import type { PluginDeclaration } from '../types' -import { toolNotionManifest } from '../card/card-mock' import { sleep } from '@/utils' +import { fetchManifestFromMarketPlace } from '@/service/plugins' const PACKAGE_IDS_KEY = 'package-ids' -export interface PluginPageProps { +export type PluginPageProps = { plugins: React.ReactNode marketplace: React.ReactNode } @@ -74,10 +74,9 @@ const PluginPage = ({ (async () => { await sleep(100) if (packageId) { - // setManifest(toolNotionManifest) - // TODO - // const data = await fetchManifest(encodeURIComponent(packageId)) - setManifest(toolNotionManifest) + const data = await fetchManifestFromMarketPlace(encodeURIComponent(packageId)) + // wait for add cors + setManifest(data) showInstallFromMarketplace() } })() diff --git a/web/app/layout.tsx b/web/app/layout.tsx index 48e35c50e0..ec68790677 100644 --- a/web/app/layout.tsx +++ b/web/app/layout.tsx @@ -37,6 +37,7 @@ const LocaleLayout = ({ className="h-full select-auto" data-api-prefix={process.env.NEXT_PUBLIC_API_PREFIX} data-pubic-api-prefix={process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX} + data-marketplace-api-prefix={process.env.NEXT_PUBLIC_MARKETPLACE_API_PREFIX} data-public-edition={process.env.NEXT_PUBLIC_EDITION} data-public-support-mail-login={process.env.NEXT_PUBLIC_SUPPORT_MAIL_LOGIN} data-public-sentry-dsn={process.env.NEXT_PUBLIC_SENTRY_DSN} diff --git a/web/config/index.ts b/web/config/index.ts index 9eb4889441..3492fbe991 100644 --- a/web/config/index.ts +++ b/web/config/index.ts @@ -1,23 +1,26 @@ -/* eslint-disable import/no-mutable-exports */ import { InputVarType } from '@/app/components/workflow/types' import { AgentStrategy } from '@/types/app' import { PromptRole } from '@/models/debug' export let apiPrefix = '' export let publicApiPrefix = '' +export let marketplaceApiPrefix = '' // NEXT_PUBLIC_API_PREFIX=/console/api NEXT_PUBLIC_PUBLIC_API_PREFIX=/api npm run start -if (process.env.NEXT_PUBLIC_API_PREFIX && process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX) { +if (process.env.NEXT_PUBLIC_API_PREFIX && process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX && process.env.NEXT_PUBLIC_MARKETPLACE_API_PREFIX) { apiPrefix = process.env.NEXT_PUBLIC_API_PREFIX publicApiPrefix = process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX + marketplaceApiPrefix = process.env.NEXT_PUBLIC_MARKETPLACE_API_PREFIX } else if ( globalThis.document?.body?.getAttribute('data-api-prefix') && globalThis.document?.body?.getAttribute('data-pubic-api-prefix') + && globalThis.document?.body?.getAttribute('data-marketplace-api-prefix') ) { // Not build can not get env from process.env.NEXT_PUBLIC_ in browser https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser apiPrefix = globalThis.document.body.getAttribute('data-api-prefix') as string publicApiPrefix = globalThis.document.body.getAttribute('data-pubic-api-prefix') as string + marketplaceApiPrefix = globalThis.document.body.getAttribute('data-marketplace-api-prefix') as string } else { // const domainParts = globalThis.location?.host?.split('.'); @@ -25,10 +28,12 @@ else { // const env = domainParts.length === 2 ? 'ai' : domainParts?.[0]; apiPrefix = 'http://localhost:5001/console/api' publicApiPrefix = 'http://localhost:5001/api' // avoid browser private mode api cross origin + marketplaceApiPrefix = 'http://localhost:5002/api' } export const API_PREFIX: string = apiPrefix export const PUBLIC_API_PREFIX: string = publicApiPrefix +export const MARKETPLACE_API_PREFIX: string = marketplaceApiPrefix const EDITION = process.env.NEXT_PUBLIC_EDITION || globalThis.document?.body?.getAttribute('data-public-edition') || 'SELF_HOSTED' export const IS_CE_EDITION = EDITION === 'SELF_HOSTED' @@ -251,9 +256,9 @@ export const resetReg = () => VAR_REGEX.lastIndex = 0 export let textGenerationTimeoutMs = 60000 if (process.env.NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS && process.env.NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS !== '') - textGenerationTimeoutMs = parseInt(process.env.NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS) + textGenerationTimeoutMs = Number.parseInt(process.env.NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS) else if (globalThis.document?.body?.getAttribute('data-public-text-generation-timeout-ms') && globalThis.document.body.getAttribute('data-public-text-generation-timeout-ms') !== '') - textGenerationTimeoutMs = parseInt(globalThis.document.body.getAttribute('data-public-text-generation-timeout-ms') as string) + textGenerationTimeoutMs = Number.parseInt(globalThis.document.body.getAttribute('data-public-text-generation-timeout-ms') as string) export const TEXT_GENERATION_TIMEOUT_MS = textGenerationTimeoutMs diff --git a/web/service/base.ts b/web/service/base.ts index f43a23df52..f90e3ef1b1 100644 --- a/web/service/base.ts +++ b/web/service/base.ts @@ -1,4 +1,4 @@ -import { API_PREFIX, IS_CE_EDITION, PUBLIC_API_PREFIX } from '@/config' +import { API_PREFIX, IS_CE_EDITION, MARKETPLACE_API_PREFIX, PUBLIC_API_PREFIX } from '@/config' import Toast from '@/app/components/base/toast' import type { AnnotationReply, MessageEnd, MessageReplace, ThoughtItem } from '@/app/components/base/chat/chat/type' import type { VisionFile } from '@/types/app' @@ -70,6 +70,7 @@ export type IOnTextReplace = (textReplace: TextReplaceResponse) => void export type IOtherOptions = { isPublicAPI?: boolean + isMarketplaceAPI?: boolean bodyStringify?: boolean needAllResponseContent?: boolean deleteContentType?: boolean @@ -114,7 +115,7 @@ function unicodeToChar(text: string) { return '' return text.replace(/\\u[0-9a-f]{4}/g, (_match, p1) => { - return String.fromCharCode(parseInt(p1, 16)) + return String.fromCharCode(Number.parseInt(p1, 16)) }) } @@ -280,6 +281,7 @@ const baseFetch = ( fetchOptions: FetchOptionType, { isPublicAPI = false, + isMarketplaceAPI = false, bodyStringify = true, needAllResponseContent, deleteContentType, @@ -305,7 +307,7 @@ const baseFetch = ( } options.headers.set('Authorization', `Bearer ${accessTokenJson[sharedToken]}`) } - else { + else if (!isMarketplaceAPI) { const accessToken = localStorage.getItem('console_token') || '' options.headers.set('Authorization', `Bearer ${accessToken}`) } @@ -319,7 +321,13 @@ const baseFetch = ( options.headers.set('Content-Type', ContentType.json) } - const urlPrefix = isPublicAPI ? PUBLIC_API_PREFIX : API_PREFIX + const urlPrefix = (() => { + if (isMarketplaceAPI) + return MARKETPLACE_API_PREFIX + if (isPublicAPI) + return PUBLIC_API_PREFIX + return API_PREFIX + })() let urlWithPrefix = `${urlPrefix}${url.startsWith('/') ? url : `/${url}`}` const { method, params, body } = options @@ -357,6 +365,9 @@ const baseFetch = ( const bodyJson = res.json() switch (res.status) { case 401: { + if (isMarketplaceAPI) + return + if (isPublicAPI) { return bodyJson.then((data: ResponseError) => { if (data.code === 'web_sso_auth_required') @@ -582,6 +593,11 @@ export const getPublic = (url: string, options = {}, otherOptions?: IOtherOpt return get(url, options, { ...otherOptions, isPublicAPI: true }) } +// For Marketplace API +export const getMarketplace = (url: string, options = {}, otherOptions?: IOtherOptions) => { + return get(url, options, { ...otherOptions, isMarketplaceAPI: true }) +} + export const post = (url: string, options = {}, otherOptions?: IOtherOptions) => { return request(url, Object.assign({}, options, { method: 'POST' }), otherOptions) } diff --git a/web/service/plugins.ts b/web/service/plugins.ts index c2e542f48c..05ec73c7b1 100644 --- a/web/service/plugins.ts +++ b/web/service/plugins.ts @@ -1,5 +1,5 @@ import type { Fetcher } from 'swr' -import { del, get, post, upload } from './base' +import { del, get, getMarketplace, post, upload } from './base' import type { CreateEndpointRequest, EndpointOperationResponse, @@ -79,6 +79,10 @@ export const fetchManifest = async (uniqueIdentifier: string) => { return get(`/workspaces/current/plugin/fetch-manifest?plugin_unique_identifier=${uniqueIdentifier}`) } +export const fetchManifestFromMarketPlace = async (uniqueIdentifier: string) => { + return getMarketplace(`/plugins/identifier?unique_identifier=${uniqueIdentifier}`) +} + export const installPackageFromMarketPlace = async (uniqueIdentifier: string) => { return post('/workspaces/current/plugin/install/marketplace', { body: { plugin_unique_identifiers: [uniqueIdentifier] },