Skip to content

Commit 6e1b99e

Browse files
authored
refactor(server): remove polka and use find-my-way + native HTTP (#622)
Update workspaces/server/src/endpoints/report.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Update workspaces/server/src/endpoints/util/send.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> chore: fix review
1 parent 393b4f6 commit 6e1b99e

File tree

25 files changed

+504
-322
lines changed

25 files changed

+504
-322
lines changed

src/commands/http.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export async function start(
6464
});
6565

6666
httpServer.listen(httpPort, async() => {
67-
const link = `http://localhost:${httpServer.server.address().port}`;
67+
const link = `http://localhost:${httpServer.address().port}`;
6868
console.log(kleur.magenta().bold(await i18n.getToken("cli.http_server_started")), kleur.cyan().bold(link));
6969

7070
open(link);
@@ -77,7 +77,7 @@ export async function start(
7777

7878
for (const eventName of ["SIGINT", "SIGTERM"]) {
7979
process.on(eventName, () => {
80-
httpServer.server.close();
80+
httpServer.close();
8181

8282
console.log(kleur.red().bold(`${eventName} signal received.`));
8383
process.exit(0);

test/helpers/utils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
export function getExpectedScorecardLines(pkgName, body) {
1+
export function getExpectedScorecardLines(packageName, body) {
22
const { date, score: scorePkg, checks } = body;
33

44
const expectedLines = [
55
"",
66
" OSSF Scorecard",
77
"",
8-
mockScorecardCliLine("Repository", pkgName),
8+
mockScorecardCliLine("Repository", packageName),
99
mockScorecardCliLine("Scan at", date),
1010
mockScorecardCliLine("Score", scorePkg),
1111
"--------------------------------------------------------------------------------"

workspaces/server/README.md

Lines changed: 77 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ Scorecard](https://api.securityscorecards.dev/projects/github.com/NodeSecure/cli
77
![size](https://img.shields.io/github/languages/code-size/NodeSecure/server?style=for-the-badge)
88
[![build](https://img.shields.io/github/actions/workflow/status/NodeSecure/cli/server.yml?style=for-the-badge)](https://github.com/NodeSecure/cli/actions?query=workflow%3A%22server+CI%22)
99

10-
NodeSecure CLI's http server based on `polka`.
10+
NodeSecure CLI's http and websocket server.
1111

1212
## Requirements
1313

14-
- [Node.js](https://nodejs.org/en/) v20 or higher
14+
- [Node.js](https://nodejs.org/en/) v22 or higher
1515

1616
## Getting Started
1717

@@ -50,7 +50,7 @@ httpServer.listen(port, async() => {
5050
5151
### `buildServer(dataFilePath: string, options: BuildServerOptions): polka`
5252
53-
Creates and configures a Polka HTTP server instance for the NodeSecure platform.
53+
Creates and configures a Node.js HTTP server instance for the NodeSecure CLI.
5454
5555
**Parameters**
5656
- `dataFilePath` (`string`):
@@ -73,106 +73,130 @@ The i18n tokens required for the interface.
7373
7474
**Returns**
7575
- `httpServer` (`object`):
76-
A configured **Polka** server instance with all routes and middlewares registered.
76+
A configured Node.js server instance with all routes and middlewares registered.
7777
7878
## API Endpoints
79+
7980
The server exposes the following REST API endpoints:
8081
81-
- `GET /`
82+
### `GET /`
83+
8284
Render and return the main HTML page for the NodeSecure UI.
8385
84-
- `GET /data`
86+
### `GET /data`
87+
8588
Returns the current analysis payload from the cache.
8689
87-
- **204**: No content if running from an empty cache.
88-
- **200**: JSON payload with analysis data.
90+
| Status | Description |
91+
| ------ | ----------- |
92+
| 204 | No content if running from an empty cache |
93+
| 200 | JSON payload with analysis data |
94+
95+
### `GET /config`
8996
90-
- `GET /config`
9197
Fetch the current server configuration.
9298
93-
- `PUT /config`
99+
### `PUT /config`
100+
94101
Update and save the server configuration.
95102
96-
**Body**: JSON configuration object.
103+
| Body | Description |
104+
| ---- | ----------- |
105+
| `config` | JSON configuration object |
106+
107+
### `GET /i18n`
97108
98-
- `GET /i18n`
99109
Returns UI translations for supported languages (English and French).
100110
101-
- `GET /search/:packageName`
111+
### `GET /search/:packageName`
112+
102113
Search for npm packages by name.
103114
104-
**Params**:
105-
- `packageName`: The name (or partial name) of the npm package to search for.
115+
| Param | Description |
116+
| ----- | ----------- |
117+
| `packageName` | The name (or partial name) of the npm package to search for |
106118
107-
**Response**:
108-
- `count`: Number of results.
109-
- `result`: Array of package objects (name, version, description).
119+
| Response Field | Description |
120+
| -------------- | ----------- |
121+
| `count` | Number of results |
122+
| `result` | Array of package objects (name, version, description) |
123+
124+
### `GET /search-versions/:packageName`
110125
111-
- `GET /search-versions/:packageName`
112126
Get all available versions for a given npm package.
113127
114-
**Params**:
115-
- `packageName`: The npm package name.
128+
| Param | Description |
129+
| ----- | ----------- |
130+
| `packageName` | The npm package name |
116131
117-
**Response**:
118-
Array of version strings.
132+
**Response**: Array of version strings.
133+
134+
### `GET /flags`
119135
120-
- `GET /flags`
121136
List all available NodeSecure flags and their metadata.
122137
123-
- `GET /flags/description/:title`
138+
### `GET /flags/description/:title`
139+
124140
Get the HTML description for a specific flag.
125141
126-
**Params**:
127-
- `title`: The flag name.
142+
| Param | Description |
143+
| ----- | ----------- |
144+
| `title` | The flag name |
145+
146+
### `GET /bundle/:packageName`
128147
129-
- `GET /bundle/:pkgName`
130148
Get bundle size information for a package from Bundlephobia.
131149
132-
**Params**:
133-
- `pkgName`: The npm package name.
150+
| Param | Description |
151+
| ----- | ----------- |
152+
| `packageName` | The npm package name |
153+
154+
### `GET /bundle/:packageName/:version`
134155
135-
- `GET /bundle/:pkgName/:version`
136156
Get bundle size information for a specific version of a package from Bundlephobia.
137157
138-
**Params**:
139-
- `pkgName`: The npm package name.
140-
- `version`: The package version.
158+
| Param | Description |
159+
| ----- | ----------- |
160+
| `packageName` | The npm package name |
161+
| `version` | The package version |
162+
163+
### `GET /downloads/:packageName`
141164
142-
- `GET /downloads/:pkgName`
143165
Get npm download statistics for the last week for a package.
144166
145-
**Params**:
146-
- `pkgName`: The npm package name.
167+
| Param | Description |
168+
| ----- | ----------- |
169+
| `packageName` | The npm package name |
170+
171+
### `GET /scorecard/:org/:packageName`
147172
148-
- `GET /scorecard/:org/:pkgName`
149173
Get OSSF Scorecard results for a package repository.
150174
151-
**Params**:
152-
- `org`: The organization or user.
153-
- `pkgName`: The repository name.
175+
| Param | Description |
176+
| ----- | ----------- |
177+
| `org` | The organization or user |
178+
| `packageName` | The repository name |
179+
180+
| Query | Description |
181+
| ----- | ----------- |
182+
| `platform` *(optional)* | The platform (default: `github.com`) |
154183
155-
**Query**:
156-
`platform` (*optional*): The platform (default: `github.com`).
184+
### `POST /report`
157185
158-
- `POST /report`
159186
Generate a PDF report for the current analysis.
160187
161-
**Body**:
162-
- `title`: Report title.
163-
- `includesAllDeps`: Boolean, include all dependencies or only the root.
164-
- `theme`: Report theme.
188+
| Body Field | Description |
189+
| ---------- | ----------- |
190+
| `title` | Report title |
191+
| `includesAllDeps` | Boolean, include all dependencies or only the root |
192+
| `theme` | Report theme |
165193
166-
**Response**:
167-
PDF file as binary data.
194+
**Response**: PDF file as binary data.
168195
169196
### Static Files
170197
171198
All static files (UI, assets, etc.) are served from the project root directory.
172199
173-
> [!NOTE]
174-
> For more details on each endpoint, see the corresponding files in /src/endpoints.
175-
176200
## Websocket commands
177201
178202
The `WebSocketServerInstanciator` class sets up and manages a WebSocket server for real-time communication with NodeSecure clients. It provides live updates and cache management features for package analysis.

workspaces/server/package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,18 @@
1818
"author": "GENTILHOMME Thomas <gentilhomme.thomas@gmail.com>",
1919
"license": "MIT",
2020
"devDependencies": {
21-
"@polka/send-type": "0.5.2",
22-
"@types/polka": "^0.5.7",
2321
"@types/server-destroy": "^1.0.4",
24-
"@types/ws": "^8.18.1"
22+
"@types/ws": "^8.18.1",
23+
"server-destroy": "1.0.1"
2524
},
2625
"dependencies": {
2726
"@nodesecure/cache": "1.0.0",
2827
"cacache": "20.0.3",
2928
"chokidar": "5.0.0",
29+
"find-my-way": "9.3.0",
3030
"glob": "13.0.0",
3131
"pino": "10.1.0",
3232
"pino-pretty": "13.1.2",
33-
"polka": "0.5.2",
34-
"server-destroy": "1.0.1",
3533
"sirv": "3.0.2",
3634
"ts-pattern": "5.9.0",
3735
"ws": "8.18.3",

workspaces/server/src/ALS.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22
import { AsyncLocalStorage } from "node:async_hooks";
33

44
// Import Internal Dependencies
5-
import type { AyncStoreContext } from "./middlewares/context.ts";
5+
import type { ViewBuilder } from "./ViewBuilder.class.ts";
66

7-
export const context = new AsyncLocalStorage<AyncStoreContext>();
7+
export type NestedStringRecord = {
8+
[key: string]: string | NestedStringRecord;
9+
};
10+
11+
export interface AsyncStoreContext {
12+
dataFilePath?: string;
13+
i18n: {
14+
english: NestedStringRecord;
15+
french: NestedStringRecord;
16+
};
17+
viewBuilder: ViewBuilder;
18+
}
19+
20+
export const context = new AsyncLocalStorage<AsyncStoreContext>();
Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
// Import Node.js Dependencies
2+
import type {
3+
IncomingMessage,
4+
ServerResponse
5+
} from "node:http";
6+
17
// Import Third-party Dependencies
28
import * as httpie from "@openally/httpie";
3-
import send from "@polka/send-type";
4-
import type { Request, Response } from "express-serve-static-core";
9+
10+
// Import Internal Dependencies
11+
import { send } from "./util/send.ts";
512

613
// CONSTANTS
714
const kBaseBundlePhobiaUrl = "https://bundlephobia.com/api";
@@ -15,21 +22,34 @@ interface BundlePhobiaResponse {
1522
}[];
1623
}
1724

18-
export async function get(req: Request, res: Response) {
19-
const { pkgName, version } = req.params;
25+
export async function get(
26+
_: IncomingMessage,
27+
res: ServerResponse,
28+
params: Record<string, string | undefined>
29+
) {
30+
const { packageName, version } = params;
31+
if (!packageName) {
32+
return send(res, {
33+
error: "Package name is missing."
34+
}, { code: 400 });
35+
}
2036

21-
const pkgTemplate = version ? `${pkgName.replaceAll("%2F", "/")}@${version}` : pkgName;
37+
const pkgTemplate = version ?
38+
`${packageName.replaceAll("%2F", "/")}@${version}` :
39+
packageName;
2240
try {
2341
const { data } = await httpie.get<BundlePhobiaResponse>(`${kBaseBundlePhobiaUrl}/size?package=${pkgTemplate}`);
2442
const { gzip, size, dependencySizes } = data;
2543

26-
return send(res, 200, {
44+
return send(res, {
2745
gzip,
2846
size,
2947
dependencySizes
3048
});
3149
}
3250
catch (error: any) {
33-
return send(res, error.statusCode, { error: error.statusMessage });
51+
return send(res, { error: error.statusMessage }, {
52+
code: error.statusCode ?? 500
53+
});
3454
}
3555
}
Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,33 @@
1+
// Import Node.js Dependencies
2+
import type {
3+
IncomingMessage,
4+
ServerResponse
5+
} from "node:http";
6+
17
// Import Third-party Dependencies
2-
import send from "@polka/send-type";
3-
import type { Request, Response } from "express-serve-static-core";
8+
import type { AppConfig } from "@nodesecure/cache";
49

510
// Import Internal Dependencies
611
import * as config from "../config.ts";
7-
import { bodyParser } from "../middlewares/bodyParser.ts";
12+
import { bodyParser } from "./util/bodyParser.ts";
13+
import { send } from "./util/send.ts";
814

9-
export async function get(_req: Request, res: Response) {
15+
export async function get(
16+
_req: IncomingMessage,
17+
res: ServerResponse
18+
) {
1019
const result = await config.get();
1120

12-
send(res, 200, result);
21+
send(res, result);
1322
}
1423

15-
export async function save(req: Request, res: Response) {
16-
const data = await bodyParser(req);
24+
export async function save(
25+
req: IncomingMessage,
26+
res: ServerResponse
27+
) {
28+
const data = await bodyParser<AppConfig>(req);
1729
await config.set(data);
1830

19-
send(res, 204);
31+
res.statusCode = 204;
32+
res.end();
2033
}

0 commit comments

Comments
 (0)