Skip to content

Enabled private repo api in api-service and fixed response type issue. #1231

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import {
} from "types/remoteComp";

async function npmLoader(
remoteInfo: RemoteCompInfo
{
appId,
...remoteInfo
}: RemoteCompInfo & {appId?: string}
): Promise<CompConstructor | null> {

// Falk: removed "packageVersion = "latest" as default value fir packageVersion - to ensure no automatic version jumping.
const localPackageVersion = remoteInfo.packageVersion || "latest";
const { packageName, packageVersion, compName } = remoteInfo;
const entry = `${NPM_PLUGIN_ASSETS_BASE_URL}/${packageName}@${localPackageVersion}/index.js`;
const entry = `${NPM_PLUGIN_ASSETS_BASE_URL}/${appId}/${packageName}@${localPackageVersion}/index.js`;

try {
const module = await import(
Expand Down Expand Up @@ -51,7 +54,7 @@ async function bundleLoader(
return comp;
}

export const loaders: Record<RemoteCompSource, RemoteCompLoader> = {
export const loaders: Record<RemoteCompSource, RemoteCompLoader<RemoteCompInfo & {appId?: string}>> = {
npm: npmLoader,
bundle: bundleLoader,
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { CompContext } from "@lowcoder-ee/comps/utils/compContext";
import React from "react";
import type { AppState } from "@lowcoder-ee/redux/reducers";
import { useSelector } from "react-redux";
import { useApplicationId } from "@lowcoder-ee/util/hooks";

const ViewError = styled.div`
display: flex;
Expand Down Expand Up @@ -51,7 +52,7 @@ interface RemoteCompReadyAction {

interface RemoteCompViewProps {
isLowcoderComp?: boolean;
loadComp: (packageVersion?: string) => Promise<void>;
loadComp: (packageVersion?: string, appId?: string) => Promise<void>;
loadingElement?: () => React.ReactNode;
errorElement?: (error: any) => React.ReactNode;
source?: RemoteCompSource;
Expand All @@ -62,6 +63,7 @@ const RemoteCompView = React.memo((props: React.PropsWithChildren<RemoteCompView
const [error, setError] = useState<any>("");
const editorState = useContext(EditorContext);
const compState = useContext(CompContext);
const appId = useApplicationId();
const lowcoderCompPackageVersion = editorState?.getAppSettings().lowcoderCompVersion || 'latest';
const latestLowcoderCompsVersion = useSelector((state: AppState) => state.npmPlugin.packageVersion['lowcoder-comps']);

Expand All @@ -79,7 +81,7 @@ const RemoteCompView = React.memo((props: React.PropsWithChildren<RemoteCompView

useMount(() => {
setError("");
loadComp(packageVersion).catch((e) => {
loadComp(packageVersion, appId).catch((e) => {
setError(String(e));
});
});
Expand Down Expand Up @@ -117,7 +119,7 @@ export function remoteComp<T extends RemoteCompInfo = RemoteCompInfo>(
this.compValue = params.value;
}

private async load(packageVersion = 'latest') {
private async load(packageVersion = 'latest', appId = 'none') {
if (!remoteInfo) {
return;
}
Expand All @@ -129,7 +131,7 @@ export function remoteComp<T extends RemoteCompInfo = RemoteCompInfo>(
log.error("loader not found, remote info:", remoteInfo);
return;
}
const RemoteExportedComp = await finalLoader({...remoteInfo, packageVersion});
const RemoteExportedComp = await finalLoader({...remoteInfo, packageVersion, appId});
if (!RemoteExportedComp) {
return;
}
Expand Down Expand Up @@ -159,7 +161,7 @@ export function remoteComp<T extends RemoteCompInfo = RemoteCompInfo>(
<RemoteCompView
key={key}
isLowcoderComp={remoteInfo?.packageName === 'lowcoder-comps'}
loadComp={(packageVersion?: string) => this.load(packageVersion)}
loadComp={(packageVersion?: string, appId?: string) => this.load(packageVersion, appId)}
loadingElement={loadingElement}
source={remoteInfo?.source}
/>
Expand Down
2 changes: 1 addition & 1 deletion client/packages/lowcoder/src/comps/utils/remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function parseCompType(compType: string) {
}

export async function getNpmPackageMeta(packageName: string) {
const res = await axios.get<NpmPackageMeta>(`${NPM_REGISTRY_URL}/${packageName}`);
const res = await axios.get<NpmPackageMeta>(`${NPM_REGISTRY_URL}/none/${packageName}`);
if (res.status >= 400) {
return null;
}
Expand Down
10 changes: 7 additions & 3 deletions client/packages/lowcoder/src/constants/npmPlugins.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export const SERVER_HOST = `${REACT_APP_NODE_SERVICE_URL ?? ""}`;
export const NPM_REGISTRY_URL = `${SERVER_HOST}/node-service/api/npm/registry`;
export const NPM_PLUGIN_ASSETS_BASE_URL = `${SERVER_HOST}/node-service/api/npm/package`;
// export const SERVER_HOST = `${REACT_APP_NODE_SERVICE_URL ?? ""}`;
// export const NPM_REGISTRY_URL = `${SERVER_HOST}/node-service/api/npm/registry`;
// export const NPM_PLUGIN_ASSETS_BASE_URL = `${SERVER_HOST}/node-service/api/npm/package`;

export const SERVER_HOST = `${REACT_APP_API_SERVICE_URL ?? ""}`;
export const NPM_REGISTRY_URL = `${SERVER_HOST}/api/npm/registry`;
export const NPM_PLUGIN_ASSETS_BASE_URL = `${SERVER_HOST}/api/npm/package`;
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, NewUrl.ORGANIZATION_URL + "/*/datasourceTypes"), // datasource types
ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, NewUrl.ORGANIZATION_URL + "/byuser/*"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, NewUrl.DATASOURCE_URL + "/jsDatasourcePlugins"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, NewUrl.NPM_REGISTRY + "/**"),
ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/api/docs/**")
)
.permitAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.lowcoder.api.home.SessionUserService;
import org.lowcoder.domain.application.service.ApplicationServiceImpl;
import org.lowcoder.domain.organization.service.OrgMemberServiceImpl;
import org.lowcoder.domain.organization.service.OrganizationService;
import org.lowcoder.infra.constant.NewUrl;
import org.lowcoder.infra.js.NodeServerHelper;
Expand All @@ -27,33 +29,59 @@ public class PrivateNpmRegistryController implements PrivateNpmRegistryEndpoint{

private static final String NPM_REGISTRY_METADATA = "npm/registry";
private static final String NPM_REGISTRY_ASSET = "npm/package";
private final OrgMemberServiceImpl orgMemberServiceImpl;
private final ApplicationServiceImpl applicationServiceImpl;

@Override
public Mono<ResponseEntity<Resource>> getNpmPackageMeta(String name) {
return forwardToNodeService(name, NPM_REGISTRY_METADATA);
public Mono<ResponseEntity<Resource>> getNpmPackageMeta(String applicationId, String name) {
return forwardToNodeService(applicationId, name, NPM_REGISTRY_METADATA);
}

@Override
public Mono<ResponseEntity<Resource>> getNpmPackageAsset(String path) {
return forwardToNodeService(path, NPM_REGISTRY_ASSET);
public Mono<ResponseEntity<Resource>> getNpmPackageAsset(String applicationId, String path) {
return forwardToNodeService(applicationId, path, NPM_REGISTRY_ASSET);
}

@NotNull
private Mono<ResponseEntity<Resource>> forwardToNodeService(String path, String prefix) {
return sessionUserService.getVisitorOrgMemberCache().flatMap(orgMember -> organizationService.getOrgCommonSettings(orgMember.getOrgId()).flatMap(organizationCommonSettings -> {
Map<String, Object> config = Map.of("npmRegistries", organizationCommonSettings.get("npmRegistries"), "workspaceId", orgMember.getOrgId());
return WebClientBuildHelper.builder()
.systemProxy()
.build()
.post()
.uri(nodeServerHelper.createUri(prefix + "/" + path))
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(config))
.retrieve().toEntity(Resource.class)
.map(response -> ResponseEntity
.status(response.getStatusCode())
.headers(response.getHeaders())
.body(response.getBody()));
}));
private Mono<ResponseEntity<Resource>> forwardToNodeService(String applicationId, String path, String prefix) {

String withoutLeadingSlash = path.startsWith("/") ? path.substring(1) : path;
if(applicationId.equals("none")) {
return sessionUserService.getVisitorOrgMemberCache().flatMap(orgMember -> organizationService.getOrgCommonSettings(orgMember.getOrgId()).flatMap(organizationCommonSettings -> {
Map<String, Object> config = Map.of("npmRegistries", organizationCommonSettings.get("npmRegistries"), "workspaceId", orgMember.getOrgId());
return WebClientBuildHelper.builder()
.systemProxy()
.build()
.post()
.uri(nodeServerHelper.createUri(prefix + "/" + withoutLeadingSlash))
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(config))
.retrieve().toEntity(Resource.class)
.map(response -> {
return ResponseEntity
.status(response.getStatusCode())
.headers(response.getHeaders())
.body(response.getBody());
});
}));
} else{
return applicationServiceImpl.findById(applicationId).flatMap(application -> organizationService.getById(application.getOrganizationId())).flatMap(orgMember -> organizationService.getOrgCommonSettings(orgMember.getId()).flatMap(organizationCommonSettings -> {
Map<String, Object> config = Map.of("npmRegistries", organizationCommonSettings.get("npmRegistries"), "workspaceId", orgMember.getId());
return WebClientBuildHelper.builder()
.systemProxy()
.build()
.post()
.uri(nodeServerHelper.createUri(prefix + "/" + withoutLeadingSlash))
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(config))
.retrieve().toEntity(Resource.class)
.map(response -> {
return ResponseEntity
.status(response.getStatusCode())
.headers(response.getHeaders())
.body(response.getBody());
});
}));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ public interface PrivateNpmRegistryEndpoint {
summary = "Get NPM registry Metadata",
description = "Retrieve the metadata of private NPM registry package."
)
// @GetMapping("/registry/{name}")
public Mono<ResponseEntity<Resource>> getNpmPackageMeta(@PathVariable String name);
@GetMapping("/registry/{applicationId}/{name}")
public Mono<ResponseEntity<Resource>> getNpmPackageMeta(@PathVariable String applicationId, @PathVariable String name);

@Operation(
tags = TAG_NPM_REGISTRY_MANAGEMENT,
operationId = "getNpmPackageAsset",
summary = "Get NPM registry asset",
description = "Retrieve the asset of private NPM registry package."
)
// @GetMapping("/package/{path}")
public Mono<ResponseEntity<Resource>> getNpmPackageAsset(@PathVariable String path);
@GetMapping("/package/{applicationId}/{*path}")
public Mono<ResponseEntity<Resource>> getNpmPackageAsset(@PathVariable String applicationId, @PathVariable String path);
}
6 changes: 3 additions & 3 deletions server/node-service/src/controllers/npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import fs from "fs/promises";
import { spawn } from "child_process";
import { Request as ServerRequest, Response as ServerResponse } from "express";
import { NpmRegistryService, NpmRegistryConfigEntry, NpmRegistryConfig } from "../services/npmRegistry";

import {default as pathlib} from 'path';

type RequestConfig = {
workspaceId: string;
Expand Down Expand Up @@ -217,7 +217,7 @@ async function fetchPackageFileInner(request: ServerRequest, response: ServerRes
logger.info(`Fetching tarball: ${tarball}`);
await fetchAndUnpackTarball(tarball, packageId, packageVersion, registry, baseDir);
} catch (error) {
logger.error(`Error fetching package: ${error} ${(error as {stack: string}).stack}`);
logger.error(`Error fetching package: ${error} ${(error as any)?.stack}`);
return response.status(500).send("Internal server error");
} finally {
PackageProcessingQueue.resolve(packageId);
Expand All @@ -232,7 +232,7 @@ async function fetchPackageFileInner(request: ServerRequest, response: ServerRes
return response.sendFile(`${packageBaseDir}/index.mjs`);
}

return response.sendFile(`${packageBaseDir}/${file}`);
return response.sendFile(pathlib.resolve(`${packageBaseDir}/${file}`));
} catch (error) {
logger.error(`Error fetching package file: ${error} ${(error as {stack: string})?.stack?.toString()}`);
response.status(500).send("Internal server error");
Expand Down
Loading