objective-http 1.3.0 → 2.0.1

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 (58) hide show
  1. package/README.md +102 -191
  2. package/package.json +43 -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 -6
  13. package/src/js/server/Server.js +42 -60
  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 -4
  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 -4
  34. package/src/js/bun/Bunttp.js +0 -28
  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 -50
  43. package/src/js/bun/server/request/index.js +0 -3
  44. package/src/js/bun/server/response/OutputResponse.js +0 -49
  45. package/src/js/bun/server/response/index.js +0 -3
  46. package/src/js/client/request/OutputRequest.js +0 -81
  47. package/src/js/client/response/InputResponse.js +0 -58
  48. package/src/js/server/LoggedServer.js +0 -30
  49. package/src/js/server/endpoint/Endpoint.js +0 -24
  50. package/src/js/server/endpoint/Endpoints.js +0 -26
  51. package/src/js/server/endpoint/LoggedEndpoint.js +0 -30
  52. package/src/js/server/endpoint/index.js +0 -5
  53. package/src/js/server/request/InputRequest.js +0 -58
  54. package/src/js/server/request/JsonInputRequest.js +0 -51
  55. package/src/js/server/request/LoggedInputRequest.js +0 -44
  56. package/src/js/server/response/JsonOutputResponse.js +0 -45
  57. package/src/js/server/response/LoggedOutputResponse.js +0 -36
  58. package/src/js/server/response/OutputResponse.js +0 -52
@@ -1,28 +0,0 @@
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
- return new Bunttp({fetch: cb});
12
- }
13
-
14
- listen(options, cb) {
15
- const config = {...this.#serverConfig, port: options.port};
16
- const server = Bun.serve(config);
17
- cb();
18
- return new Bunttp(config, server);
19
- }
20
-
21
- close(cb) {
22
- const server = this.#server.stop();
23
- cb();
24
- return new Bunttp(this.#serverConfig, server);
25
- }
26
-
27
- request = fetch;
28
- }
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- request: require('./request'),
3
- response: require('./response')
4
- }
@@ -1,26 +0,0 @@
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
- }
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- OutputRequest: require('./OutputRequest')
3
- };
@@ -1,40 +0,0 @@
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
- }
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- InputResponse: require('./InputResponse')
3
- };
@@ -1,5 +0,0 @@
1
- module.exports = {
2
- server: require('./server'),
3
- client: require('./client'),
4
- bunttp: new (require('./Bunttp'))()
5
- }
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- request: require('./request'),
3
- response: require('./response')
4
- }
@@ -1,50 +0,0 @@
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
- }
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- InputRequest: require('./InputRequest')
3
- };
@@ -1,49 +0,0 @@
1
- module.exports = class OutputResponse {
2
- #options;
3
- #outputStream;
4
-
5
- constructor(options, outputStream) {
6
- this.#options = {...{statusCode: 200, headers: {}}, ...options};
7
- this.#outputStream = outputStream;
8
- }
9
-
10
- copy(options = this.#options, outputStream = this.#outputStream) {
11
- return new OutputResponse({...{statusCode: 200, headers: {}}, ...options}, outputStream);
12
- }
13
-
14
- update(options) {
15
- return new OutputResponse(this.#mergeOptions(this.#options, options), this.#outputStream);
16
- }
17
-
18
- flush() {
19
- try {
20
- return new Response(this.#options.body, {
21
- status: this.#options.statusCode,
22
- headers: this.#options.headers
23
- });
24
-
25
- } catch (e) {
26
- throw new Error(e.message, {cause: 'INVALID_RESPONSE'});
27
- }
28
- }
29
-
30
- #mergeOptions(existedOptions, newOptions) {
31
- if (newOptions == null) {
32
- return existedOptions;
33
- }
34
-
35
- if (newOptions.statusCode != null) {
36
- existedOptions.statusCode = newOptions.statusCode;
37
- }
38
-
39
- if (newOptions.body != null) {
40
- existedOptions.body = newOptions.body;
41
- }
42
-
43
- if (newOptions.headers != null) {
44
- existedOptions.headers = {...existedOptions.headers, ...newOptions.headers};
45
- }
46
-
47
- return existedOptions;
48
- }
49
- }
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- OutputResponse: require('./OutputResponse')
3
- };
@@ -1,81 +0,0 @@
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 = {method: 'GET', ...options};
10
- }
11
-
12
- copy(options = this.#options, response = this.#response, http = this.#requestFunction) {
13
- return new OutputRequest(response, http, {method: 'GET', ...options});
14
- }
15
-
16
- async send() {
17
- try {
18
- return await new Promise((resolve, reject) => {
19
- this.#sendRequestOutputStream(
20
- this.#configureRequestOutputStream(this.#requestFunction, this.#response, this.#options, resolve, reject),
21
- this.#options,
22
- reject);
23
- });
24
-
25
- } catch (e) {
26
- if (e.cause == null) {
27
- throw new Error(e.message, {cause: 'INVALID_REQUEST'});
28
- }
29
-
30
- throw e;
31
- }
32
- }
33
-
34
- #sendRequestOutputStream(requestOutputStream, options, reject) {
35
- try {
36
- requestOutputStream.once('error', e => reject(e));
37
-
38
- if (this.#needToByWritten(options)) {
39
- requestOutputStream.write(options.body);
40
- }
41
-
42
- requestOutputStream.end();
43
-
44
- } catch (e) {
45
- reject(e);
46
- }
47
- }
48
-
49
- #needToByWritten(options) {
50
- return ['POST', 'PUT'].some(method => method === options.method.toString().toUpperCase())
51
- && (options.body != null && typeof options.body === 'string');
52
- }
53
-
54
- #configureRequestOutputStream(requestFunction, response, options, resolve, reject) {
55
- if (options.url != null) {
56
- return requestFunction(
57
- options.url,
58
- options,
59
- async (responseInputStream) => {
60
- await this.#flushResponseInputStream(responseInputStream, response, resolve, reject);
61
- });
62
- }
63
-
64
- return requestFunction(
65
- options,
66
- async (responseInputStream) => {
67
- await this.#flushResponseInputStream(responseInputStream, response, resolve, reject);
68
- });
69
- }
70
-
71
- async #flushResponseInputStream(responseInputStream, response, resolve, reject) {
72
- try {
73
- resolve(await response
74
- .copy(responseInputStream)
75
- .flush());
76
-
77
- } catch (e) {
78
- reject(e);
79
- }
80
- }
81
- };
@@ -1,58 +0,0 @@
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
- statusCode() {
15
- return this.#options.statusCode;
16
- }
17
-
18
- headers() {
19
- return this.#options.headers;
20
- }
21
-
22
- body() {
23
- return this.#options.body;
24
- }
25
-
26
- async flush() {
27
- try {
28
- return await new Promise((resolve, reject) => {
29
- this.#flushResponseInputStream(this.#inputStream, resolve, reject);
30
- });
31
-
32
- } catch (e) {
33
- throw new Error(e.message, {cause: 'INVALID_RESPONSE'});
34
- }
35
- }
36
-
37
- #flushResponseInputStream(inputStream, resolve, reject) {
38
- try {
39
- inputStream.once('error', (e) => reject(e));
40
-
41
- let chunks = [];
42
- inputStream.on('data', (chunk) => chunks.push(chunk));
43
- inputStream.on('end', () => resolve(
44
- new InputResponse(
45
- inputStream,
46
- {
47
- statusCode: inputStream.statusCode,
48
- headers: new Headers(inputStream.headers),
49
- body: Buffer.concat(chunks)
50
- }
51
- )
52
- ));
53
-
54
- } catch (e) {
55
- reject(e);
56
- }
57
- }
58
- };
@@ -1,30 +0,0 @@
1
- module.exports = class LoggedServer {
2
- #origin;
3
- #logger;
4
-
5
- constructor(origin, logger) {
6
- this.#origin = origin;
7
- this.#logger = logger;
8
- }
9
-
10
- async start() {
11
- const server = await this.#origin.start();
12
-
13
- this.#logger.debug(`HttpServer is running at port: ${server.options().port}`);
14
-
15
- return new LoggedServer(server, this.#logger);
16
- }
17
-
18
- async stop() {
19
- const server = await this.#origin.stop();
20
-
21
- this.#logger.debug(`HttpServer at port: ${server.options().port} is stopped`);
22
-
23
- return new LoggedServer(server, this.#logger);
24
- }
25
-
26
-
27
- options() {
28
- return this.#origin.options();
29
- }
30
- }
@@ -1,24 +0,0 @@
1
- module.exports = class Endpoint {
2
- #method;
3
- #path;
4
-
5
- constructor(method, path) {
6
- this.#method = method;
7
- this.#path = path;
8
- }
9
-
10
- copy(method = this.#method, path = this.#path) {
11
- return new Endpoint(method, path);
12
- }
13
-
14
- route() {
15
- return {
16
- method: this.#method.toString().toUpperCase(),
17
- path: this.#path.toString().toLowerCase()
18
- };
19
- }
20
-
21
- async handle(request) {
22
- return {};
23
- }
24
- }
@@ -1,26 +0,0 @@
1
- module.exports = class Endpoints {
2
- #collection;
3
-
4
- constructor(collection = []) {
5
- this.#collection = collection;
6
- }
7
-
8
- copy(collection = this.#collection) {
9
- return new Endpoints(collection);
10
- }
11
-
12
- async handle(request) {
13
- const endpoint = this.#collection
14
- .find(endpoint => endpoint.route().method === request.route().method
15
- && endpoint.route().path === request.route().path);
16
-
17
- if (endpoint == null) {
18
- return {
19
- statusCode: 501,
20
- body: 'There are no handler for request.'
21
- }
22
- }
23
-
24
- return await endpoint.handle(request);
25
- }
26
- }
@@ -1,30 +0,0 @@
1
- module.exports = class LoggedEndpoint {
2
- #origin;
3
- #logger;
4
-
5
- constructor(origin, logger) {
6
- this.#origin = origin;
7
- this.#logger = logger;
8
- }
9
-
10
- copy(method, path, logger = this.#logger, origin = this.#origin.copy(method, path)) {
11
- return new LoggedEndpoint(origin, logger);
12
- }
13
-
14
- route() {
15
- return this.#origin.route();
16
- }
17
-
18
- async handle(request) {
19
- this.#logger.debug(`HttpEndpoint's handling [${request.route().method}] ${request.route().path}`);
20
-
21
- try {
22
- return await this.#origin.handle(request);
23
-
24
- } catch (e) {
25
- this.#logger.error(`HttpEndpoint's handling [${request.route().method}] ${request.route().path} error: ${e.message}`, e);
26
-
27
- throw e;
28
- }
29
- }
30
- }
@@ -1,5 +0,0 @@
1
- module.exports = {
2
- Endpoint: require('./Endpoint'),
3
- LoggedEndpoint: require('./LoggedEndpoint'),
4
- Endpoints: require('./Endpoints'),
5
- };
@@ -1,58 +0,0 @@
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
- flush() {
15
- return new Promise((resolve, reject) => {
16
- try {
17
- this.#inputStream.once('error', (e) =>
18
- reject(new Error(e.message, {cause: 'INVALID_REQUEST'}))
19
- );
20
-
21
- let chunks = [];
22
- this.#inputStream.on('data', (chunk) => chunks.push(chunk));
23
- this.#inputStream.on('end', () => resolve(new InputRequest(
24
- this.#inputStream,
25
- {
26
- method: this.#inputStream.method,
27
- path: new URL(this.#inputStream.url, 'http://dummy').pathname,
28
- query: new URL(this.#inputStream.url, 'http://dummy').searchParams,
29
- headers: new Headers(this.#inputStream.headers),
30
- body: Buffer.concat(chunks)
31
- }
32
- )));
33
-
34
- } catch (e) {
35
- throw new Error(e.message, {cause: 'INVALID_REQUEST'});
36
- }
37
- });
38
- }
39
-
40
- route() {
41
- return {
42
- method: this.#options.method.toString().toUpperCase(),
43
- path: this.#options.path.toString().toLowerCase()
44
- };
45
- }
46
-
47
- query() {
48
- return this.#options.query;
49
- }
50
-
51
- body() {
52
- return this.#options.body;
53
- }
54
-
55
- headers() {
56
- return this.#options.headers;
57
- }
58
- };
@@ -1,51 +0,0 @@
1
- module.exports = class JsonInputRequest {
2
- #origin;
3
- #inputStream;
4
-
5
- constructor(origin, inputStream) {
6
- this.#origin = origin;
7
- this.#inputStream = inputStream;
8
- }
9
-
10
- copy(inputStream, options, origin = this.#origin.copy(inputStream, options)) {
11
- return new JsonInputRequest(origin, inputStream);
12
- }
13
-
14
- async flush() {
15
- if (this.#useChunkMethod(this.#inputStream.method) && !this.#validHeaders(new Headers(this.#inputStream.headers))) {
16
- throw new Error('Wrong content-type. Only application/json accepted.', {cause: 'INVALID_REQUEST'});
17
- }
18
-
19
- return new JsonInputRequest(await this.#origin.flush(), this.#inputStream);
20
- }
21
-
22
- route() {
23
- return this.#origin.route();
24
- }
25
-
26
- query() {
27
- return this.#origin.query();
28
- }
29
-
30
- body() {
31
- try {
32
- return JSON.parse(this.#origin.body().toString());
33
-
34
- } catch (e) {
35
- throw new Error('Wrong body format. Only JSON accepted.', {cause: 'INVALID_REQUEST'});
36
- }
37
- }
38
-
39
- headers() {
40
- return this.#origin.headers();
41
- }
42
-
43
- #useChunkMethod(requestMethod) {
44
- return ['POST', 'PUT'].some(method => method === requestMethod.toString().toUpperCase())
45
- }
46
-
47
- #validHeaders(requestHeaders) {
48
- return new Headers(requestHeaders).has('content-type')
49
- && new RegExp('^application\/json').test(new Headers(requestHeaders).get('content-type'));
50
- }
51
- }
@@ -1,44 +0,0 @@
1
- module.exports = class LoggedInputRequest {
2
- #origin;
3
- #inputStream;
4
- #logger;
5
-
6
- constructor(origin, logger, inputStream) {
7
- this.#origin = origin;
8
- this.#logger = logger;
9
- this.#inputStream = inputStream;
10
- }
11
-
12
- copy(inputStream, options, logger = this.#logger, origin = this.#origin.copy(inputStream, options)) {
13
- return new LoggedInputRequest(origin, logger, inputStream);
14
- }
15
-
16
- async flush() {
17
- this.#logger.debug(`HttpRequest: [${this.#inputStream.method}] ${this.#inputStream.url} ${JSON.stringify(this.#inputStream.headers)}`);
18
-
19
- try {
20
- return new LoggedInputRequest(await this.#origin.flush(), this.#logger);
21
-
22
- } catch (e) {
23
- this.#logger.error(`HttpRequest: [${this.#inputStream.method}] ${this.#inputStream.url} error: ${e.message}`, e);
24
-
25
- throw e;
26
- }
27
- }
28
-
29
- route() {
30
- return this.#origin.route();
31
- }
32
-
33
- query() {
34
- return this.#origin.query();
35
- }
36
-
37
- body() {
38
- return this.#origin.body();
39
- }
40
-
41
- headers() {
42
- return this.#origin.headers();
43
- }
44
- }