Skip to content

Commit 31f6403

Browse files
Bun support features (#16)
Bun support feature
1 parent eb2e7fe commit 31f6403

38 files changed

+2128
-218
lines changed

.github/workflows/npm-test.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,9 @@ jobs:
1414
- uses: actions/setup-node@v3
1515
with:
1616
node-version: 21
17-
- run: npm test
17+
- uses: oven-sh/setup-bun@v1
18+
with:
19+
bun-version: 1.1.4
20+
- run: node --test **/test/**/[!b][!u][!n]*/**/*.js
21+
- run: bun test **/test/**/bun/**/**
22+

README.md

Lines changed: 116 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# objective-http
22
Proxy classes for creating a http server
33

4+
45
## Server
56

6-
There are all ```Server``` classes feature.
7-
Your endpoints must implement ```Endpoint``` class interface (```route``` and ```handle``` functions).
7+
There are all `Server` classes feature.
8+
Your endpoints must implement `Endpoint` class interface (`route()` and `async handle(request)` methods).
89

9-
``` javascript
10+
```javascript
1011
const http = require('node:http');
1112
const cluster = require('node:cluster');
1213

@@ -28,15 +29,15 @@ const {
2829
new ClusteredServer(
2930
new LoggedServer(
3031
new Server(
31-
http,
32-
new LoggedInputRequest(new JsonInputRequest(new InputRequest()), console),
33-
new LoggedOutputResponse(new JsonOutputResponse(new OutputResponse()), console),
3432
new Endpoints([
3533
new MyFirstEndpoint(new LoggedEndpoint(new Endpoint(), console)),
3634
new MySecondEndpoint(new LoggedEndpoint(new Endpoint(), console)),
3735
new MyThirdEndpoint(new LoggedEndpoint(new Endpoint(), console))
3836
]),
39-
{port: server_port}
37+
{port: server_port},
38+
new LoggedInputRequest(new JsonInputRequest(new InputRequest()), console),
39+
new LoggedOutputResponse(new JsonOutputResponse(new OutputResponse()), console),
40+
http
4041
),
4142
console
4243
),
@@ -45,19 +46,21 @@ new ClusteredServer(
4546
).start();
4647
```
4748

49+
4850
## Client
4951

50-
``` javascript
51-
const https = require('node:https');
52+
```javascript
53+
const http = require('node:http');
54+
const requestFunction = http.request;
5255
const {
5356
OutputRequest,
5457
InputResponse
5558
} = require('objective-http').client;
5659

5760

5861
const response = await new OutputRequest(
59-
https,
6062
new InputResponse(),
63+
requestFunction,
6164
{
6265
url: 'https://example.com',
6366
method: 'POST',
@@ -69,14 +72,115 @@ console.log(response.body().toString());
6972

7073
//or
7174

72-
const request = new OutputRequest(https, new InputResponse());
75+
const request = new OutputRequest(new InputResponse(), requestFunction);
7376

7477
const otherResponse = await (request
7578
.copy({
7679
url: 'https://example.com',
7780
method: 'POST',
7881
body: 'test body'
7982
}))
80-
.send()
83+
.send();
84+
85+
console.log(response.body().toString());
86+
```
87+
88+
89+
## [Bun](https://bun.sh) support
90+
91+
`server` and `client` packages support Bun by default.
92+
But there ara special `bun` package with native [Bun API](https://bun.sh/docs/runtime/bun-apis) implementation (like `Bun.serve()`).
93+
And you should replace `node:http` package with `objective-http.bun.bunttp` in your `Server` configuration.
94+
[Don't use](https://bun.sh/docs/runtime/nodejs-apis#node-cluster) `ClusteredServer` with `Bun`!!!
95+
96+
97+
### Server Bun usage
98+
99+
It should work with `node` and `bun`:
100+
101+
```javascript
102+
const http = require('node:http');
103+
104+
const {
105+
Server,
106+
LoggedServer,
107+
InputRequest,
108+
JsonInputRequest,
109+
LoggedInputRequest,
110+
OutputResponse,
111+
JsonOutputResponse,
112+
LoggedOutputResponse,
113+
Endpoint,
114+
LoggedEndpoint,
115+
Endpoints
116+
} = require('objective-http').server;
117+
118+
new LoggedServer(
119+
new Server(
120+
new Endpoints([
121+
new MyFirstEndpoint(new LoggedEndpoint(new Endpoint(), console)),
122+
new MySecondEndpoint(new LoggedEndpoint(new Endpoint(), console)),
123+
new MyThirdEndpoint(new LoggedEndpoint(new Endpoint(), console))
124+
]),
125+
{port: server_port},
126+
new LoggedInputRequest(new JsonInputRequest(new InputRequest()), console),
127+
new LoggedOutputResponse(new JsonOutputResponse(new OutputResponse()), console),
128+
http
129+
),
130+
console
131+
).start()
132+
```
133+
134+
In order for the code to be executed only by `bun` (with `Bun API` inside), you need to make changes to the import block.
135+
`bun` package redeclare only `InputRequest` and `OutputResponse` classes. Other classes taken from `server` package.
81136

137+
```javascript
138+
const http = require('objective-http').bun.bunttp;
139+
140+
const {
141+
Server,
142+
LoggedServer,
143+
InputRequest,
144+
JsonInputRequest,
145+
LoggedInputRequest,
146+
OutputResponse,
147+
JsonOutputResponse,
148+
LoggedOutputResponse,
149+
Endpoint,
150+
LoggedEndpoint,
151+
Endpoints
152+
} = require('objective-http').bun.server;
153+
```
154+
155+
156+
### Client Bun usage
157+
158+
It should work with `node` and `bun`:
159+
160+
```javascript
161+
const http = require('node:http');
162+
const requestFunction = http.request;
163+
const {
164+
OutputRequest,
165+
InputResponse
166+
} = require('objective-http').client;
167+
168+
await (new OutputRequest(new InputResponse(), requestFunction)
169+
.copy({
170+
url: 'https://example.com',
171+
method: 'POST',
172+
body: 'test body'
173+
}))
174+
.send();
175+
```
176+
177+
In order for the code to be executed only by `bun`, you need to make changes to the import block.
178+
179+
```javascript
180+
const http = require('objective-http').bun.bunttp;
181+
const requestFunction = http.request;
182+
const {
183+
OutputRequest,
184+
InputResponse
185+
} = require('objective-http').bun.client;
82186
```

package.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@
33
"version": "master",
44
"private": "true",
55
"description": "Proxy classes for creating a http server",
6-
"keywords": ["web", "web-server", "http", "http-server", "oop"],
6+
"keywords": [
7+
"web",
8+
"web-server",
9+
"http",
10+
"http-server",
11+
"oop"
12+
],
713
"scripts": {
814
"prepareToPublish": "node dist/prepareToPublish.js",
9-
"test": "node --test"
15+
"test": "node --test **/test/**/[!b][!u][!n]*/**/*.js",
16+
"testBun": "bun test **/test/**/bun/**/**"
1017
},
1118
"author": {
1219
"name": "volatilization",
@@ -16,4 +23,4 @@
1623
"url": "git+https://github.com/volatilization/objective-http.git"
1724
},
1825
"license": "LGPL-3.0-only"
19-
}
26+
}

src/js/bun/Bunttp.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module.exports = class Bunttp {
2+
#serverConfig;
3+
#server;
4+
5+
constructor(serverConfig = {}, server = {}) {
6+
this.#serverConfig = serverConfig;
7+
this.#server = server;
8+
}
9+
10+
createServer(cb) {
11+
this.#serverConfig.fetch = cb;
12+
return this;
13+
}
14+
15+
listen(options, cb) {
16+
this.#serverConfig.port = options.port;
17+
this.#server = Bun.serve(this.#serverConfig);
18+
cb();
19+
return this;
20+
}
21+
22+
close(cb) {
23+
this.#server.stop();
24+
cb();
25+
return this;
26+
}
27+
28+
request = fetch;
29+
}

src/js/bun/client/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
OutputRequest: require('./request/OutputRequest'),
3+
InputResponse: require('./response/InputResponse')
4+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module.exports = class OutputRequest {
2+
#response;
3+
#requestFunction;
4+
#options;
5+
6+
constructor(response, requestFunction, options) {
7+
this.#response = response;
8+
this.#requestFunction = requestFunction;
9+
this.#options = options;
10+
}
11+
12+
copy(options = this.#options, response = this.#response, requestFunction = this.#requestFunction) {
13+
return new OutputRequest(response, requestFunction, options);
14+
}
15+
16+
async send() {
17+
try {
18+
return await (this.#response
19+
.copy(await this.#requestFunction(this.#options.url, this.#options)))
20+
.flush()
21+
22+
} catch (e) {
23+
throw new Error(e.message, {cause: 'INVALID_REQUEST'});
24+
}
25+
}
26+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
module.exports = class InputResponse {
2+
#inputStream;
3+
#options;
4+
5+
constructor(inputStream, options) {
6+
this.#inputStream = inputStream;
7+
this.#options = options;
8+
}
9+
10+
copy(inputStream = this.#inputStream, options = this.#options) {
11+
return new InputResponse(inputStream, options);
12+
}
13+
14+
async flush() {
15+
try {
16+
return new InputResponse(this.#inputStream,
17+
{
18+
statusCode: this.#inputStream.status,
19+
headers: this.#inputStream.headers,
20+
body: Buffer.from(await (await this.#inputStream.blob()).arrayBuffer())
21+
}
22+
);
23+
24+
} catch (e) {
25+
throw new Error(e.message, {cause: 'INVALID_RESPONSE'});
26+
}
27+
}
28+
29+
statusCode() {
30+
return this.#options.statusCode;
31+
}
32+
33+
headers() {
34+
return this.#options.headers;
35+
}
36+
37+
body() {
38+
return this.#options.body;
39+
}
40+
}

src/js/bun/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
server: require('./server'),
3+
client: require('./client'),
4+
bunttp: new (require('./Bunttp'))()
5+
}

src/js/bun/server/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
InputRequest: require('./request/InputRequest'),
3+
OutputResponse: require('./response/OutputResponse')
4+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
module.exports = class InputRequest {
2+
#inputStream;
3+
#options;
4+
5+
constructor(inputStream, options) {
6+
this.#inputStream = inputStream;
7+
this.#options = options;
8+
}
9+
10+
copy(inputStream = this.#inputStream, options = this.#options) {
11+
return new InputRequest(inputStream, options);
12+
}
13+
14+
async flush() {
15+
try {
16+
return new InputRequest(
17+
this.#inputStream,
18+
{
19+
method: this.#inputStream.method,
20+
path: new URL(this.#inputStream.url).pathname,
21+
query: new URL(this.#inputStream.url).searchParams,
22+
headers: this.#inputStream.headers,
23+
body: Buffer.from(await (await this.#inputStream.blob()).arrayBuffer())
24+
}
25+
);
26+
27+
} catch (e) {
28+
throw new Error(e.message, {cause: 'INVALID_REQUEST'});
29+
}
30+
}
31+
32+
route() {
33+
return {
34+
method: this.#options.method.toString().toUpperCase(),
35+
path: this.#options.path.toString().toLowerCase()
36+
}
37+
}
38+
39+
query() {
40+
return this.#options.query;
41+
}
42+
43+
body() {
44+
return this.#options.body;
45+
}
46+
47+
headers() {
48+
return this.#options.headers;
49+
}
50+
}

0 commit comments

Comments
 (0)