Skip to content

Commit

Permalink
Merge pull request #1231 from lowcoder-org/feature-private-repo
Browse files Browse the repository at this point in the history
Enabled private repo api in api-service and fixed response type issue.
  • Loading branch information
FalkWolsky authored Oct 9, 2024
2 parents 66b527b + a839beb commit 75fc901
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 39 deletions.
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

0 comments on commit 75fc901

Please sign in to comment.