@dooboostore/simple-boot-http-server 1.0.14 → 1.0.16

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.
package/README.MD CHANGED
@@ -198,23 +198,57 @@ const option = new HttpServerOption({
198
198
 
199
199
  Define global exception handlers in an `Advice` class. This class is managed by `@Sim` and can catch errors thrown from anywhere in the application.
200
200
 
201
+ ### Preventing `ERR_HTTP_HEADERS_SENT`
202
+
203
+ A common issue in asynchronous frameworks is the `ERR_HTTP_HEADERS_SENT` error. This occurs when an error is thrown *after* a response has already been sent by another part of the application (like a filter). The global exception handler then tries to send a *second* response, causing a crash.
204
+
205
+ To prevent this, **always check if a response has already been sent** before sending a new one from your exception handler. The `RequestResponse` object provides the `resIsDone()` method for this purpose.
206
+
201
207
  ```typescript
202
- import { Sim, ExceptionHandler } from '@dooboostore/simple-boot';
203
- import { RequestResponse, NotFoundError } from '@dooboostore/simple-boot-http-server';
208
+ import { Sim, ExceptionHandler, Inject, ExceptionHandlerSituationType } from '@dooboostore/simple-boot';
209
+ import { RequestResponse, NotFoundError, HttpError, InternalServerError, Mimes, HttpStatus } from '@dooboostore/simple-boot-http-server';
204
210
 
205
211
  @Sim
206
212
  export class GlobalErrorHandler {
213
+
207
214
  @ExceptionHandler({ type: NotFoundError })
208
215
  handleNotFound(rr: RequestResponse, e: NotFoundError) {
216
+ // Critical check
217
+ if (rr.resIsDone()) {
218
+ console.error(`Not found error for URL: ${rr.reqUrl}, but response already sent.`, e);
219
+ return;
220
+ }
209
221
  rr.resStatusCode(404).resSetHeader('X-Error-Message', 'Resource not found');
210
222
  console.error(`Not found error for URL: ${rr.reqUrl}`, e);
223
+ rr.resEnd(JSON.stringify({ error: 'Resource not found' }));
211
224
  }
212
225
 
213
226
  @ExceptionHandler()
214
- handleAll(rr: RequestResponse, e: any) {
215
- console.error('An unexpected error occurred:', e);
216
- // Avoid sending detailed error in production
217
- rr.resStatusCode(500).resWriteJson({ error: 'Internal Server Error' });
227
+ async catch(@Inject({situationType: ExceptionHandlerSituationType.ERROR_OBJECT}) e: any, rr: RequestResponse) {
228
+ console.error(`GlobalAdvice.catch ${rr.reqUrl}`, e);
229
+
230
+ // Critical check to prevent writing to an already-sent response
231
+ if (rr.resIsDone()) {
232
+ return;
233
+ }
234
+
235
+ rr.resStatusCode(HttpStatus.InternalServerError);
236
+ rr.resSetHeader('Content-Type', Mimes.ApplicationJson);
237
+
238
+ let data = '';
239
+ if (e instanceof HttpError) {
240
+ rr.resStatusCode(e.status);
241
+ data = JSON.stringify(e);
242
+ } else if (e instanceof Error){
243
+ const error = new InternalServerError();
244
+ error.data = {message: e.message, stack: e.stack}; // Be careful with stack in production
245
+ data = JSON.stringify(error);
246
+ } else {
247
+ const error = new InternalServerError();
248
+ error.data = e;
249
+ data = JSON.stringify(error);
250
+ }
251
+ await rr.resEnd(data);
218
252
  }
219
253
  }
220
254
 
@@ -1,5 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
1
  import { SimpleApplication } from '@dooboostore/simple-boot/SimpleApplication';
4
2
  import { HttpServerOption } from './option/HttpServerOption';
5
3
  import { ConstructorType } from '@dooboostore/core/types';
@@ -18,7 +18,7 @@ import { HttpHeaders } from './codes/HttpHeaders';
18
18
  import { Mimes } from './codes/Mimes';
19
19
  import { ExceptionHandlerSituationType, targetExceptionHandler } from '@dooboostore/simple-boot/decorators/exception/ExceptionDecorator';
20
20
  import { getInject, SituationTypeContainer, SituationTypeContainers } from '@dooboostore/simple-boot/decorators/inject/Inject';
21
- import { ReflectUtils } from '@dooboostore/simple-boot/utils/reflect/ReflectUtils';
21
+ import { ReflectUtils } from '@dooboostore/core/reflect/ReflectUtils';
22
22
  import { ReqFormUrlBody } from './models/datas/body/ReqFormUrlBody';
23
23
  import { ReqJsonBody } from './models/datas/body/ReqJsonBody';
24
24
  import { ReqHeader } from './models/datas/ReqHeader';
@@ -1,5 +1,5 @@
1
1
  import 'reflect-metadata';
2
- import { ReflectUtils } from '@dooboostore/simple-boot/utils/reflect/ReflectUtils';
2
+ import { ReflectUtils } from '@dooboostore/core/reflect/ReflectUtils';
3
3
  import { HttpMethod } from '../codes/HttpMethod';
4
4
  export var UrlMappingSituationType;
5
5
  (function (UrlMappingSituationType) {
@@ -13,8 +13,8 @@ export class CrossDomainHeaderEndPoint {
13
13
  this.config = config;
14
14
  }
15
15
  endPoint(rr, app) {
16
- var _a, _b, _c, _d;
17
16
  return __awaiter(this, void 0, void 0, function* () {
17
+ var _a, _b, _c, _d;
18
18
  if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.accessControlAllowOrigin) {
19
19
  rr.resSetHeader(HttpHeaders.AccessControlAllowOrigin, Array.isArray(this.config.accessControlAllowOrigin) ? this.config.accessControlAllowOrigin.join(', ') : this.config.accessControlAllowOrigin);
20
20
  }
@@ -22,11 +22,11 @@ export class CacheFilter {
22
22
  return __awaiter(this, void 0, void 0, function* () {
23
23
  });
24
24
  }
25
- proceedBefore({ rr, app, carrier }) {
26
- var _a, _b, _c, _d, _e, _f, _g;
27
- var _h, _j, _k;
28
- return __awaiter(this, void 0, void 0, function* () {
29
- const filter = (_b = (_a = this.config).filter) === null || _b === void 0 ? void 0 : _b.call(_a, rr, app);
25
+ proceedBefore(_a) {
26
+ return __awaiter(this, arguments, void 0, function* ({ rr, app, carrier }) {
27
+ var _b, _c, _d, _e, _f, _g, _h;
28
+ var _j, _k, _l;
29
+ const filter = (_c = (_b = this.config).filter) === null || _c === void 0 ? void 0 : _c.call(_b, rr, app);
30
30
  if (!filter) {
31
31
  return true;
32
32
  }
@@ -41,16 +41,16 @@ export class CacheFilter {
41
41
  }
42
42
  }
43
43
  const date = new Date().toISOString();
44
- (_c = this.cacheConfig) !== null && _c !== void 0 ? _c : (this.cacheConfig = {
44
+ (_d = this.cacheConfig) !== null && _d !== void 0 ? _d : (this.cacheConfig = {
45
45
  createDate: date,
46
46
  updateDate: date,
47
47
  caches: {}
48
48
  });
49
- (_d = (_h = this.cacheConfig).createDate) !== null && _d !== void 0 ? _d : (_h.createDate = date);
50
- (_e = (_j = this.cacheConfig).updateDate) !== null && _e !== void 0 ? _e : (_j.updateDate = date);
51
- (_f = (_k = this.cacheConfig).caches) !== null && _f !== void 0 ? _f : (_k.caches = {});
49
+ (_e = (_j = this.cacheConfig).createDate) !== null && _e !== void 0 ? _e : (_j.createDate = date);
50
+ (_f = (_k = this.cacheConfig).updateDate) !== null && _f !== void 0 ? _f : (_k.updateDate = date);
51
+ (_g = (_l = this.cacheConfig).caches) !== null && _g !== void 0 ? _g : (_l.caches = {});
52
52
  const rkey = this.config.key(rr, app);
53
- const sessionData = { key: rkey.key, lifeTime: (_g = rkey.lifeTime) !== null && _g !== void 0 ? _g : this.config.config.lifeTime, isUpdate: false, responseHeaders: rkey.responseHeaders };
53
+ const sessionData = { key: rkey.key, lifeTime: (_h = rkey.lifeTime) !== null && _h !== void 0 ? _h : this.config.config.lifeTime, isUpdate: false, responseHeaders: rkey.responseHeaders };
54
54
  const cache = this.cacheConfig.caches[sessionData.key];
55
55
  if (cache) {
56
56
  const existes = this.config.config.cacheDir ? FileUtils.existesSync(cache.path) : this.storage.has(cache.path);
@@ -89,10 +89,10 @@ export class CacheFilter {
89
89
  getChunk(path) {
90
90
  return this.config.config.cacheDir ? FileUtils.readSync(path) : this.storage.get(path);
91
91
  }
92
- proceedAfter({ rr, app, carrier }) {
93
- var _a, _b;
94
- var _c;
95
- return __awaiter(this, void 0, void 0, function* () {
92
+ proceedAfter(_a) {
93
+ return __awaiter(this, arguments, void 0, function* ({ rr, app, carrier }) {
94
+ var _b, _c;
95
+ var _d;
96
96
  const sessionData = carrier.get(CacheFilter.CARRIER_KEY_NAME);
97
97
  if (sessionData && sessionData.isUpdate) {
98
98
  try {
@@ -108,10 +108,10 @@ export class CacheFilter {
108
108
  p = this.writeChunk(destFileUUID, resBody);
109
109
  const updateDateNow = Date.now();
110
110
  const updateDate = new Date(updateDateNow).toISOString();
111
- (_a = (_c = this.cacheConfig).createDate) !== null && _a !== void 0 ? _a : (_c.createDate = updateDate);
111
+ (_b = (_d = this.cacheConfig).createDate) !== null && _b !== void 0 ? _b : (_d.createDate = updateDate);
112
112
  this.cacheConfig.updateDate = updateDate;
113
113
  const responseHeaders = {};
114
- (_b = sessionData.responseHeaders) === null || _b === void 0 ? void 0 : _b.map(it => it.toLowerCase()).forEach(it => {
114
+ (_c = sessionData.responseHeaders) === null || _c === void 0 ? void 0 : _c.map(it => it.toLowerCase()).forEach(it => {
115
115
  responseHeaders[it] = rr.resHeader(it);
116
116
  });
117
117
  this.cacheConfig.caches[sessionData.key] = {
@@ -11,15 +11,15 @@ export class HttpStatusFilter {
11
11
  constructor(httpStatus) {
12
12
  this.httpStatus = httpStatus;
13
13
  }
14
- proceedBefore({ rr, app }) {
15
- return __awaiter(this, void 0, void 0, function* () {
14
+ proceedBefore(_a) {
15
+ return __awaiter(this, arguments, void 0, function* ({ rr, app }) {
16
16
  rr.resStatusCode(this.httpStatus);
17
17
  rr.resEnd();
18
18
  return false;
19
19
  });
20
20
  }
21
- proceedAfter({ rr, app }) {
22
- return __awaiter(this, void 0, void 0, function* () {
21
+ proceedAfter(_a) {
22
+ return __awaiter(this, arguments, void 0, function* ({ rr, app }) {
23
23
  return true;
24
24
  });
25
25
  }
@@ -25,8 +25,8 @@ export class OpenApi3Filter {
25
25
  return __awaiter(this, void 0, void 0, function* () {
26
26
  });
27
27
  }
28
- proceedBefore({ rr, app }) {
29
- return __awaiter(this, void 0, void 0, function* () {
28
+ proceedBefore(_a) {
29
+ return __awaiter(this, arguments, void 0, function* ({ rr, app }) {
30
30
  if (rr.reqUrl === this.config.path) {
31
31
  const map = app.routerManager.routingMap();
32
32
  const data = {
@@ -48,8 +48,8 @@ export class OpenApi3Filter {
48
48
  return true;
49
49
  });
50
50
  }
51
- proceedAfter({ rr, app }) {
52
- return __awaiter(this, void 0, void 0, function* () {
51
+ proceedAfter(_a) {
52
+ return __awaiter(this, arguments, void 0, function* ({ rr, app }) {
53
53
  return true;
54
54
  });
55
55
  }
@@ -21,10 +21,10 @@ export class ResourceFilter {
21
21
  return __awaiter(this, void 0, void 0, function* () {
22
22
  });
23
23
  }
24
- proceedBefore({ rr, app }) {
25
- var _a;
26
- return __awaiter(this, void 0, void 0, function* () {
27
- const url = ((_a = rr.reqUrlPathName) !== null && _a !== void 0 ? _a : '').replace(/\.\./g, '');
24
+ proceedBefore(_a) {
25
+ return __awaiter(this, arguments, void 0, function* ({ rr, app }) {
26
+ var _b;
27
+ const url = ((_b = rr.reqUrlPathName) !== null && _b !== void 0 ? _b : '').replace(/\.\./g, '');
28
28
  const urlObj = rr.reqUrlObject;
29
29
  let sw = true;
30
30
  const regExps = this.resourceRegex.filter(it => {
@@ -63,8 +63,8 @@ export class ResourceFilter {
63
63
  return sw;
64
64
  });
65
65
  }
66
- proceedAfter({ rr, app }) {
67
- return __awaiter(this, void 0, void 0, function* () {
66
+ proceedAfter(_a) {
67
+ return __awaiter(this, arguments, void 0, function* ({ rr, app }) {
68
68
  return true;
69
69
  });
70
70
  }
@@ -15,13 +15,13 @@ export class ThrowFilter {
15
15
  return __awaiter(this, void 0, void 0, function* () {
16
16
  });
17
17
  }
18
- proceedBefore({ rr, app }) {
19
- return __awaiter(this, void 0, void 0, function* () {
18
+ proceedBefore(_a) {
19
+ return __awaiter(this, arguments, void 0, function* ({ rr, app }) {
20
20
  return true;
21
21
  });
22
22
  }
23
- proceedAfter({ rr, app }) {
24
- return __awaiter(this, void 0, void 0, function* () {
23
+ proceedAfter(_a) {
24
+ return __awaiter(this, arguments, void 0, function* ({ rr, app }) {
25
25
  const sw = rr.resIsDone();
26
26
  if (!sw) {
27
27
  throw this.error;
@@ -1,8 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
- /// <reference types="node" />
4
- /// <reference types="node" />
5
- /// <reference types="node" />
6
1
  import { IncomingMessage, OutgoingHttpHeader, OutgoingHttpHeaders, ServerResponse } from 'http';
7
2
  import { HttpHeaders } from '../codes/HttpHeaders';
8
3
  import { Mimes } from '../codes/Mimes';
@@ -78,8 +73,8 @@ export declare class RequestResponse {
78
73
  reqSessionSet(key: string, value: any): void;
79
74
  reqSessionGet<T = any>(key: string): T | undefined;
80
75
  resSetStatusCode(statusCode: number): RequestResponseChain<number>;
81
- resWrite(chunk: string | Buffer | any, encoding?: BufferEncoding): RequestResponseChain<string | Buffer>;
82
- resWriteJson(chunk: any, encoding?: BufferEncoding): RequestResponseChain<string | Buffer>;
76
+ resWrite(chunk: string | Buffer | any, encoding?: BufferEncoding): RequestResponseChain<string | Buffer<ArrayBufferLike>>;
77
+ resWriteJson(chunk: any, encoding?: BufferEncoding): RequestResponseChain<string | Buffer<ArrayBufferLike>>;
83
78
  resSetHeader(key: HttpHeaders | string, value: string | string[]): RequestResponseChain<ServerResponse<IncomingMessage>>;
84
79
  resAddHeader(key: HttpHeaders | string, value: string | string[]): RequestResponseChain<ServerResponse<IncomingMessage>>;
85
80
  resSetHeaders(headers: {
@@ -1,5 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
1
  export type MultipartData = {
4
2
  isFile: true;
5
3
  name: string;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { IncomingHttpHeaders } from 'http';
3
2
  export declare class ReqHeader implements IncomingHttpHeaders {
4
3
  [key: string]: string | string[] | undefined;
@@ -1,5 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
1
  import { InitOptionType, SimOption } from '@dooboostore/simple-boot/SimOption';
4
2
  import { ConstructorType } from '@dooboostore/core/types';
5
3
  import { Server as HttpServer, ServerOptions } from 'http';
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@dooboostore/simple-boot-http-server",
3
- "version": "1.0.14",
4
- "main": "dist/SimpleBootHttpServer.js",
3
+ "version": "1.0.16",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
5
6
  "license": "MIT",
6
7
  "description": "back end http server frameworks",
7
8
  "files": [
@@ -51,7 +52,7 @@
51
52
  "ts-node": "^10.0.0",
52
53
  "ts-node-dev": "^1.1.8",
53
54
  "tsconfig-paths": "^3.9.0",
54
- "typescript": "^4.4.3"
55
+ "typescript": "^5.9.2"
55
56
  },
56
57
  "dependencies": {
57
58
  "@types/node-gzip": "^1.1.0",
@@ -59,17 +60,16 @@
59
60
  "mime-types": "^2.1.34",
60
61
  "node-gzip": "^1.1.2",
61
62
  "reflect-metadata": "^0.2.2",
62
- "canvas": "^3.1.0",
63
- "@dooboostore/core": "1.0.7",
63
+ "@dooboostore/core": "1.0.8",
64
+ "@dooboostore/dom-render": "1.0.102",
64
65
  "@dooboostore/core-node": "1.0.1",
65
66
  "@dooboostore/core-web": "1.0.1",
66
- "@dooboostore/dom-render": "1.0.99",
67
- "@dooboostore/simple-boot": "1.0.43"
67
+ "@dooboostore/simple-boot": "1.0.44"
68
68
  },
69
69
  "scripts": {
70
- "build": "rm -rf dist && tsc -p tsconfig.build.json",
70
+ "tsc:build": "rm -rf dist && tsc -p tsconfig.build.json",
71
71
  "clean": "rm -rf dist",
72
- "npm:build": "pnpm run build && cp README.MD dist/ && pnpm pack && TARBALL_NAME=$(ls dooboostore-simple-boot-http-server-*.tgz | head -n 1) && tar -xzf \"$TARBALL_NAME\" -C dist --strip-components=1 package/package.json && rm \"$TARBALL_NAME\"",
72
+ "npm:build": "pnpm run clean && pnpm run tsc:build && cp README.MD dist/ && pnpm pack && TARBALL_NAME=$(ls dooboostore-simple-boot-http-server-*.tgz | head -n 1) && tar -xzf \"$TARBALL_NAME\" -C dist --strip-components=1 package/package.json && rm \"$TARBALL_NAME\"",
73
73
  "npm:clean": "rm -rf dist",
74
74
  "npm:publish": "pnpm run npm:build && cd dist && pnpm publish --no-git-checks",
75
75
  "npm:publish:clean": "pnpm run npm:publish && rm -rf dist",
@@ -25,8 +25,8 @@ export class SessionManager {
25
25
  }), this.sessionOption.expiredTime);
26
26
  }
27
27
  getSessionUUIDs() {
28
- var _a;
29
28
  return __awaiter(this, void 0, void 0, function* () {
29
+ var _a;
30
30
  if ((_a = this.sessionOption.provider) === null || _a === void 0 ? void 0 : _a.uuids) {
31
31
  return this.sessionOption.provider.uuids();
32
32
  }
@@ -36,8 +36,8 @@ export class SessionManager {
36
36
  });
37
37
  }
38
38
  deleteSession(uuid) {
39
- var _a;
40
39
  return __awaiter(this, void 0, void 0, function* () {
40
+ var _a;
41
41
  if ((_a = this.sessionOption.provider) === null || _a === void 0 ? void 0 : _a.delete) {
42
42
  this.sessionOption.provider.delete(uuid);
43
43
  }
@@ -47,8 +47,8 @@ export class SessionManager {
47
47
  });
48
48
  }
49
49
  getSessionDataSet(uuid) {
50
- var _a;
51
50
  return __awaiter(this, void 0, void 0, function* () {
51
+ var _a;
52
52
  if ((_a = this.sessionOption.provider) === null || _a === void 0 ? void 0 : _a.get) {
53
53
  return this.sessionOption.provider.get(uuid);
54
54
  }
@@ -58,8 +58,8 @@ export class SessionManager {
58
58
  });
59
59
  }
60
60
  setSessionDataSet(uuid, dataSet) {
61
- var _a;
62
61
  return __awaiter(this, void 0, void 0, function* () {
62
+ var _a;
63
63
  if ((_a = this.sessionOption.provider) === null || _a === void 0 ? void 0 : _a.set) {
64
64
  this.sessionOption.provider.set(uuid, dataSet);
65
65
  }
@@ -75,8 +75,8 @@ export class SessionManager {
75
75
  return RandomUtils.uuid('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
76
76
  }
77
77
  session(rrOrUUID) {
78
- var _a;
79
78
  return __awaiter(this, void 0, void 0, function* () {
79
+ var _a;
80
80
  let uuid;
81
81
  if (rrOrUUID instanceof RequestResponse) {
82
82
  uuid = (_a = rrOrUUID.reqCookieGet(this.sessionOption.key)) !== null && _a !== void 0 ? _a : this.makeUUID();