objective-http 1.4.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of objective-http might be problematic. Click here for more details.

Files changed (55) hide show
  1. package/README.md +102 -182
  2. package/package.json +44 -1
  3. package/src/js/client/index.js +2 -2
  4. package/src/js/client/request/chunk/ChunkClientRequest.js +67 -0
  5. package/src/js/client/request/chunk/JsonClientRequest.js +55 -0
  6. package/src/js/client/request/chunk/index.js +4 -0
  7. package/src/js/client/request/index.js +2 -2
  8. package/src/js/client/response/chunk/ChunkClientResponse.js +75 -0
  9. package/src/js/client/response/chunk/JsonClientResponse.js +62 -0
  10. package/src/js/client/response/chunk/index.js +4 -0
  11. package/src/js/client/response/index.js +2 -2
  12. package/src/js/index.js +1 -2
  13. package/src/js/server/Server.js +40 -62
  14. package/src/js/server/handler/endpoint/EndpointHandler.js +35 -0
  15. package/src/js/server/handler/endpoint/EndpointHandlers.js +22 -0
  16. package/src/js/server/handler/endpoint/EndpointsHandler.js +42 -0
  17. package/src/js/server/handler/endpoint/EndpontRequiredHandler.js +22 -0
  18. package/src/js/server/handler/endpoint/index.js +6 -0
  19. package/src/js/server/handler/error/HandlerNotFoundErrorHandler.js +27 -0
  20. package/src/js/server/handler/error/InvalidRequestErrorHandler.js +27 -0
  21. package/src/js/server/handler/error/LogErrorHandler.js +21 -0
  22. package/src/js/server/handler/error/UnexpectedErrorHandler.js +23 -0
  23. package/src/js/server/handler/error/index.js +6 -0
  24. package/src/js/server/handler/index.js +4 -0
  25. package/src/js/server/index.js +3 -4
  26. package/src/js/server/request/chunk/ChunkServerRequest.js +87 -0
  27. package/src/js/server/request/chunk/JsonServerRequest.js +67 -0
  28. package/src/js/server/request/chunk/index.js +4 -0
  29. package/src/js/server/request/index.js +2 -3
  30. package/src/js/server/response/chunk/ChunkServerResponse.js +53 -0
  31. package/src/js/server/response/chunk/JsonServerResponse.js +50 -0
  32. package/src/js/server/response/chunk/index.js +4 -0
  33. package/src/js/server/response/index.js +2 -3
  34. package/src/js/bun/Bunttp.js +0 -25
  35. package/src/js/bun/client/index.js +0 -4
  36. package/src/js/bun/client/request/OutputRequest.js +0 -26
  37. package/src/js/bun/client/request/index.js +0 -3
  38. package/src/js/bun/client/response/InputResponse.js +0 -40
  39. package/src/js/bun/client/response/index.js +0 -3
  40. package/src/js/bun/index.js +0 -5
  41. package/src/js/bun/server/index.js +0 -4
  42. package/src/js/bun/server/request/InputRequest.js +0 -49
  43. package/src/js/bun/server/request/index.js +0 -3
  44. package/src/js/bun/server/response/OutputResponse.js +0 -25
  45. package/src/js/bun/server/response/index.js +0 -3
  46. package/src/js/client/request/OutputRequest.js +0 -53
  47. package/src/js/client/response/InputResponse.js +0 -48
  48. package/src/js/server/LoggedServer.js +0 -29
  49. package/src/js/server/endpoint/Endpoint.js +0 -17
  50. package/src/js/server/endpoint/Endpoints.js +0 -36
  51. package/src/js/server/endpoint/index.js +0 -4
  52. package/src/js/server/request/InputRequest.js +0 -57
  53. package/src/js/server/request/LoggedInputRequest.js +0 -44
  54. package/src/js/server/response/LoggedOutputResponse.js +0 -32
  55. package/src/js/server/response/OutputResponse.js +0 -28
@@ -1,83 +1,61 @@
1
1
  module.exports = class Server {
2
- #endpoints;
2
+ #handler;
3
3
  #options;
4
- #request;
5
- #response;
6
- #createServerFunction;
4
+ #http;
7
5
  #server;
8
6
 
9
- constructor(endpoints, options, request, response, createServerFunction, server) {
10
- this.#endpoints = endpoints;
7
+ constructor({ handler, options, http, server }) {
8
+ this.#handler = handler;
11
9
  this.#options = options;
12
- this.#request = request;
13
- this.#response = response;
14
- this.#createServerFunction = createServerFunction;
10
+ this.#http = http;
15
11
  this.#server = server;
16
12
  }
17
13
 
18
- options() {
14
+ with({
15
+ handler = this.#handler,
16
+ options = this.#options,
17
+ http = this.#http,
18
+ server = this.#server,
19
+ }) {
20
+ return new Server({
21
+ handler,
22
+ options,
23
+ http,
24
+ server,
25
+ });
26
+ }
27
+
28
+ get options() {
19
29
  return this.#options;
20
30
  }
21
31
 
22
32
  start() {
23
- const server = this.#createServerFunction(async (requestStream, responseStream) => {
33
+ return new Promise((resolve, reject) => {
24
34
  try {
25
- return await this.#response
26
- .copy(responseStream,
27
- await this.#endpoints
28
- .handle(await this.#request
29
- .copy(requestStream)
30
- .flush()))
31
- .flush();
32
-
35
+ const server = this.#http.createServer(
36
+ async (requestStream, responseStream) =>
37
+ await this.#handler.handle(
38
+ requestStream,
39
+ responseStream,
40
+ ),
41
+ );
42
+
43
+ server.listen(this.options, () =>
44
+ resolve(this.with({ server })),
45
+ );
33
46
  } catch (e) {
34
- if (e.cause === 'INVALID_REQUEST') {
35
- return this.#response
36
- .copy(responseStream,
37
- {statusCode: 400, body: e.message})
38
- .flush();
39
- }
40
-
41
- if (e.cause === 'HANDLER_NOT_FOUND') {
42
- return this.#response
43
- .copy(responseStream,
44
- {statusCode: 501, body: e.message})
45
- .flush();
46
- }
47
-
48
- return this.#response
49
- .copy(responseStream,
50
- {statusCode: 500, body: 'Unexpected server error.'})
51
- .flush();
47
+ reject(
48
+ new Error('Init server fail', {
49
+ cause: { error: e, code: 'INITIAL_SERVER_FAIL' },
50
+ }),
51
+ );
52
52
  }
53
53
  });
54
-
55
- return new Promise(resolve => {
56
- server.listen(
57
- this.#options,
58
- () => resolve(new Server(
59
- this.#endpoints,
60
- this.#options,
61
- this.#request,
62
- this.#response,
63
- this.#createServerFunction,
64
- server))
65
- );
66
- });
67
54
  }
68
55
 
69
56
  stop() {
70
- return new Promise(resolve => {
71
- console.log('stop ', this.#server);
72
-
73
- this.#server.close(
74
- () => resolve(new Server(
75
- this.#endpoints,
76
- this.#options,
77
- this.#request,
78
- this.#response,
79
- this.#createServerFunction))
80
- );
57
+ return new Promise((resolve) => {
58
+ this.#server.close(() => resolve(this.with({ server: null })));
81
59
  });
82
60
  }
83
- };
61
+ };
@@ -0,0 +1,35 @@
1
+ module.exports = class EndpointHandler {
2
+ #endpoint;
3
+ #request;
4
+ #response;
5
+
6
+ constructor({ endpoint, request, response }) {
7
+ this.#endpoint = endpoint;
8
+ this.#request = request;
9
+ this.#response = response;
10
+ }
11
+
12
+ async handle(requestStream, responseStream) {
13
+ const requestRoute = JSON.stringify({
14
+ method: requestStream.method,
15
+ path: new URL(`http://localhost${requestStream.url}`).pathname,
16
+ });
17
+
18
+ if (requestRoute !== JSON.stringify(this.#endpoint.route)) {
19
+ return;
20
+ }
21
+
22
+ const request = await this.#request
23
+ .with({
24
+ requestStream,
25
+ })
26
+ .accept();
27
+
28
+ return this.#response
29
+ .with({
30
+ responseStream,
31
+ ...(await this.#endpoint.handle(request)),
32
+ })
33
+ .send();
34
+ }
35
+ };
@@ -0,0 +1,22 @@
1
+ module.exports = class EndpointHandlers {
2
+ #handlers;
3
+
4
+ constructor({ handlers }) {
5
+ this.#handlers = handlers;
6
+ }
7
+
8
+ async handle(requestStream, responseStream) {
9
+ for (let i = 0; i < this.#handlers.length; i++) {
10
+ const response = await this.#handlers[i].handle(
11
+ requestStream,
12
+ responseStream,
13
+ );
14
+
15
+ if (response != null) {
16
+ return response;
17
+ }
18
+ }
19
+
20
+ return;
21
+ }
22
+ };
@@ -0,0 +1,42 @@
1
+ module.exports = class EndpointsHandler {
2
+ #routeToEndpointMap;
3
+ #request;
4
+ #response;
5
+
6
+ constructor({ endpoints, request, response }) {
7
+ this.#request = request;
8
+ this.#response = response;
9
+ this.#routeToEndpointMap = new Map(
10
+ endpoints.map((endpoint) => [
11
+ JSON.stringify(endpoint.route),
12
+ endpoint,
13
+ ]),
14
+ );
15
+ }
16
+
17
+ async handle(requestStream, responseStream) {
18
+ const requestRoute = JSON.stringify({
19
+ method: requestStream.method,
20
+ path: new URL(`http://localhost${requestStream.url}`).pathname,
21
+ });
22
+
23
+ if (!this.#routeToEndpointMap.has(requestRoute)) {
24
+ return;
25
+ }
26
+
27
+ const request = await this.#request
28
+ .with({
29
+ requestStream,
30
+ })
31
+ .accept();
32
+
33
+ return this.#response
34
+ .with({
35
+ responseStream,
36
+ ...(await this.#routeToEndpointMap
37
+ .get(JSON.stringify(request.route))
38
+ .handle(request)),
39
+ })
40
+ .send();
41
+ }
42
+ };
@@ -0,0 +1,22 @@
1
+ module.exports = class EndpontRequiredHandler {
2
+ #origin;
3
+
4
+ constructor({ origin }) {
5
+ this.#origin = origin;
6
+ }
7
+
8
+ async handle(requestStream, responseStream) {
9
+ const response = await this.#origin.handle(
10
+ requestStream,
11
+ responseStream,
12
+ );
13
+
14
+ if (response == null) {
15
+ throw new Error(`Handler for ${requestStream.url} not found`, {
16
+ cause: { code: 'HANDLER_NOT_FOUND' },
17
+ });
18
+ }
19
+
20
+ return response;
21
+ }
22
+ };
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ EndpointHandler: require('./EndpointHandler'),
3
+ EndpointsHandler: require('./EndpointsHandler'),
4
+ EndpointHandlers: require('./EndpointHandlers'),
5
+ EndpointRequiredHandler: require('./EndpontRequiredHandler'),
6
+ };
@@ -0,0 +1,27 @@
1
+ module.exports = class HandlerNotFoundErrorHandler {
2
+ #origin;
3
+ #response;
4
+
5
+ constructor({ origin, response }) {
6
+ this.#origin = origin;
7
+ this.#response = response;
8
+ }
9
+
10
+ async handle(requestStream, responseStream) {
11
+ try {
12
+ return await this.#origin.handle(requestStream, responseStream);
13
+ } catch (e) {
14
+ if (e.cause?.code !== 'HANDLER_NOT_FOUND') {
15
+ throw e;
16
+ }
17
+
18
+ return this.#response
19
+ .with({
20
+ responseStream,
21
+ status: 501,
22
+ body: e.message,
23
+ })
24
+ .send();
25
+ }
26
+ }
27
+ };
@@ -0,0 +1,27 @@
1
+ module.exports = class InvalidRequestErrorHandler {
2
+ #origin;
3
+ #response;
4
+
5
+ constructor({ origin, response }) {
6
+ this.#origin = origin;
7
+ this.#response = response;
8
+ }
9
+
10
+ async handle(requestStream, responseStream) {
11
+ try {
12
+ return await this.#origin.handle(requestStream, responseStream);
13
+ } catch (e) {
14
+ if (e.cause?.code !== 'INVALID_REQUEST') {
15
+ throw e;
16
+ }
17
+
18
+ return this.#response
19
+ .with({
20
+ responseStream,
21
+ status: 400,
22
+ body: e.message,
23
+ })
24
+ .send();
25
+ }
26
+ }
27
+ };
@@ -0,0 +1,21 @@
1
+ module.exports = class LogErrorHandler {
2
+ #origin;
3
+ #logger;
4
+
5
+ constructor({ origin, logger }) {
6
+ this.#origin = origin;
7
+ this.#logger = logger;
8
+ }
9
+
10
+ async handle(reqestStream, responseStream) {
11
+ try {
12
+ return await this.#origin.handle(reqestStream, responseStream);
13
+ } catch (e) {
14
+ this.#logger.error(`Error while handling ${reqestStream.url}`, {
15
+ cause: { error: e },
16
+ });
17
+
18
+ throw e;
19
+ }
20
+ }
21
+ };
@@ -0,0 +1,23 @@
1
+ module.exports = class UnexpectedErrorHandler {
2
+ #origin;
3
+ #response;
4
+
5
+ constructor({ origin, response }) {
6
+ this.#origin = origin;
7
+ this.#response = response;
8
+ }
9
+
10
+ async handle(requestStream, responseStream) {
11
+ try {
12
+ return await this.#origin.handle(requestStream, responseStream);
13
+ } catch {
14
+ return this.#response
15
+ .with({
16
+ responseStream,
17
+ status: 500,
18
+ body: 'Application unexpected error',
19
+ })
20
+ .send();
21
+ }
22
+ }
23
+ };
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ UnexpectedErrorHandler: require('./UnexpectedErrorHandler'),
3
+ InvalidRequestErrorHandler: require('./InvalidRequestErrorHandler'),
4
+ HandlerNotFoundErrorHandler: require('./HandlerNotFoundErrorHandler'),
5
+ LogErrorHandler: require('./LogErrorHandler'),
6
+ };
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ endpoint: require('./endpoint'),
3
+ error: require('./error'),
4
+ };
@@ -1,7 +1,6 @@
1
1
  module.exports = {
2
2
  Server: require('./Server'),
3
- LoggedServer: require('./LoggedServer'),
4
- endpoint: require('./endpoint'),
3
+ handler: require('./handler'),
5
4
  request: require('./request'),
6
- response: require('./response')
7
- }
5
+ response: require('./response'),
6
+ };
@@ -0,0 +1,87 @@
1
+ module.exports = class ChunkServerRequest {
2
+ #requestStream;
3
+ #route;
4
+ #query;
5
+ #headers;
6
+ #body;
7
+
8
+ constructor({ requestStream, route, query, headers, body }) {
9
+ this.#requestStream = requestStream;
10
+ this.#route = route;
11
+ this.#query = query;
12
+ this.#headers = headers;
13
+ this.#body = body;
14
+ }
15
+
16
+ with({
17
+ requestStream = this.#requestStream,
18
+ route = this.#route,
19
+ query = this.#query,
20
+ headers = this.#headers,
21
+ body = this.#body,
22
+ }) {
23
+ return new ChunkServerRequest({
24
+ requestStream,
25
+ route,
26
+ query,
27
+ headers,
28
+ body,
29
+ });
30
+ }
31
+
32
+ get route() {
33
+ return this.#route;
34
+ }
35
+
36
+ get query() {
37
+ return this.#query;
38
+ }
39
+
40
+ get body() {
41
+ return this.#body;
42
+ }
43
+
44
+ get headers() {
45
+ return this.#headers;
46
+ }
47
+
48
+ accept() {
49
+ return new Promise((resolve, reject) => {
50
+ try {
51
+ this.#requestStream.on('error', (e) => {
52
+ reject(
53
+ new Error('Server request error', {
54
+ cause: { error: e, code: 'REQUEST_ERROR' },
55
+ }),
56
+ );
57
+ });
58
+
59
+ let chunks = [];
60
+ this.#requestStream.on('data', (chunk) => chunks.push(chunk));
61
+ this.#requestStream.on('end', () => {
62
+ resolve(
63
+ this.with({
64
+ route: {
65
+ method: this.#requestStream.method,
66
+ path: new URL(
67
+ `http://${process.env.HOST ?? 'localhost'}${this.#requestStream.url}`,
68
+ ).pathname,
69
+ },
70
+ query: new URL(
71
+ `http://${process.env.HOST ?? 'localhost'}${this.#requestStream.url}`,
72
+ ).searchParams,
73
+ headers: new Headers(this.#requestStream.headers),
74
+ body: Buffer.concat(chunks),
75
+ }),
76
+ );
77
+ });
78
+ } catch (e) {
79
+ reject(
80
+ new Error('Server request error', {
81
+ cause: { error: e, code: 'REQUEST_ERROR' },
82
+ }),
83
+ );
84
+ }
85
+ });
86
+ }
87
+ };
@@ -0,0 +1,67 @@
1
+ module.exports = class JsonServerRequest {
2
+ #origin;
3
+
4
+ constructor({ origin }) {
5
+ this.#origin = origin;
6
+ }
7
+
8
+ with({
9
+ requestStream,
10
+ route,
11
+ query,
12
+ headers,
13
+ body,
14
+ origin = this.#origin.with({
15
+ requestStream,
16
+ route,
17
+ query,
18
+ headers,
19
+ body,
20
+ }),
21
+ }) {
22
+ return new JsonServerRequest({
23
+ origin,
24
+ });
25
+ }
26
+
27
+ get route() {
28
+ return this.#origin.route;
29
+ }
30
+
31
+ get query() {
32
+ return this.#origin.query;
33
+ }
34
+
35
+ get body() {
36
+ return this.#origin.body;
37
+ }
38
+
39
+ get headers() {
40
+ return this.#origin.headers;
41
+ }
42
+
43
+ async accept() {
44
+ const accepted = await this.#origin.accept();
45
+
46
+ try {
47
+ return this.with({
48
+ origin: accepted.with({
49
+ body:
50
+ accepted.body?.length > 0
51
+ ? JSON.parse(accepted.body?.toString())
52
+ : accepted.body,
53
+ headers: Object.fromEntries(accepted.headers),
54
+ query: Object.fromEntries(accepted.query),
55
+ }),
56
+ });
57
+ } catch (e) {
58
+ if (e instanceof SyntaxError) {
59
+ throw new Error('Invalid server json request', {
60
+ cause: { error: e, code: 'INVALID_REQUEST' },
61
+ });
62
+ }
63
+
64
+ throw e;
65
+ }
66
+ }
67
+ };
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ ChunkServerRequest: require('./ChunkServerRequest'),
3
+ JsonServerRequest: require('./JsonServerRequest'),
4
+ };
@@ -1,4 +1,3 @@
1
1
  module.exports = {
2
- InputRequest: require('./InputRequest'),
3
- LoggedInputRequest: require('./LoggedInputRequest')
4
- };
2
+ chunk: require('./chunk'),
3
+ };
@@ -0,0 +1,53 @@
1
+ module.exports = class ChunkServerResponse {
2
+ #responseStream;
3
+ #status;
4
+ #headers;
5
+ #body;
6
+
7
+ constructor({ responseStream, status = 200, headers = {}, body }) {
8
+ this.#responseStream = responseStream;
9
+ this.#status = status;
10
+ this.#headers = headers;
11
+ this.#body = body;
12
+ }
13
+
14
+ with({
15
+ responseStream = this.#responseStream,
16
+ status = this.#status,
17
+ headers = this.#headers,
18
+ body = this.#body,
19
+ }) {
20
+ return new ChunkServerResponse({
21
+ responseStream,
22
+ status,
23
+ headers,
24
+ body,
25
+ });
26
+ }
27
+
28
+ get status() {
29
+ return this.#status;
30
+ }
31
+
32
+ get headers() {
33
+ return this.#headers;
34
+ }
35
+
36
+ get body() {
37
+ return this.#body;
38
+ }
39
+
40
+ send() {
41
+ try {
42
+ this.#responseStream.writeHead(this.status, this.headers);
43
+
44
+ if (this.body != null) {
45
+ this.#responseStream.write(this.body);
46
+ }
47
+
48
+ return this;
49
+ } finally {
50
+ this.#responseStream.end();
51
+ }
52
+ }
53
+ };
@@ -0,0 +1,50 @@
1
+ module.exports = class JsonServerResponse {
2
+ #origin;
3
+
4
+ constructor({ origin }) {
5
+ this.#origin = origin;
6
+ }
7
+
8
+ with({
9
+ responseStream,
10
+ status,
11
+ headers,
12
+ body,
13
+ origin = this.#origin.with({
14
+ responseStream,
15
+ status,
16
+ headers,
17
+ body,
18
+ }),
19
+ }) {
20
+ return new JsonServerResponse({ origin });
21
+ }
22
+
23
+ get status() {
24
+ return this.#origin.status;
25
+ }
26
+
27
+ get headers() {
28
+ return {
29
+ ...this.#origin.headers,
30
+ 'content-type': 'application/json',
31
+ };
32
+ }
33
+
34
+ get body() {
35
+ return this.#origin.body
36
+ ? JSON.stringify(this.#origin.body)
37
+ : this.#origin.body;
38
+ }
39
+
40
+ send() {
41
+ return this.with({
42
+ origin: this.#origin
43
+ .with({
44
+ headers: this.headers,
45
+ body: this.body,
46
+ })
47
+ .send(),
48
+ });
49
+ }
50
+ };
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ ChunkServerResponse: require('./ChunkServerResponse'),
3
+ JsonServerResponse: require('./JsonServerResponse')
4
+ };
@@ -1,4 +1,3 @@
1
1
  module.exports = {
2
- OutputResponse: require('./OutputResponse'),
3
- LoggedOutputResponse: require('./LoggedOutputResponse')
4
- };
2
+ chunk: require('./chunk'),
3
+ };