@things-factory/shell 9.0.25 → 9.0.34

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.
Files changed (29) hide show
  1. package/dist-server/process-cleaner.d.ts +33 -0
  2. package/dist-server/process-cleaner.js +70 -75
  3. package/dist-server/process-cleaner.js.map +1 -1
  4. package/dist-server/pubsub.js +0 -23
  5. package/dist-server/pubsub.js.map +1 -1
  6. package/dist-server/server-dev.js +1 -0
  7. package/dist-server/server-dev.js.map +1 -1
  8. package/dist-server/server.js +1 -0
  9. package/dist-server/server.js.map +1 -1
  10. package/dist-server/tsconfig.tsbuildinfo +1 -1
  11. package/dist-server/utils/headless-pool/browser-factory.d.ts +27 -0
  12. package/dist-server/utils/headless-pool/browser-factory.js +144 -0
  13. package/dist-server/utils/headless-pool/browser-factory.js.map +1 -0
  14. package/dist-server/utils/headless-pool/config.d.ts +25 -0
  15. package/dist-server/utils/headless-pool/config.js +72 -0
  16. package/dist-server/utils/headless-pool/config.js.map +1 -0
  17. package/dist-server/utils/headless-pool/index.d.ts +98 -0
  18. package/dist-server/utils/headless-pool/index.js +131 -0
  19. package/dist-server/utils/headless-pool/index.js.map +1 -0
  20. package/dist-server/utils/headless-pool/pool-manager.d.ts +59 -0
  21. package/dist-server/utils/headless-pool/pool-manager.js +212 -0
  22. package/dist-server/utils/headless-pool/pool-manager.js.map +1 -0
  23. package/dist-server/utils/headless-pool/pool-stats.d.ts +29 -0
  24. package/dist-server/utils/headless-pool/pool-stats.js +80 -0
  25. package/dist-server/utils/headless-pool/pool-stats.js.map +1 -0
  26. package/dist-server/utils/index.d.ts +1 -0
  27. package/dist-server/utils/index.js +1 -0
  28. package/dist-server/utils/index.js.map +1 -1
  29. package/package.json +4 -2
@@ -1 +1,34 @@
1
+ /**
2
+ * Process Exit Handlers for Things Factory
3
+ *
4
+ * === SIGNAL HANDLER CONFLICTS ISSUE (2025-09-01) ===
5
+ *
6
+ * PROBLEM:
7
+ * - Multiple libraries (Apollo Server, Puppeteer) automatically register SIGINT/SIGTERM handlers
8
+ * - This caused handler conflicts and prevented proper cleanup of headless Chrome processes
9
+ * - Up to 6+ handlers were registered simultaneously, causing interference
10
+ *
11
+ * ROOT CAUSE:
12
+ * - Apollo Server: Automatic graceful shutdown handlers
13
+ * - Puppeteer: Browser cleanup on process exit handlers
14
+ * - Our code: Custom cleanup handlers
15
+ * - Result: Multiple handlers competing to exit process, causing premature termination before cleanup completed
16
+ *
17
+ * SOLUTION:
18
+ * 1. Apollo Server: Added `stopOnTerminationSignals: false` in server.ts & server-dev.ts
19
+ * 2. Puppeteer: Added `handleSIGINT: false, handleSIGTERM: false, handleSIGHUP: false` in browser-factory.ts
20
+ * 3. Unified cleanup: Single handler in this file manages all cleanup (headless pools, pubsub, etc.)
21
+ * 4. Simplified pool cleanup: Direct `drain() -> clear()` without complex fallbacks
22
+ *
23
+ * LESSON LEARNED:
24
+ * - Always check for signal handler conflicts when multiple libraries are involved
25
+ * - Keep cleanup logic simple - complex fallbacks often cause more problems
26
+ * - Document these kinds of integration issues for future reference
27
+ *
28
+ * FILES MODIFIED:
29
+ * - server.ts: stopOnTerminationSignals: false
30
+ * - server-dev.ts: stopOnTerminationSignals: false
31
+ * - browser-factory.ts: handleSIGINT/SIGTERM: false
32
+ * - pool-manager.ts: simplified cleanup logic
33
+ */
1
34
  export declare function setupProcessExitHandlers(): void;
@@ -1,92 +1,87 @@
1
1
  "use strict";
2
+ /**
3
+ * Process Exit Handlers for Things Factory
4
+ *
5
+ * === SIGNAL HANDLER CONFLICTS ISSUE (2025-09-01) ===
6
+ *
7
+ * PROBLEM:
8
+ * - Multiple libraries (Apollo Server, Puppeteer) automatically register SIGINT/SIGTERM handlers
9
+ * - This caused handler conflicts and prevented proper cleanup of headless Chrome processes
10
+ * - Up to 6+ handlers were registered simultaneously, causing interference
11
+ *
12
+ * ROOT CAUSE:
13
+ * - Apollo Server: Automatic graceful shutdown handlers
14
+ * - Puppeteer: Browser cleanup on process exit handlers
15
+ * - Our code: Custom cleanup handlers
16
+ * - Result: Multiple handlers competing to exit process, causing premature termination before cleanup completed
17
+ *
18
+ * SOLUTION:
19
+ * 1. Apollo Server: Added `stopOnTerminationSignals: false` in server.ts & server-dev.ts
20
+ * 2. Puppeteer: Added `handleSIGINT: false, handleSIGTERM: false, handleSIGHUP: false` in browser-factory.ts
21
+ * 3. Unified cleanup: Single handler in this file manages all cleanup (headless pools, pubsub, etc.)
22
+ * 4. Simplified pool cleanup: Direct `drain() -> clear()` without complex fallbacks
23
+ *
24
+ * LESSON LEARNED:
25
+ * - Always check for signal handler conflicts when multiple libraries are involved
26
+ * - Keep cleanup logic simple - complex fallbacks often cause more problems
27
+ * - Document these kinds of integration issues for future reference
28
+ *
29
+ * FILES MODIFIED:
30
+ * - server.ts: stopOnTerminationSignals: false
31
+ * - server-dev.ts: stopOnTerminationSignals: false
32
+ * - browser-factory.ts: handleSIGINT/SIGTERM: false
33
+ * - pool-manager.ts: simplified cleanup logic
34
+ */
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.setupProcessExitHandlers = setupProcessExitHandlers;
4
- const tslib_1 = require("tslib");
5
- const fs = tslib_1.__importStar(require("fs"));
6
- const path = tslib_1.__importStar(require("path"));
7
- const os = tslib_1.__importStar(require("os"));
8
- const child_process_1 = require("child_process");
9
- const TEMP_DIR = os.tmpdir(); // OS별 임시 디렉토리 사용
10
- const PID_FILE = path.join(TEMP_DIR, `puppeteer-${process.pid}.pid`);
11
- // 🛠 **이전에 실행된 유령 프로세스 정리**
12
- function cleanupZombieProcesses() {
13
- if (fs.existsSync(PID_FILE)) {
14
- const pid = fs.readFileSync(PID_FILE, 'utf8').trim();
15
- if (pid) {
16
- console.log(`Cleaning up old Puppeteer process with PID: ${pid}`);
17
- if (os.platform() === 'win32') {
18
- (0, child_process_1.exec)(`taskkill /F /PID ${pid}`, (err, stdout, stderr) => {
19
- if (err)
20
- console.error(`Failed to kill process ${pid} on Windows:`, err);
21
- else
22
- console.log(`Process ${pid} killed on Windows.`);
23
- });
24
- }
25
- else {
26
- try {
27
- process.kill(Number(pid), 'SIGKILL');
28
- console.log(`Process ${pid} killed on Unix-like OS.`);
29
- }
30
- catch (err) {
31
- console.error(`Failed to kill process ${pid}:`, err);
32
- }
33
- }
34
- }
35
- fs.unlinkSync(PID_FILE); // 프로세스 종료 후 PID 파일 삭제
37
+ const pool_manager_1 = require("./utils/headless-pool/pool-manager");
38
+ const pubsub_1 = require("./pubsub");
39
+ let exiting = false;
40
+ async function cleanup(code = 0, info) {
41
+ if (exiting) {
42
+ console.warn('Shutdown already in progress. Received another signal.');
43
+ return;
36
44
  }
37
- }
38
- // **애플리케이션 시작 시 이전 프로세스 정리**
39
- cleanupZombieProcesses();
40
- // **현재 프로세스의 PID 저장**
41
- fs.writeFileSync(PID_FILE, process.pid.toString(), { flag: 'w' });
42
- async function cleanup() {
45
+ exiting = true;
43
46
  try {
44
- if (fs.existsSync(PID_FILE)) {
45
- fs.unlinkSync(PID_FILE); // 종료 PID 파일 삭제
46
- }
47
- console.log('Cleaning up resources...');
48
- // **프로세스가 존재하는지 확인 후 종료 시도**
47
+ if (info)
48
+ console.error('Cleaning up resources by:', info);
49
+ // 1. **Headless Pool 정리 (우선순위 높음)**
49
50
  try {
50
- process.kill(-process.pid, 'SIGTERM'); // 프로세스 그룹 전체 종료
51
- console.log(`Successfully killed process group (-${process.pid})`);
51
+ console.log('🧹 Cleaning up headless pools...');
52
+ await pool_manager_1.HeadlessPoolManager.cleanupAll();
53
+ console.log('✅ Headless pools cleaned up');
52
54
  }
53
- catch (err) {
54
- if (err.code === 'ESRCH') {
55
- console.warn(`Warning: Process group (-${process.pid}) already terminated.`);
56
- }
57
- else {
58
- console.error('Cleanup error:', err);
55
+ catch (error) {
56
+ console.log('❌ Headless pool cleanup failed:', error);
57
+ }
58
+ // 2. **PubSub 정리**
59
+ try {
60
+ console.log('🔌 Cleaning up pubsub connections...');
61
+ // @ts-ignore
62
+ if (pubsub_1.pubsub && pubsub_1.pubsub.close) {
63
+ // @ts-ignore
64
+ await pubsub_1.pubsub.close();
65
+ console.log('✅ PubSub cleaned up');
59
66
  }
60
67
  }
68
+ catch (error) {
69
+ console.log('❌ PubSub cleanup failed:', error);
70
+ }
61
71
  }
62
72
  catch (err) {
63
- console.error('Cleanup error:', err);
73
+ console.log('Cleanup error:', err);
64
74
  }
75
+ process.exit(code);
65
76
  }
66
77
  function setupProcessExitHandlers() {
67
- process.once('exit', async () => {
68
- console.log('Parent process is exiting, killing all child processes...');
69
- await cleanup();
70
- });
71
- process.once('SIGINT', async () => {
72
- console.log('\nReceived SIGINT, cleaning up...');
73
- await cleanup();
74
- process.exit(0);
75
- });
76
- process.once('SIGTERM', async () => {
77
- console.log('\nReceived SIGTERM, cleaning up...');
78
- await cleanup();
79
- process.exit(0);
80
- });
81
- process.once('uncaughtException', async (err) => {
82
- console.error('\nUncaught Exception:', err);
83
- await cleanup();
84
- process.exit(1);
85
- });
86
- process.once('unhandledRejection', async (reason) => {
87
- console.error('\nUnhandled Rejection:', reason);
88
- await cleanup();
89
- process.exit(1);
78
+ process.on('exit', () => {
79
+ console.log('Process is exiting...');
80
+ // exit 이벤트에서는 비동기 작업 불가능 - 동기적 정리만
90
81
  });
82
+ process.on('SIGINT', () => cleanup(0, 'SIGINT'));
83
+ process.on('SIGTERM', () => cleanup(0, 'SIGTERM'));
84
+ process.on('unhandledRejection', r => cleanup(1, 'unhandledRejection'));
85
+ process.on('uncaughtException', e => cleanup(1, 'uncaughtException'));
91
86
  }
92
87
  //# sourceMappingURL=process-cleaner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"process-cleaner.js","sourceRoot":"","sources":["../server/process-cleaner.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs'\nimport * as path from 'path'\nimport * as os from 'os'\nimport { exec } from 'child_process'\n\nconst TEMP_DIR = os.tmpdir() // OS별 임시 디렉토리 사용\nconst PID_FILE = path.join(TEMP_DIR, `puppeteer-${process.pid}.pid`)\n\n// 🛠 **이전에 실행된 유령 프로세스 정리**\nfunction cleanupZombieProcesses() {\n if (fs.existsSync(PID_FILE)) {\n const pid = fs.readFileSync(PID_FILE, 'utf8').trim()\n\n if (pid) {\n console.log(`Cleaning up old Puppeteer process with PID: ${pid}`)\n\n if (os.platform() === 'win32') {\n exec(`taskkill /F /PID ${pid}`, (err, stdout, stderr) => {\n if (err) console.error(`Failed to kill process ${pid} on Windows:`, err)\n else console.log(`Process ${pid} killed on Windows.`)\n })\n } else {\n try {\n process.kill(Number(pid), 'SIGKILL')\n console.log(`Process ${pid} killed on Unix-like OS.`)\n } catch (err) {\n console.error(`Failed to kill process ${pid}:`, err)\n }\n }\n }\n\n fs.unlinkSync(PID_FILE) // 프로세스 종료 PID 파일 삭제\n }\n}\n\n// **애플리케이션 시작 이전 프로세스 정리**\ncleanupZombieProcesses()\n\n// **현재 프로세스의 PID 저장**\nfs.writeFileSync(PID_FILE, process.pid.toString(), { flag: 'w' })\n\nasync function cleanup() {\n try {\n if (fs.existsSync(PID_FILE)) {\n fs.unlinkSync(PID_FILE) // 종료 PID 파일 삭제\n }\n\n console.log('Cleaning up resources...')\n\n // **프로세스가 존재하는지 확인 종료 시도**\n try {\n process.kill(-process.pid, 'SIGTERM') // 프로세스 그룹 전체 종료\n console.log(`Successfully killed process group (-${process.pid})`)\n } catch (err: any) {\n if (err.code === 'ESRCH') {\n console.warn(`Warning: Process group (-${process.pid}) already terminated.`)\n } else {\n console.error('Cleanup error:', err)\n }\n }\n } catch (err) {\n console.error('Cleanup error:', err)\n }\n}\n\nexport function setupProcessExitHandlers() {\n process.once('exit', async () => {\n console.log('Parent process is exiting, killing all child processes...')\n await cleanup()\n })\n\n process.once('SIGINT', async () => {\n console.log('\\nReceived SIGINT, cleaning up...')\n await cleanup()\n process.exit(0)\n })\n\n process.once('SIGTERM', async () => {\n console.log('\\nReceived SIGTERM, cleaning up...')\n await cleanup()\n process.exit(0)\n })\n\n process.once('uncaughtException', async err => {\n console.error('\\nUncaught Exception:', err)\n await cleanup()\n process.exit(1)\n })\n\n process.once('unhandledRejection', async reason => {\n console.error('\\nUnhandled Rejection:', reason)\n await cleanup()\n process.exit(1)\n })\n}\n"]}
1
+ {"version":3,"file":"process-cleaner.js","sourceRoot":"","sources":["../server/process-cleaner.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;;AA6CH,4DAUC;AArDD,qEAAwE;AACxE,qCAAiC;AAEjC,IAAI,OAAO,GAAG,KAAK,CAAA;AAEnB,KAAK,UAAU,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,IAAc;IAC7C,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAA;QACtE,OAAM;IACR,CAAC;IACD,OAAO,GAAG,IAAI,CAAA;IAEd,IAAI,CAAC;QACH,IAAI,IAAI;YAAE,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,IAAI,CAAC,CAAA;QAE1D,oCAAoC;QACpC,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAA;YAC/C,MAAM,kCAAmB,CAAC,UAAU,EAAE,CAAA;YACtC,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAA;QAC5C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAA;QACvD,CAAC;QAED,mBAAmB;QACnB,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAA;YACnD,aAAa;YACb,IAAI,eAAM,IAAI,eAAM,CAAC,KAAK,EAAE,CAAC;gBAC3B,aAAa;gBACb,MAAM,eAAM,CAAC,KAAK,EAAE,CAAA;gBACpB,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;YACpC,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAA;QAChD,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAA;IACpC,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACpB,CAAC;AAED,SAAgB,wBAAwB;IACtC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QACtB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAA;QACpC,mCAAmC;IACrC,CAAC,CAAC,CAAA;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAA;IAChD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAA;IAClD,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAA;IACvE,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAA;AACvE,CAAC","sourcesContent":["/**\n * Process Exit Handlers for Things Factory\n *\n * === SIGNAL HANDLER CONFLICTS ISSUE (2025-09-01) ===\n *\n * PROBLEM:\n * - Multiple libraries (Apollo Server, Puppeteer) automatically register SIGINT/SIGTERM handlers\n * - This caused handler conflicts and prevented proper cleanup of headless Chrome processes\n * - Up to 6+ handlers were registered simultaneously, causing interference\n *\n * ROOT CAUSE:\n * - Apollo Server: Automatic graceful shutdown handlers\n * - Puppeteer: Browser cleanup on process exit handlers\n * - Our code: Custom cleanup handlers\n * - Result: Multiple handlers competing to exit process, causing premature termination before cleanup completed\n *\n * SOLUTION:\n * 1. Apollo Server: Added `stopOnTerminationSignals: false` in server.ts & server-dev.ts\n * 2. Puppeteer: Added `handleSIGINT: false, handleSIGTERM: false, handleSIGHUP: false` in browser-factory.ts\n * 3. Unified cleanup: Single handler in this file manages all cleanup (headless pools, pubsub, etc.)\n * 4. Simplified pool cleanup: Direct `drain() -> clear()` without complex fallbacks\n *\n * LESSON LEARNED:\n * - Always check for signal handler conflicts when multiple libraries are involved\n * - Keep cleanup logic simple - complex fallbacks often cause more problems\n * - Document these kinds of integration issues for future reference\n *\n * FILES MODIFIED:\n * - server.ts: stopOnTerminationSignals: false\n * - server-dev.ts: stopOnTerminationSignals: false\n * - browser-factory.ts: handleSIGINT/SIGTERM: false\n * - pool-manager.ts: simplified cleanup logic\n */\n\nimport { HeadlessPoolManager } from './utils/headless-pool/pool-manager'\nimport { pubsub } from './pubsub'\n\nlet exiting = false\n\nasync function cleanup(code = 0, info?: unknown) {\n if (exiting) {\n console.warn('Shutdown already in progress. Received another signal.')\n return\n }\n exiting = true\n\n try {\n if (info) console.error('Cleaning up resources by:', info)\n\n // 1. **Headless Pool 정리 (우선순위 높음)**\n try {\n console.log('🧹 Cleaning up headless pools...')\n await HeadlessPoolManager.cleanupAll()\n console.log('✅ Headless pools cleaned up')\n } catch (error) {\n console.log('❌ Headless pool cleanup failed:', error)\n }\n\n // 2. **PubSub 정리**\n try {\n console.log('🔌 Cleaning up pubsub connections...')\n // @ts-ignore\n if (pubsub && pubsub.close) {\n // @ts-ignore\n await pubsub.close()\n console.log('✅ PubSub cleaned up')\n }\n } catch (error) {\n console.log(' PubSub cleanup failed:', error)\n }\n } catch (err) {\n console.log('Cleanup error:', err)\n }\n\n process.exit(code)\n}\n\nexport function setupProcessExitHandlers() {\n process.on('exit', () => {\n console.log('Process is exiting...')\n // exit 이벤트에서는 비동기 작업 불가능 - 동기적 정리만\n })\n\n process.on('SIGINT', () => cleanup(0, 'SIGINT'))\n process.on('SIGTERM', () => cleanup(0, 'SIGTERM'))\n process.on('unhandledRejection', r => cleanup(1, 'unhandledRejection'))\n process.on('uncaughtException', e => cleanup(1, 'uncaughtException'))\n}\n"]}
@@ -48,27 +48,4 @@ switch (middleware) {
48
48
  exports.pubsub = pubsub = (0, graphql_yoga_1.createPubSub)();
49
49
  break;
50
50
  }
51
- // kafka pubsub keeps connection and app port with 'ctrl+c' termination.
52
- const exitHandler = async (evt) => {
53
- //@ts-ignore
54
- if (pubsub.close) {
55
- try {
56
- //@ts-ignore
57
- await pubsub.close();
58
- }
59
- catch (err) {
60
- env_1.logger.error(err);
61
- }
62
- }
63
- };
64
- /*
65
- * exit events hint from https://stackoverflow.com/a/14032965/14539284
66
- */
67
- //do something when app is closing
68
- process.on('exit', exitHandler.bind(null, { name: 'exit', exit: true }));
69
- //catches ctrl+c event
70
- process.on('SIGINT', exitHandler.bind(null, { name: 'SIGINT', exit: true }));
71
- // catches "kill pid" (for example: nodemon restart)
72
- process.on('SIGUSR1', exitHandler.bind(null, { name: 'SIGUSR1', exit: true }));
73
- process.on('SIGUSR2', exitHandler.bind(null, { name: 'SIGUSR2', exit: true }));
74
51
  //# sourceMappingURL=pubsub.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pubsub.js","sourceRoot":"","sources":["../server/pubsub.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;AAEH,+CAA2C;AAC3C,yEAAyE;AACzE,8DAA2B;AAE3B,6CAAoD;AAGpD,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,YAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;AAE3E,IAAI,MAAc,CAAA;AAElB,QAAQ,UAAU,EAAE,CAAC;IACnB,KAAK,OAAO;QACV,MAAM,WAAW,GAAG;YAClB,IAAI;YACJ,IAAI;YACJ,aAAa,EAAE,KAAK,CAAC,EAAE;gBACrB,kBAAkB;gBAClB,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,EAAE,EAAE,IAAI,CAAC,CAAA;YACnC,CAAC;YACD,GAAG,OAAO;SACX,CAAA;QACD,YAAY;QACZ,iBAAA,MAAM,GAAG,IAAA,2BAAY,EAAC;YACpB,WAAW,EAAE,IAAA,2CAAsB,EAAC;gBAClC,aAAa,EAAE,IAAI,iBAAK,CAAC,WAAW,CAAC;gBACrC,eAAe,EAAE,IAAI,iBAAK,CAAC,WAAW,CAAC;aACxC,CAAC;SACH,CAAC,CAAA;QACF,MAAK;IACP,KAAK,cAAc;QACjB,MAAM,OAAO,GAAG,IAAI,iBAAK,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;QACjD,YAAY;QACZ,iBAAA,MAAM,GAAG,IAAA,2BAAY,EAAC;YACpB,WAAW,EAAE,IAAA,2CAAsB,EAAC;gBAClC,aAAa,EAAE,OAAO;gBACtB,eAAe,EAAE,OAAO;aACzB,CAAC;SACH,CAAC,CAAA;QACF,MAAK;IACP;QACE,iBAAA,MAAM,GAAG,IAAA,2BAAY,GAAE,CAAA;QACvB,MAAK;AACT,CAAC;AAED,wEAAwE;AACxE,MAAM,WAAW,GAAG,KAAK,EAAC,GAAG,EAAC,EAAE;IAC9B,YAAY;IACZ,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,YAAY;YACZ,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,YAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;AACH,CAAC,CAAA;AAED;;GAEG;AAEH,kCAAkC;AAClC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AAExE,sBAAsB;AACtB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AAE5E,oDAAoD;AACpD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AAC9E,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA","sourcesContent":["/**\n * @module pubsub\n * @description\n * This module provides a Pub/Sub (Publish/Subscribe) mechanism for handling messages and events.\n * Developers can use various middleware options such as Redis, Redis Cluster\n * to implement Pub/Sub functionality.\n */\n\nimport { createPubSub } from 'graphql-yoga'\nimport { createRedisEventTarget } from '@graphql-yoga/redis-event-target'\nimport Redis from 'ioredis'\n\nimport { config, logger } from '@things-factory/env'\nimport { PubSub } from 'type-graphql'\n\nconst { middleware, host, port, nodes, options } = config.get('pubsub', {})\n\nlet pubsub: PubSub\n\nswitch (middleware) {\n case 'redis':\n const redisOption = {\n host,\n port,\n retryStrategy: times => {\n // reconnect after\n return Math.min(times * 50, 2000)\n },\n ...options\n }\n //@ts-ignore\n pubsub = createPubSub({\n eventTarget: createRedisEventTarget({\n publishClient: new Redis(redisOption),\n subscribeClient: new Redis(redisOption)\n })\n })\n break\n case 'redisCluster':\n const cluster = new Redis.Cluster(nodes, options)\n //@ts-ignore\n pubsub = createPubSub({\n eventTarget: createRedisEventTarget({\n publishClient: cluster,\n subscribeClient: cluster\n })\n })\n break\n default:\n pubsub = createPubSub()\n break\n}\n\n// kafka pubsub keeps connection and app port with 'ctrl+c' termination.\nconst exitHandler = async evt => {\n //@ts-ignore\n if (pubsub.close) {\n try {\n //@ts-ignore\n await pubsub.close()\n } catch (err) {\n logger.error(err)\n }\n }\n}\n\n/*\n * exit events hint from https://stackoverflow.com/a/14032965/14539284\n */\n\n//do something when app is closing\nprocess.on('exit', exitHandler.bind(null, { name: 'exit', exit: true }))\n\n//catches ctrl+c event\nprocess.on('SIGINT', exitHandler.bind(null, { name: 'SIGINT', exit: true }))\n\n// catches \"kill pid\" (for example: nodemon restart)\nprocess.on('SIGUSR1', exitHandler.bind(null, { name: 'SIGUSR1', exit: true }))\nprocess.on('SIGUSR2', exitHandler.bind(null, { name: 'SIGUSR2', exit: true }))\n\n//catches uncaught exceptions\n// process.on('uncaughtException', exitHandler.bind(null, { name: 'uncaughtException', exit: true }))\n\nexport { pubsub }\n"]}
1
+ {"version":3,"file":"pubsub.js","sourceRoot":"","sources":["../server/pubsub.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;AAEH,+CAA2C;AAC3C,yEAAyE;AACzE,8DAA2B;AAE3B,6CAAoD;AAGpD,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,YAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;AAE3E,IAAI,MAAc,CAAA;AAElB,QAAQ,UAAU,EAAE,CAAC;IACnB,KAAK,OAAO;QACV,MAAM,WAAW,GAAG;YAClB,IAAI;YACJ,IAAI;YACJ,aAAa,EAAE,KAAK,CAAC,EAAE;gBACrB,kBAAkB;gBAClB,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,EAAE,EAAE,IAAI,CAAC,CAAA;YACnC,CAAC;YACD,GAAG,OAAO;SACX,CAAA;QACD,YAAY;QACZ,iBAAA,MAAM,GAAG,IAAA,2BAAY,EAAC;YACpB,WAAW,EAAE,IAAA,2CAAsB,EAAC;gBAClC,aAAa,EAAE,IAAI,iBAAK,CAAC,WAAW,CAAC;gBACrC,eAAe,EAAE,IAAI,iBAAK,CAAC,WAAW,CAAC;aACxC,CAAC;SACH,CAAC,CAAA;QACF,MAAK;IACP,KAAK,cAAc;QACjB,MAAM,OAAO,GAAG,IAAI,iBAAK,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;QACjD,YAAY;QACZ,iBAAA,MAAM,GAAG,IAAA,2BAAY,EAAC;YACpB,WAAW,EAAE,IAAA,2CAAsB,EAAC;gBAClC,aAAa,EAAE,OAAO;gBACtB,eAAe,EAAE,OAAO;aACzB,CAAC;SACH,CAAC,CAAA;QACF,MAAK;IACP;QACE,iBAAA,MAAM,GAAG,IAAA,2BAAY,GAAE,CAAA;QACvB,MAAK;AACT,CAAC","sourcesContent":["/**\n * @module pubsub\n * @description\n * This module provides a Pub/Sub (Publish/Subscribe) mechanism for handling messages and events.\n * Developers can use various middleware options such as Redis, Redis Cluster\n * to implement Pub/Sub functionality.\n */\n\nimport { createPubSub } from 'graphql-yoga'\nimport { createRedisEventTarget } from '@graphql-yoga/redis-event-target'\nimport Redis from 'ioredis'\n\nimport { config, logger } from '@things-factory/env'\nimport { PubSub } from 'type-graphql'\n\nconst { middleware, host, port, nodes, options } = config.get('pubsub', {})\n\nlet pubsub: PubSub\n\nswitch (middleware) {\n case 'redis':\n const redisOption = {\n host,\n port,\n retryStrategy: times => {\n // reconnect after\n return Math.min(times * 50, 2000)\n },\n ...options\n }\n //@ts-ignore\n pubsub = createPubSub({\n eventTarget: createRedisEventTarget({\n publishClient: new Redis(redisOption),\n subscribeClient: new Redis(redisOption)\n })\n })\n break\n case 'redisCluster':\n const cluster = new Redis.Cluster(nodes, options)\n //@ts-ignore\n pubsub = createPubSub({\n eventTarget: createRedisEventTarget({\n publishClient: cluster,\n subscribeClient: cluster\n })\n })\n break\n default:\n pubsub = createPubSub()\n break\n}\n\n/*\n * PubSub cleanup is handled by process-cleaner.ts\n * All process termination signals (SIGINT, SIGTERM, etc.) and cleanup logic\n * have been moved to process-cleaner.ts for centralized resource management.\n */\n\nexport { pubsub }\n"]}
@@ -134,6 +134,7 @@ const bootstrap = async () => {
134
134
  },
135
135
  introspection: true,
136
136
  csrfPrevention: true,
137
+ stopOnTerminationSignals: false, // ★ 자동 시그널 핸들러 비활성화
137
138
  plugins: [
138
139
  // Proper shutdown for the HTTP server.
139
140
  (0, drainHttpServer_1.ApolloServerPluginDrainHttpServer)({ httpServer }),
@@ -1 +1 @@
1
- {"version":3,"file":"server-dev.js","sourceRoot":"","sources":["../server/server-dev.ts"],"names":[],"mappings":"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","sourcesContent":["// ts-import-sorter: disable\n\n/* following 7 lines should be located in top of the file */\nimport OS from 'os'\nprocess.env.UV_THREADPOOL_SIZE = String(OS.availableParallelism())\n\nconsole.log('UV_THREADPOOL_SIZE', process.env.UV_THREADPOOL_SIZE)\n\nprocess.env.NODE_ENV = 'development'\nprocess.setMaxListeners(0)\n\nimport { ApolloServer } from '@apollo/server'\nimport { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer'\nimport { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default'\n\nimport { koaMiddleware } from '@as-integrations/koa'\nimport { EntityManager } from 'typeorm'\nimport args from 'args'\nimport wdm from 'webpack-dev-middleware'\nimport bytesFormat from 'bytes'\nimport graphqlUploadKoa from 'graphql-upload/graphqlUploadKoa.js'\nimport { useServer } from 'graphql-ws/lib/use/ws'\nimport { createServer } from 'http'\nimport Koa from 'koa'\nimport koaBodyParser from 'koa-bodyparser'\nimport compose from 'koa-compose'\nimport { historyApiFallback } from 'koa2-connect-history-api-fallback'\nimport { WebSocketServer } from 'ws'\nimport co from 'co'\nimport http from 'http'\n\nimport cors from '@koa/cors'\n\nimport crypto from 'crypto'\n\nimport { config, loader, logger, orderedModuleNames } from '@things-factory/env'\nimport { initLicense, checkValidity } from '@things-factory/operato-license-checker'\n\nimport { GraphqlLocalClient } from './graphql-local-client.js'\nimport { databaseInitializer } from './initializers/database.js'\nimport {\n domainPrivateRouter,\n domainPublicRouter,\n globalPrivateRouter,\n globalPublicRouter,\n graphqlRouter\n} from './routers/index.js'\nimport { schema } from './schema.js'\nimport { Domain } from './service/index.js'\nimport { domainMiddleware } from './middlewares/domain-middleware.js'\nimport { setupProcessExitHandlers } from './process-cleaner.js'\n\nsetupProcessExitHandlers()\n\nargs.option('port', 'The port on which the app will be running', config.get('port', 3000))\nargs.option(\n 'inspect',\n `The address on which the inspection will be running. Used in development mode only.\n This option is just to prevent termination for reasons of not recognizing the 'inspect' option.`,\n config.get('inspect', ':9229')\n)\nargs.option('webpack', 'webpack configuration file', config.get('webpack'))\n\nconst flags = args.parse(process.argv)\n\nimport webpack from 'webpack'\nconst webpackConfig = require(flags.webpack || '@things-factory/builder/webpack.config.dev.js')\n\nconst compiler = webpack(webpackConfig)\n\nconst PORT = (process.env.PORT = flags.port)\n\nconst requestBody = config.get('requestBody') || {}\n\nconst bodyParserOption = {\n formLimit: requestBody.formLimit || '10mb',\n jsonLimit: requestBody.jsonLimit || '10mb',\n textLimit: requestBody.textLimit || '10mb'\n}\n\nconst fileUpload = config.get('fileUpload') || {}\nconst fileUploadOption = {\n maxFileSize: bytesFormat.parse(fileUpload.maxFileSize) || bytesFormat.parse('10mb'),\n maxFiles: fileUpload.maxFiles || 10\n}\n\ninterface ICustomAppState {\n domain: Domain\n user: any\n tx: EntityManager\n}\n\ninterface ICustomAppContext {\n t: any\n ssoMiddlewares: any[]\n}\n\ninitLicense(config.get('licenseKey'))\n\n/* bootstrap */\nconst bootstrap = async () => {\n await databaseInitializer()\n\n const app = new Koa<ICustomAppState, ICustomAppContext>() as any\n app.proxy = true\n\n app.use(\n cors({\n origin: function (ctx) {\n return ctx.request.headers.origin || '*'\n },\n exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],\n maxAge: 5,\n credentials: true,\n /* allowMethods: ['GET', 'POST', 'DELETE'], -- use default */\n allowHeaders: ['Content-Type', 'Authorization', 'Accept']\n })\n )\n\n app.use(async (ctx, next) => {\n ctx.set('X-Content-Type-Options', 'nosniff')\n\n const { directives = {} } = config.get('CSP') || {}\n\n const nonce = crypto.randomBytes(16).toString('base64')\n ctx.state.nonce = nonce\n\n const cspHeader = Object.entries(directives as { [key: string]: string[] })\n .map(([key, value]) => `${key} ${value.join(' ')}`)\n .join('; ')\n\n ctx.set('Content-Security-Policy', cspHeader)\n\n await next()\n })\n\n var subscriptionMiddleware = []\n process.emit('bootstrap-module-subscription' as any, app, subscriptionMiddleware)\n\n const builtSchema = await schema()\n\n const httpServer = createServer(app.callback())\n const websocketServer = new WebSocketServer({\n server: httpServer,\n path: '/graphql'\n })\n\n // Save the returned server's info so we can shut down this server later\n const serverCleanup = useServer(\n {\n schema: builtSchema,\n context: async (ctx, msg, args) => {\n return ctx['context']\n },\n onConnect: async ctx => {\n var { extra, connectionParams } = ctx\n var { request } = extra\n\n if (((connectionParams['headers'] as any) || connectionParams)?.referer) {\n var url = new URL(((connectionParams['headers'] as any) || connectionParams).referer)\n var accessToken = url.searchParams.get('access_token')\n if (accessToken) {\n connectionParams['headers']['authorization'] = accessToken\n }\n }\n\n request.headers = {\n ...request.headers,\n ...(connectionParams['headers'] || (connectionParams as any))\n }\n\n var koacontext = await app.createContext(request, new http.ServerResponse(request))\n koacontext['state'] = {}\n\n /* in case connect error(like a authentication error) just throw exception */\n var middlewares = [domainMiddleware, ...subscriptionMiddleware]\n const fn = co.wrap(compose(middlewares))\n\n await fn(koacontext)\n\n return (ctx['context'] = koacontext)\n },\n onDisconnect(ctx, code, reason) {\n console.log('Disconnected!')\n },\n onError(ctx, msg, errors) {\n console.error(msg, errors)\n }\n },\n websocketServer\n )\n\n const server = new ApolloServer({\n schema: builtSchema,\n formatError: error => {\n logger.error(error)\n return error\n },\n introspection: true,\n csrfPrevention: true,\n plugins: [\n // Proper shutdown for the HTTP server.\n ApolloServerPluginDrainHttpServer({ httpServer }),\n // Proper shutdown for the WebSocket server.\n {\n async serverWillStart() {\n return {\n async drainServer() {\n await serverCleanup.dispose()\n }\n }\n }\n },\n // TODO make this landing page work\n ApolloServerPluginLandingPageLocalDefault({\n footer: false,\n embed: true,\n includeCookies: true\n })\n ],\n cache: 'bounded'\n })\n\n await server.start()\n\n GraphqlLocalClient.init(builtSchema, app)\n\n orderedModuleNames.forEach(name => {\n const { initMiddlewares } = loader(name)\n initMiddlewares && initMiddlewares(app)\n })\n\n const render = require('@things-factory/ejs-remote')\n render(app, {\n root: '/views',\n host: `http://127.0.0.1:${PORT}`,\n layout: false,\n viewExt: 'html',\n cache: false,\n debug: false\n })\n\n // only for development mode. triggered after webpack compilation is done.\n compiler.hooks.done.tap({ name: 'server-dev' }, stats => {\n process.emit('client-rebuilt' as any, app, compiler.outputFileSystem)\n })\n\n app.use(koaBodyParser(bodyParserOption))\n\n /* routers */\n const ssoMiddlewares = []\n process.emit('bootstrap-collect-sso-middleware' as any, null, ssoMiddlewares)\n app.ssoMiddlewares = ssoMiddlewares\n\n process.emit('bootstrap-module-global-public-route' as any, app, globalPublicRouter)\n process.emit('bootstrap-module-global-private-route' as any, app, globalPrivateRouter)\n process.emit('bootstrap-module-domain-public-route' as any, app, domainPublicRouter)\n process.emit('bootstrap-module-domain-private-route' as any, app, domainPrivateRouter)\n\n app.use(checkValidity) /* Check the license after most of the context has been built */\n\n app\n .use(globalPublicRouter.routes())\n .use(globalPublicRouter.allowedMethods())\n .use(globalPrivateRouter.routes())\n .use(globalPrivateRouter.allowedMethods())\n .use(domainPublicRouter.routes())\n .use(domainPublicRouter.allowedMethods())\n .use(domainPrivateRouter.routes())\n .use(domainPrivateRouter.allowedMethods())\n\n /* Graphql Upload's multipart/form-data handling affects the restful file upload feature, so it should be placed after the routers configuration. */\n app.use(graphqlUploadKoa(fileUploadOption))\n\n graphqlRouter.post(\n '/graphql',\n koaMiddleware(server, {\n context: async ({ ctx }) => ctx\n })\n )\n app.use(graphqlRouter.routes())\n app.use(graphqlRouter.allowedMethods())\n\n /* should follow this order : history-fallback => webpack-middleware */\n app.use(historyApiFallback({ whiteList: [] }))\n\n app.use(\n wdm.koaWrapper(compiler, {\n publicPath: webpackConfig.output.publicPath\n })\n )\n\n httpServer.listen({ port: PORT }, () => {\n logger.info(`🚀 Server ready at http://0.0.0.0:${PORT}/graphql`)\n logger.info(`🚀 Subscriptions ready at ws://0.0.0.0:${PORT}/graphql`)\n\n process.emit('bootstrap-module-start' as any, { app, config, builtSchema, httpServer } as any)\n })\n}\n\nbootstrap()\n"]}
1
+ {"version":3,"file":"server-dev.js","sourceRoot":"","sources":["../server/server-dev.ts"],"names":[],"mappings":"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","sourcesContent":["// ts-import-sorter: disable\n\n/* following 7 lines should be located in top of the file */\nimport OS from 'os'\nprocess.env.UV_THREADPOOL_SIZE = String(OS.availableParallelism())\n\nconsole.log('UV_THREADPOOL_SIZE', process.env.UV_THREADPOOL_SIZE)\n\nprocess.env.NODE_ENV = 'development'\nprocess.setMaxListeners(0)\n\nimport { ApolloServer } from '@apollo/server'\nimport { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer'\nimport { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default'\n\nimport { koaMiddleware } from '@as-integrations/koa'\nimport { EntityManager } from 'typeorm'\nimport args from 'args'\nimport wdm from 'webpack-dev-middleware'\nimport bytesFormat from 'bytes'\nimport graphqlUploadKoa from 'graphql-upload/graphqlUploadKoa.js'\nimport { useServer } from 'graphql-ws/lib/use/ws'\nimport { createServer } from 'http'\nimport Koa from 'koa'\nimport koaBodyParser from 'koa-bodyparser'\nimport compose from 'koa-compose'\nimport { historyApiFallback } from 'koa2-connect-history-api-fallback'\nimport { WebSocketServer } from 'ws'\nimport co from 'co'\nimport http from 'http'\n\nimport cors from '@koa/cors'\n\nimport crypto from 'crypto'\n\nimport { config, loader, logger, orderedModuleNames } from '@things-factory/env'\nimport { initLicense, checkValidity } from '@things-factory/operato-license-checker'\n\nimport { GraphqlLocalClient } from './graphql-local-client.js'\nimport { databaseInitializer } from './initializers/database.js'\nimport {\n domainPrivateRouter,\n domainPublicRouter,\n globalPrivateRouter,\n globalPublicRouter,\n graphqlRouter\n} from './routers/index.js'\nimport { schema } from './schema.js'\nimport { Domain } from './service/index.js'\nimport { domainMiddleware } from './middlewares/domain-middleware.js'\nimport { setupProcessExitHandlers } from './process-cleaner.js'\n\nsetupProcessExitHandlers()\n\nargs.option('port', 'The port on which the app will be running', config.get('port', 3000))\nargs.option(\n 'inspect',\n `The address on which the inspection will be running. Used in development mode only.\n This option is just to prevent termination for reasons of not recognizing the 'inspect' option.`,\n config.get('inspect', ':9229')\n)\nargs.option('webpack', 'webpack configuration file', config.get('webpack'))\n\nconst flags = args.parse(process.argv)\n\nimport webpack from 'webpack'\nconst webpackConfig = require(flags.webpack || '@things-factory/builder/webpack.config.dev.js')\n\nconst compiler = webpack(webpackConfig)\n\nconst PORT = (process.env.PORT = flags.port)\n\nconst requestBody = config.get('requestBody') || {}\n\nconst bodyParserOption = {\n formLimit: requestBody.formLimit || '10mb',\n jsonLimit: requestBody.jsonLimit || '10mb',\n textLimit: requestBody.textLimit || '10mb'\n}\n\nconst fileUpload = config.get('fileUpload') || {}\nconst fileUploadOption = {\n maxFileSize: bytesFormat.parse(fileUpload.maxFileSize) || bytesFormat.parse('10mb'),\n maxFiles: fileUpload.maxFiles || 10\n}\n\ninterface ICustomAppState {\n domain: Domain\n user: any\n tx: EntityManager\n}\n\ninterface ICustomAppContext {\n t: any\n ssoMiddlewares: any[]\n}\n\ninitLicense(config.get('licenseKey'))\n\n/* bootstrap */\nconst bootstrap = async () => {\n await databaseInitializer()\n\n const app = new Koa<ICustomAppState, ICustomAppContext>() as any\n app.proxy = true\n\n app.use(\n cors({\n origin: function (ctx) {\n return ctx.request.headers.origin || '*'\n },\n exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],\n maxAge: 5,\n credentials: true,\n /* allowMethods: ['GET', 'POST', 'DELETE'], -- use default */\n allowHeaders: ['Content-Type', 'Authorization', 'Accept']\n })\n )\n\n app.use(async (ctx, next) => {\n ctx.set('X-Content-Type-Options', 'nosniff')\n\n const { directives = {} } = config.get('CSP') || {}\n\n const nonce = crypto.randomBytes(16).toString('base64')\n ctx.state.nonce = nonce\n\n const cspHeader = Object.entries(directives as { [key: string]: string[] })\n .map(([key, value]) => `${key} ${value.join(' ')}`)\n .join('; ')\n\n ctx.set('Content-Security-Policy', cspHeader)\n\n await next()\n })\n\n var subscriptionMiddleware = []\n process.emit('bootstrap-module-subscription' as any, app, subscriptionMiddleware)\n\n const builtSchema = await schema()\n\n const httpServer = createServer(app.callback())\n const websocketServer = new WebSocketServer({\n server: httpServer,\n path: '/graphql'\n })\n\n // Save the returned server's info so we can shut down this server later\n const serverCleanup = useServer(\n {\n schema: builtSchema,\n context: async (ctx, msg, args) => {\n return ctx['context']\n },\n onConnect: async ctx => {\n var { extra, connectionParams } = ctx\n var { request } = extra\n\n if (((connectionParams['headers'] as any) || connectionParams)?.referer) {\n var url = new URL(((connectionParams['headers'] as any) || connectionParams).referer)\n var accessToken = url.searchParams.get('access_token')\n if (accessToken) {\n connectionParams['headers']['authorization'] = accessToken\n }\n }\n\n request.headers = {\n ...request.headers,\n ...(connectionParams['headers'] || (connectionParams as any))\n }\n\n var koacontext = await app.createContext(request, new http.ServerResponse(request))\n koacontext['state'] = {}\n\n /* in case connect error(like a authentication error) just throw exception */\n var middlewares = [domainMiddleware, ...subscriptionMiddleware]\n const fn = co.wrap(compose(middlewares))\n\n await fn(koacontext)\n\n return (ctx['context'] = koacontext)\n },\n onDisconnect(ctx, code, reason) {\n console.log('Disconnected!')\n },\n onError(ctx, msg, errors) {\n console.error(msg, errors)\n }\n },\n websocketServer\n )\n\n const server = new ApolloServer({\n schema: builtSchema,\n formatError: error => {\n logger.error(error)\n return error\n },\n introspection: true,\n csrfPrevention: true,\n stopOnTerminationSignals: false, // ★ 자동 시그널 핸들러 비활성화\n plugins: [\n // Proper shutdown for the HTTP server.\n ApolloServerPluginDrainHttpServer({ httpServer }),\n // Proper shutdown for the WebSocket server.\n {\n async serverWillStart() {\n return {\n async drainServer() {\n await serverCleanup.dispose()\n }\n }\n }\n },\n // TODO make this landing page work\n ApolloServerPluginLandingPageLocalDefault({\n footer: false,\n embed: true,\n includeCookies: true\n })\n ],\n cache: 'bounded'\n })\n\n await server.start()\n\n GraphqlLocalClient.init(builtSchema, app)\n\n orderedModuleNames.forEach(name => {\n const { initMiddlewares } = loader(name)\n initMiddlewares && initMiddlewares(app)\n })\n\n const render = require('@things-factory/ejs-remote')\n render(app, {\n root: '/views',\n host: `http://127.0.0.1:${PORT}`,\n layout: false,\n viewExt: 'html',\n cache: false,\n debug: false\n })\n\n // only for development mode. triggered after webpack compilation is done.\n compiler.hooks.done.tap({ name: 'server-dev' }, stats => {\n process.emit('client-rebuilt' as any, app, compiler.outputFileSystem)\n })\n\n app.use(koaBodyParser(bodyParserOption))\n\n /* routers */\n const ssoMiddlewares = []\n process.emit('bootstrap-collect-sso-middleware' as any, null, ssoMiddlewares)\n app.ssoMiddlewares = ssoMiddlewares\n\n process.emit('bootstrap-module-global-public-route' as any, app, globalPublicRouter)\n process.emit('bootstrap-module-global-private-route' as any, app, globalPrivateRouter)\n process.emit('bootstrap-module-domain-public-route' as any, app, domainPublicRouter)\n process.emit('bootstrap-module-domain-private-route' as any, app, domainPrivateRouter)\n\n app.use(checkValidity) /* Check the license after most of the context has been built */\n\n app\n .use(globalPublicRouter.routes())\n .use(globalPublicRouter.allowedMethods())\n .use(globalPrivateRouter.routes())\n .use(globalPrivateRouter.allowedMethods())\n .use(domainPublicRouter.routes())\n .use(domainPublicRouter.allowedMethods())\n .use(domainPrivateRouter.routes())\n .use(domainPrivateRouter.allowedMethods())\n\n /* Graphql Upload's multipart/form-data handling affects the restful file upload feature, so it should be placed after the routers configuration. */\n app.use(graphqlUploadKoa(fileUploadOption))\n\n graphqlRouter.post(\n '/graphql',\n koaMiddleware(server, {\n context: async ({ ctx }) => ctx\n })\n )\n app.use(graphqlRouter.routes())\n app.use(graphqlRouter.allowedMethods())\n\n /* should follow this order : history-fallback => webpack-middleware */\n app.use(historyApiFallback({ whiteList: [] }))\n\n app.use(\n wdm.koaWrapper(compiler, {\n publicPath: webpackConfig.output.publicPath\n })\n )\n\n httpServer.listen({ port: PORT }, () => {\n logger.info(`🚀 Server ready at http://0.0.0.0:${PORT}/graphql`)\n logger.info(`🚀 Subscriptions ready at ws://0.0.0.0:${PORT}/graphql`)\n\n process.emit('bootstrap-module-start' as any, { app, config, builtSchema, httpServer } as any)\n })\n}\n\nbootstrap()\n"]}
@@ -129,6 +129,7 @@ const bootstrap = async () => {
129
129
  },
130
130
  introspection: false,
131
131
  csrfPrevention: true,
132
+ stopOnTerminationSignals: false, // ★ 자동 시그널 핸들러 비활성화
132
133
  plugins: [
133
134
  // Proper shutdown for the HTTP server.
134
135
  (0, drainHttpServer_1.ApolloServerPluginDrainHttpServer)({ httpServer }),
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../server/server.ts"],"names":[],"mappings":";AAAA,4BAA4B;;;AAE5B,4DAA4D;AAC5D,oDAAmB;AACnB,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,MAAM,CAAC,YAAE,CAAC,oBAAoB,EAAE,CAAC,CAAA;AAElE,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;AAEjE,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,YAAY,CAAA;AACnC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;AAE1B,2CAA6C;AAC7C,2EAAyF;AACzF,uEAA0G;AAC1G,8CAAoD;AAEpD,0DAA+B;AAC/B,qGAAiE;AACjE,8CAAiD;AACjD,+BAAmC;AACnC,sDAAqB;AACrB,4EAA0C;AAC1C,oEAAkC;AAClC,sEAAiC;AACjC,yFAAsE;AACtE,2BAAoC;AACpC,oDAAmB;AACnB,wDAAuB;AACvB,wDAAuB;AACvB,wDAAuB;AAEvB,6DAA4B;AAC5B,4DAA2B;AAE3B,6CAAgF;AAChF,qFAAoF;AAEpF,uEAA8D;AAC9D,4DAAgE;AAChE,iDAM2B;AAC3B,2CAAoC;AACpC,6EAAqE;AACrE,6DAA+D;AAE/D,IAAA,6CAAwB,GAAE,CAAA;AAE1B,cAAI,CAAC,MAAM,CAAC,MAAM,EAAE,2CAA2C,EAAE,YAAM,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;AAE1F,MAAM,KAAK,GAAG,cAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AAEtC,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;AAE5C,MAAM,WAAW,GAAG,YAAM,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAA;AAEnD,MAAM,gBAAgB,GAAG;IACvB,SAAS,EAAE,WAAW,CAAC,SAAS,IAAI,MAAM;IAC1C,SAAS,EAAE,WAAW,CAAC,SAAS,IAAI,MAAM;IAC1C,SAAS,EAAE,WAAW,CAAC,SAAS,IAAI,MAAM;CAC3C,CAAA;AAED,MAAM,UAAU,GAAG,YAAM,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAA;AACjD,MAAM,gBAAgB,GAAG;IACvB,WAAW,EAAE,eAAW,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,eAAW,CAAC,KAAK,CAAC,MAAM,CAAC;IACnF,QAAQ,EAAE,UAAU,CAAC,QAAQ,IAAI,EAAE;CACpC,CAAA;AAED,IAAA,qCAAW,EAAC,YAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAA;AAErC,eAAe;AACf,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE;IAC3B,MAAM,IAAA,iCAAmB,GAAE,CAAA;IAE3B,MAAM,GAAG,GAAG,IAAI,aAAG,EAAS,CAAA;IAC5B,GAAG,CAAC,KAAK,GAAG,IAAI,CAAA;IAEhB,GAAG,CAAC,GAAG,CACL,IAAA,cAAI,EAAC;QACH,MAAM,EAAE,UAAU,GAAG;YACnB,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,GAAG,CAAA;QAC1C,CAAC;QACD,aAAa,EAAE,CAAC,kBAAkB,EAAE,sBAAsB,CAAC;QAC3D,MAAM,EAAE,CAAC;QACT,WAAW,EAAE,IAAI;QACjB,6DAA6D;QAC7D,YAAY,EAAE,CAAC,cAAc,EAAE,eAAe,EAAE,QAAQ,CAAC;KAC1D,CAAC,CACH,CAAA;IAED,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC1B,GAAG,CAAC,GAAG,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAA;QAE5C,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE,GAAG,YAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;QAEnD,MAAM,KAAK,GAAG,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QACvD,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAA;QAEvB,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,UAAyC,CAAC;aACxE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;aAClD,IAAI,CAAC,IAAI,CAAC,CAAA;QAEb,GAAG,CAAC,GAAG,CAAC,yBAAyB,EAAE,SAAS,CAAC,CAAA;QAE7C,MAAM,IAAI,EAAE,CAAA;IACd,CAAC,CAAC,CAAA;IAEF,IAAI,sBAAsB,GAAG,EAAE,CAAA;IAC/B,OAAO,CAAC,IAAI,CAAC,+BAAsC,EAAE,GAAG,EAAE,sBAAsB,CAAC,CAAA;IAEjF,MAAM,WAAW,GAAG,MAAM,IAAA,kBAAM,GAAE,CAAA;IAElC,MAAM,UAAU,GAAG,IAAA,mBAAY,EAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC/C,MAAM,eAAe,GAAG,IAAI,oBAAe,CAAC;QAC1C,MAAM,EAAE,UAAU;QAClB,IAAI,EAAE,UAAU;KACjB,CAAC,CAAA;IAEF,wEAAwE;IACxE,MAAM,aAAa,GAAG,IAAA,cAAS,EAC7B;QACE,MAAM,EAAE,WAAW;QACnB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YAChC,OAAO,GAAG,CAAC,SAAS,CAAC,CAAA;QACvB,CAAC;QACD,SAAS,EAAE,KAAK,EAAC,GAAG,EAAC,EAAE;YACrB,IAAI,EAAE,KAAK,EAAE,gBAAgB,EAAE,GAAG,GAAG,CAAA;YACrC,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,CAAA;YAEvB,IAAI,CAAE,gBAAgB,CAAC,SAAS,CAAS,IAAI,gBAAgB,CAAC,EAAE,OAAO,EAAE,CAAC;gBACxE,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,CAAE,gBAAgB,CAAC,SAAS,CAAS,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAA;gBACrF,IAAI,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;gBACtD,IAAI,WAAW,EAAE,CAAC;oBAChB,gBAAgB,CAAC,SAAS,CAAC,CAAC,eAAe,CAAC,GAAG,WAAW,CAAA;gBAC5D,CAAC;YACH,CAAC;YAED,OAAO,CAAC,OAAO,GAAG;gBAChB,GAAG,OAAO,CAAC,OAAO;gBAClB,GAAG,CAAC,gBAAgB,CAAC,SAAS,CAAC,IAAK,gBAAwB,CAAC;aAC9D,CAAA;YAED,IAAI,UAAU,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,cAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAA;YACnF,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,CAAA;YAExB,6EAA6E;YAC7E,IAAI,WAAW,GAAG,CAAC,uCAAgB,EAAE,GAAG,sBAAsB,CAAC,CAAA;YAC/D,MAAM,EAAE,GAAG,YAAE,CAAC,IAAI,CAAC,IAAA,qBAAO,EAAC,WAAW,CAAC,CAAC,CAAA;YAExC,MAAM,EAAE,CAAC,UAAU,CAAC,CAAA;YAEpB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,UAAU,CAAC,CAAA;QACtC,CAAC;QACD,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM;YAC5B,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;QAC9B,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM;YACtB,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QAC5B,CAAC;KACF,EACD,eAAe,CAChB,CAAA;IAED,MAAM,MAAM,GAAG,IAAI,qBAAY,CAAC;QAC9B,MAAM,EAAE,WAAW;QACnB,WAAW,EAAE,KAAK,CAAC,EAAE;YACnB,YAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YACnB,OAAO,KAAK,CAAA;QACd,CAAC;QACD,aAAa,EAAE,KAAK;QACpB,cAAc,EAAE,IAAI;QACpB,OAAO,EAAE;YACP,uCAAuC;YACvC,IAAA,mDAAiC,EAAC,EAAE,UAAU,EAAE,CAAC;YACjD,4CAA4C;YAC5C;gBACE,KAAK,CAAC,eAAe;oBACnB,OAAO;wBACL,KAAK,CAAC,WAAW;4BACf,MAAM,aAAa,CAAC,OAAO,EAAE,CAAA;wBAC/B,CAAC;qBACF,CAAA;gBACH,CAAC;aACF;YACD,mCAAmC;YACnC,IAAA,wDAA8C,EAAC;gBAC7C,QAAQ,EAAE,8BAA8B;gBACxC,MAAM,EAAE,KAAK;aACd,CAAC;SACH;QACD,KAAK,EAAE,SAAS;KACjB,CAAC,CAAA;IAEF,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;IAEpB,4CAAkB,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;IAEzC,wBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QAChC,MAAM,EAAE,eAAe,EAAE,GAAG,IAAA,YAAM,EAAC,IAAI,CAAC,CAAA;QACxC,eAAe,IAAI,eAAe,CAAC,GAAG,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAA;IACpD,MAAM,CAAC,GAAG,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,oBAAoB,IAAI,EAAE;QAChC,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,MAAM;QACf,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,KAAK;KACb,CAAC,CAAA;IAEF,GAAG,CAAC,GAAG,CAAC,IAAA,wBAAa,EAAC,gBAAgB,CAAC,CAAC,CAAA;IAExC,aAAa;IACb,MAAM,cAAc,GAAG,EAAE,CAAA;IACzB,OAAO,CAAC,IAAI,CAAC,kCAAyC,EAAE,IAAI,EAAE,cAAc,CAAC,CAAA;IAC7E,GAAG,CAAC,cAAc,GAAG,cAAc,CAAA;IAEnC,OAAO,CAAC,IAAI,CAAC,sCAA6C,EAAE,GAAG,EAAE,6BAAkB,CAAC,CAAA;IACpF,OAAO,CAAC,IAAI,CAAC,uCAA8C,EAAE,GAAG,EAAE,8BAAmB,CAAC,CAAA;IACtF,OAAO,CAAC,IAAI,CAAC,sCAA6C,EAAE,GAAG,EAAE,6BAAkB,CAAC,CAAA;IACpF,OAAO,CAAC,IAAI,CAAC,uCAA8C,EAAE,GAAG,EAAE,8BAAmB,CAAC,CAAA;IAEtF,GAAG,CAAC,GAAG,CAAC,uCAAa,CAAC,CAAA,CAAC,gEAAgE;IAEvF,GAAG;SACA,GAAG,CAAC,6BAAkB,CAAC,MAAM,EAAE,CAAC;SAChC,GAAG,CAAC,6BAAkB,CAAC,cAAc,EAAE,CAAC;SACxC,GAAG,CAAC,8BAAmB,CAAC,MAAM,EAAE,CAAC;SACjC,GAAG,CAAC,8BAAmB,CAAC,cAAc,EAAE,CAAC;SACzC,GAAG,CAAC,6BAAkB,CAAC,MAAM,EAAE,CAAC;SAChC,GAAG,CAAC,6BAAkB,CAAC,cAAc,EAAE,CAAC;SACxC,GAAG,CAAC,8BAAmB,CAAC,MAAM,EAAE,CAAC;SACjC,GAAG,CAAC,8BAAmB,CAAC,cAAc,EAAE,CAAC,CAAA;IAE5C,oJAAoJ;IACpJ,GAAG,CAAC,GAAG,CAAC,IAAA,6BAAgB,EAAC,gBAAgB,CAAC,CAAC,CAAA;IAE3C,wBAAa,CAAC,IAAI,CAChB,UAAU,EACV,IAAA,mBAAa,EAAC,MAAM,EAAE;QACpB,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG;KAChC,CAAC,CACH,CAAA;IACD,GAAG,CAAC,GAAG,CAAC,wBAAa,CAAC,MAAM,EAAE,CAAC,CAAA;IAC/B,GAAG,CAAC,GAAG,CAAC,wBAAa,CAAC,cAAc,EAAE,CAAC,CAAA;IAEvC,8DAA8D;IAC9D,GAAG,CAAC,GAAG,CAAC,IAAA,sDAAkB,EAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;IAE9C,GAAG,CAAC,GAAG,CACL,IAAA,oBAAS,EAAC,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,EAAE;QAC9C,KAAK,EAAE,YAAY;KACpB,CAAC,CACH,CAAA;IAED,8EAA8E;IAC9E,mFAAmF;IACnF,2BAA2B;IAC3B,MAAM,gBAAgB,GAAG,YAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAA;IAE9D,gFAAgF;IAChF,0FAA0F;IAC1F,mFAAmF;IACnF,kFAAkF;IAClF,gFAAgF;IAChF,gCAAgC;IAChC,UAAU,CAAC,gBAAgB,GAAG,gBAAgB,IAAI,KAAK,CAAA;IAEvD,2EAA2E;IAC3E,iFAAiF;IACjF,qFAAqF;IACrF,gFAAgF;IAChF,+EAA+E;IAC/E,4CAA4C;IAC5C,UAAU,CAAC,cAAc,GAAG,gBAAgB,GAAG,IAAI,CAAA;IAEnD,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE;QACrC,YAAM,CAAC,IAAI,CAAC,qCAAqC,IAAI,UAAU,CAAC,CAAA;QAChE,YAAM,CAAC,IAAI,CAAC,0CAA0C,IAAI,UAAU,CAAC,CAAA;QAErE,OAAO,CAAC,IAAI,CAAC,wBAA+B,EAAE,EAAE,GAAG,EAAE,MAAM,EAAN,YAAM,EAAE,WAAW,EAAE,UAAU,EAAS,CAAC,CAAA;IAChG,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,SAAS,EAAE,CAAA","sourcesContent":["// ts-import-sorter: disable\n\n/* following 5 lines should be located in top of the file */\nimport OS from 'os'\nprocess.env.UV_THREADPOOL_SIZE = String(OS.availableParallelism())\n\nconsole.log('UV_THREADPOOL_SIZE', process.env.UV_THREADPOOL_SIZE)\n\nprocess.env.NODE_ENV = 'production'\nprocess.setMaxListeners(0)\n\nimport { ApolloServer } from '@apollo/server'\nimport { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer'\nimport { ApolloServerPluginLandingPageProductionDefault } from '@apollo/server/plugin/landingPage/default'\nimport { koaMiddleware } from '@as-integrations/koa'\n\nimport bytesFormat from 'bytes'\nimport graphqlUploadKoa from 'graphql-upload/graphqlUploadKoa.js'\nimport { useServer } from 'graphql-ws/lib/use/ws'\nimport { createServer } from 'http'\nimport Koa from 'koa'\nimport koaBodyParser from 'koa-bodyparser'\nimport koaStatic from 'koa-static'\nimport compose from 'koa-compose'\nimport { historyApiFallback } from 'koa2-connect-history-api-fallback'\nimport { WebSocketServer } from 'ws'\nimport co from 'co'\nimport http from 'http'\nimport path from 'path'\nimport args from 'args'\n\nimport cors from '@koa/cors'\nimport crypto from 'crypto'\n\nimport { config, loader, logger, orderedModuleNames } from '@things-factory/env'\nimport { initLicense, checkValidity } from '@things-factory/operato-license-checker'\n\nimport { GraphqlLocalClient } from './graphql-local-client.js'\nimport { databaseInitializer } from './initializers/database.js'\nimport {\n domainPrivateRouter,\n domainPublicRouter,\n globalPrivateRouter,\n globalPublicRouter,\n graphqlRouter\n} from './routers/index.js'\nimport { schema } from './schema.js'\nimport { domainMiddleware } from './middlewares/domain-middleware.js'\nimport { setupProcessExitHandlers } from './process-cleaner.js'\n\nsetupProcessExitHandlers()\n\nargs.option('port', 'The port on which the app will be running', config.get('port', 3000))\n\nconst flags = args.parse(process.argv)\n\nconst PORT = (process.env.PORT = flags.port)\n\nconst requestBody = config.get('requestBody') || {}\n\nconst bodyParserOption = {\n formLimit: requestBody.formLimit || '10mb',\n jsonLimit: requestBody.jsonLimit || '10mb',\n textLimit: requestBody.textLimit || '10mb'\n}\n\nconst fileUpload = config.get('fileUpload') || {}\nconst fileUploadOption = {\n maxFileSize: bytesFormat.parse(fileUpload.maxFileSize) || bytesFormat.parse('10mb'),\n maxFiles: fileUpload.maxFiles || 10\n}\n\ninitLicense(config.get('licenseKey'))\n\n/* bootstrap */\nconst bootstrap = async () => {\n await databaseInitializer()\n\n const app = new Koa() as any\n app.proxy = true\n\n app.use(\n cors({\n origin: function (ctx) {\n return ctx.request.headers.origin || '*'\n },\n exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],\n maxAge: 5,\n credentials: true,\n /* allowMethods: ['GET', 'POST', 'DELETE'], -- use default */\n allowHeaders: ['Content-Type', 'Authorization', 'Accept']\n })\n )\n\n app.use(async (ctx, next) => {\n ctx.set('X-Content-Type-Options', 'nosniff')\n\n const { directives = {} } = config.get('CSP') || {}\n\n const nonce = crypto.randomBytes(16).toString('base64')\n ctx.state.nonce = nonce\n\n const cspHeader = Object.entries(directives as { [key: string]: string[] })\n .map(([key, value]) => `${key} ${value.join(' ')}`)\n .join('; ')\n\n ctx.set('Content-Security-Policy', cspHeader)\n\n await next()\n })\n\n var subscriptionMiddleware = []\n process.emit('bootstrap-module-subscription' as any, app, subscriptionMiddleware)\n\n const builtSchema = await schema()\n\n const httpServer = createServer(app.callback())\n const websocketServer = new WebSocketServer({\n server: httpServer,\n path: '/graphql'\n })\n\n // Save the returned server's info so we can shut down this server later\n const serverCleanup = useServer(\n {\n schema: builtSchema,\n context: async (ctx, msg, args) => {\n return ctx['context']\n },\n onConnect: async ctx => {\n var { extra, connectionParams } = ctx\n var { request } = extra\n\n if (((connectionParams['headers'] as any) || connectionParams)?.referer) {\n var url = new URL(((connectionParams['headers'] as any) || connectionParams).referer)\n var accessToken = url.searchParams.get('access_token')\n if (accessToken) {\n connectionParams['headers']['authorization'] = accessToken\n }\n }\n\n request.headers = {\n ...request.headers,\n ...(connectionParams['headers'] || (connectionParams as any))\n }\n\n var koacontext = await app.createContext(request, new http.ServerResponse(request))\n koacontext['state'] = {}\n\n /* in case connect error(like a authentication error) just throw exception */\n var middlewares = [domainMiddleware, ...subscriptionMiddleware]\n const fn = co.wrap(compose(middlewares))\n\n await fn(koacontext)\n\n return (ctx['context'] = koacontext)\n },\n onDisconnect(ctx, code, reason) {\n console.log('Disconnected!')\n },\n onError(ctx, msg, errors) {\n console.error(msg, errors)\n }\n },\n websocketServer\n )\n\n const server = new ApolloServer({\n schema: builtSchema,\n formatError: error => {\n logger.error(error)\n return error\n },\n introspection: false,\n csrfPrevention: true,\n plugins: [\n // Proper shutdown for the HTTP server.\n ApolloServerPluginDrainHttpServer({ httpServer }),\n // Proper shutdown for the WebSocket server.\n {\n async serverWillStart() {\n return {\n async drainServer() {\n await serverCleanup.dispose()\n }\n }\n }\n },\n // TODO make this landing page work\n ApolloServerPluginLandingPageProductionDefault({\n graphRef: 'my-graph-id@my-graph-variant',\n footer: false\n })\n ],\n cache: 'bounded'\n })\n\n await server.start()\n\n GraphqlLocalClient.init(builtSchema, app)\n\n orderedModuleNames.forEach(name => {\n const { initMiddlewares } = loader(name)\n initMiddlewares && initMiddlewares(app)\n })\n\n const render = require('@things-factory/ejs-remote')\n render(app, {\n root: '/views',\n host: `http://127.0.0.1:${PORT}`,\n layout: false,\n viewExt: 'html',\n cache: true,\n debug: false\n })\n\n app.use(koaBodyParser(bodyParserOption))\n\n /* routers */\n const ssoMiddlewares = []\n process.emit('bootstrap-collect-sso-middleware' as any, null, ssoMiddlewares)\n app.ssoMiddlewares = ssoMiddlewares\n\n process.emit('bootstrap-module-global-public-route' as any, app, globalPublicRouter)\n process.emit('bootstrap-module-global-private-route' as any, app, globalPrivateRouter)\n process.emit('bootstrap-module-domain-public-route' as any, app, domainPublicRouter)\n process.emit('bootstrap-module-domain-private-route' as any, app, domainPrivateRouter)\n\n app.use(checkValidity) /* Check the license after most of the context has been built */\n\n app\n .use(globalPublicRouter.routes())\n .use(globalPublicRouter.allowedMethods())\n .use(globalPrivateRouter.routes())\n .use(globalPrivateRouter.allowedMethods())\n .use(domainPublicRouter.routes())\n .use(domainPublicRouter.allowedMethods())\n .use(domainPrivateRouter.routes())\n .use(domainPrivateRouter.allowedMethods())\n\n /* Graphql Upload's multipart/form-data handling affects the restful file upload feature, so it should be placed after the routers configuration. */\n app.use(graphqlUploadKoa(fileUploadOption))\n\n graphqlRouter.post(\n '/graphql',\n koaMiddleware(server, {\n context: async ({ ctx }) => ctx\n })\n )\n app.use(graphqlRouter.routes())\n app.use(graphqlRouter.allowedMethods())\n\n /* should follow this order : history-fallback => koaStatic */\n app.use(historyApiFallback({ whiteList: [] }))\n\n app.use(\n koaStatic(path.join(process.cwd(), 'dist-app'), {\n index: 'index.html'\n })\n )\n\n // Set keep-alive timeout from configuration or fallback to default (65000ms).\n // The keepAliveTimeout determines how long the server will keep an idle connection\n // alive before closing it.\n const keepAliveTimeout = config.get('keepAliveTimeout', 65000)\n\n // Apply the configured keep-alive timeout to the server. If no configuration is\n // provided, default to 65000ms (65 seconds). In the context of an external load balancer,\n // this timeout is critical for maintaining persistent connections between the load\n // balancer and the server. Setting a sufficiently long keepAliveTimeout minimizes\n // the need to constantly re-establish TCP connections, improving efficiency and\n // reducing connection overhead.\n httpServer.keepAliveTimeout = keepAliveTimeout || 65000\n\n // Set headersTimeout to be 1000ms (1 second) longer than keepAliveTimeout.\n // This ensures the server has sufficient time to receive headers from the client\n // before closing the connection, preventing premature disconnections. In the context\n // of a load balancer, this ensures that if the load balancer is sending headers\n // slowly (due to network delays or other factors), the connection isn't closed\n // before the headers are fully transmitted.\n httpServer.headersTimeout = keepAliveTimeout + 1000\n\n httpServer.listen({ port: PORT }, () => {\n logger.info(`🚀 Server ready at http://0.0.0.0:${PORT}/graphql`)\n logger.info(`🚀 Subscriptions ready at ws://0.0.0.0:${PORT}/graphql`)\n\n process.emit('bootstrap-module-start' as any, { app, config, builtSchema, httpServer } as any)\n })\n}\n\nbootstrap()\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../server/server.ts"],"names":[],"mappings":"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","sourcesContent":["// ts-import-sorter: disable\n\n/* following 5 lines should be located in top of the file */\nimport OS from 'os'\nprocess.env.UV_THREADPOOL_SIZE = String(OS.availableParallelism())\n\nconsole.log('UV_THREADPOOL_SIZE', process.env.UV_THREADPOOL_SIZE)\n\nprocess.env.NODE_ENV = 'production'\nprocess.setMaxListeners(0)\n\nimport { ApolloServer } from '@apollo/server'\nimport { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer'\nimport { ApolloServerPluginLandingPageProductionDefault } from '@apollo/server/plugin/landingPage/default'\nimport { koaMiddleware } from '@as-integrations/koa'\n\nimport bytesFormat from 'bytes'\nimport graphqlUploadKoa from 'graphql-upload/graphqlUploadKoa.js'\nimport { useServer } from 'graphql-ws/lib/use/ws'\nimport { createServer } from 'http'\nimport Koa from 'koa'\nimport koaBodyParser from 'koa-bodyparser'\nimport koaStatic from 'koa-static'\nimport compose from 'koa-compose'\nimport { historyApiFallback } from 'koa2-connect-history-api-fallback'\nimport { WebSocketServer } from 'ws'\nimport co from 'co'\nimport http from 'http'\nimport path from 'path'\nimport args from 'args'\n\nimport cors from '@koa/cors'\nimport crypto from 'crypto'\n\nimport { config, loader, logger, orderedModuleNames } from '@things-factory/env'\nimport { initLicense, checkValidity } from '@things-factory/operato-license-checker'\n\nimport { GraphqlLocalClient } from './graphql-local-client.js'\nimport { databaseInitializer } from './initializers/database.js'\nimport {\n domainPrivateRouter,\n domainPublicRouter,\n globalPrivateRouter,\n globalPublicRouter,\n graphqlRouter\n} from './routers/index.js'\nimport { schema } from './schema.js'\nimport { domainMiddleware } from './middlewares/domain-middleware.js'\nimport { setupProcessExitHandlers } from './process-cleaner.js'\n\nsetupProcessExitHandlers()\n\nargs.option('port', 'The port on which the app will be running', config.get('port', 3000))\n\nconst flags = args.parse(process.argv)\n\nconst PORT = (process.env.PORT = flags.port)\n\nconst requestBody = config.get('requestBody') || {}\n\nconst bodyParserOption = {\n formLimit: requestBody.formLimit || '10mb',\n jsonLimit: requestBody.jsonLimit || '10mb',\n textLimit: requestBody.textLimit || '10mb'\n}\n\nconst fileUpload = config.get('fileUpload') || {}\nconst fileUploadOption = {\n maxFileSize: bytesFormat.parse(fileUpload.maxFileSize) || bytesFormat.parse('10mb'),\n maxFiles: fileUpload.maxFiles || 10\n}\n\ninitLicense(config.get('licenseKey'))\n\n/* bootstrap */\nconst bootstrap = async () => {\n await databaseInitializer()\n\n const app = new Koa() as any\n app.proxy = true\n\n app.use(\n cors({\n origin: function (ctx) {\n return ctx.request.headers.origin || '*'\n },\n exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],\n maxAge: 5,\n credentials: true,\n /* allowMethods: ['GET', 'POST', 'DELETE'], -- use default */\n allowHeaders: ['Content-Type', 'Authorization', 'Accept']\n })\n )\n\n app.use(async (ctx, next) => {\n ctx.set('X-Content-Type-Options', 'nosniff')\n\n const { directives = {} } = config.get('CSP') || {}\n\n const nonce = crypto.randomBytes(16).toString('base64')\n ctx.state.nonce = nonce\n\n const cspHeader = Object.entries(directives as { [key: string]: string[] })\n .map(([key, value]) => `${key} ${value.join(' ')}`)\n .join('; ')\n\n ctx.set('Content-Security-Policy', cspHeader)\n\n await next()\n })\n\n var subscriptionMiddleware = []\n process.emit('bootstrap-module-subscription' as any, app, subscriptionMiddleware)\n\n const builtSchema = await schema()\n\n const httpServer = createServer(app.callback())\n const websocketServer = new WebSocketServer({\n server: httpServer,\n path: '/graphql'\n })\n\n // Save the returned server's info so we can shut down this server later\n const serverCleanup = useServer(\n {\n schema: builtSchema,\n context: async (ctx, msg, args) => {\n return ctx['context']\n },\n onConnect: async ctx => {\n var { extra, connectionParams } = ctx\n var { request } = extra\n\n if (((connectionParams['headers'] as any) || connectionParams)?.referer) {\n var url = new URL(((connectionParams['headers'] as any) || connectionParams).referer)\n var accessToken = url.searchParams.get('access_token')\n if (accessToken) {\n connectionParams['headers']['authorization'] = accessToken\n }\n }\n\n request.headers = {\n ...request.headers,\n ...(connectionParams['headers'] || (connectionParams as any))\n }\n\n var koacontext = await app.createContext(request, new http.ServerResponse(request))\n koacontext['state'] = {}\n\n /* in case connect error(like a authentication error) just throw exception */\n var middlewares = [domainMiddleware, ...subscriptionMiddleware]\n const fn = co.wrap(compose(middlewares))\n\n await fn(koacontext)\n\n return (ctx['context'] = koacontext)\n },\n onDisconnect(ctx, code, reason) {\n console.log('Disconnected!')\n },\n onError(ctx, msg, errors) {\n console.error(msg, errors)\n }\n },\n websocketServer\n )\n\n const server = new ApolloServer({\n schema: builtSchema,\n formatError: error => {\n logger.error(error)\n return error\n },\n introspection: false,\n csrfPrevention: true,\n stopOnTerminationSignals: false, // ★ 자동 시그널 핸들러 비활성화\n plugins: [\n // Proper shutdown for the HTTP server.\n ApolloServerPluginDrainHttpServer({ httpServer }),\n // Proper shutdown for the WebSocket server.\n {\n async serverWillStart() {\n return {\n async drainServer() {\n await serverCleanup.dispose()\n }\n }\n }\n },\n // TODO make this landing page work\n ApolloServerPluginLandingPageProductionDefault({\n graphRef: 'my-graph-id@my-graph-variant',\n footer: false\n })\n ],\n cache: 'bounded'\n })\n\n await server.start()\n\n GraphqlLocalClient.init(builtSchema, app)\n\n orderedModuleNames.forEach(name => {\n const { initMiddlewares } = loader(name)\n initMiddlewares && initMiddlewares(app)\n })\n\n const render = require('@things-factory/ejs-remote')\n render(app, {\n root: '/views',\n host: `http://127.0.0.1:${PORT}`,\n layout: false,\n viewExt: 'html',\n cache: true,\n debug: false\n })\n\n app.use(koaBodyParser(bodyParserOption))\n\n /* routers */\n const ssoMiddlewares = []\n process.emit('bootstrap-collect-sso-middleware' as any, null, ssoMiddlewares)\n app.ssoMiddlewares = ssoMiddlewares\n\n process.emit('bootstrap-module-global-public-route' as any, app, globalPublicRouter)\n process.emit('bootstrap-module-global-private-route' as any, app, globalPrivateRouter)\n process.emit('bootstrap-module-domain-public-route' as any, app, domainPublicRouter)\n process.emit('bootstrap-module-domain-private-route' as any, app, domainPrivateRouter)\n\n app.use(checkValidity) /* Check the license after most of the context has been built */\n\n app\n .use(globalPublicRouter.routes())\n .use(globalPublicRouter.allowedMethods())\n .use(globalPrivateRouter.routes())\n .use(globalPrivateRouter.allowedMethods())\n .use(domainPublicRouter.routes())\n .use(domainPublicRouter.allowedMethods())\n .use(domainPrivateRouter.routes())\n .use(domainPrivateRouter.allowedMethods())\n\n /* Graphql Upload's multipart/form-data handling affects the restful file upload feature, so it should be placed after the routers configuration. */\n app.use(graphqlUploadKoa(fileUploadOption))\n\n graphqlRouter.post(\n '/graphql',\n koaMiddleware(server, {\n context: async ({ ctx }) => ctx\n })\n )\n app.use(graphqlRouter.routes())\n app.use(graphqlRouter.allowedMethods())\n\n /* should follow this order : history-fallback => koaStatic */\n app.use(historyApiFallback({ whiteList: [] }))\n\n app.use(\n koaStatic(path.join(process.cwd(), 'dist-app'), {\n index: 'index.html'\n })\n )\n\n // Set keep-alive timeout from configuration or fallback to default (65000ms).\n // The keepAliveTimeout determines how long the server will keep an idle connection\n // alive before closing it.\n const keepAliveTimeout = config.get('keepAliveTimeout', 65000)\n\n // Apply the configured keep-alive timeout to the server. If no configuration is\n // provided, default to 65000ms (65 seconds). In the context of an external load balancer,\n // this timeout is critical for maintaining persistent connections between the load\n // balancer and the server. Setting a sufficiently long keepAliveTimeout minimizes\n // the need to constantly re-establish TCP connections, improving efficiency and\n // reducing connection overhead.\n httpServer.keepAliveTimeout = keepAliveTimeout || 65000\n\n // Set headersTimeout to be 1000ms (1 second) longer than keepAliveTimeout.\n // This ensures the server has sufficient time to receive headers from the client\n // before closing the connection, preventing premature disconnections. In the context\n // of a load balancer, this ensures that if the load balancer is sending headers\n // slowly (due to network delays or other factors), the connection isn't closed\n // before the headers are fully transmitted.\n httpServer.headersTimeout = keepAliveTimeout + 1000\n\n httpServer.listen({ port: PORT }, () => {\n logger.info(`🚀 Server ready at http://0.0.0.0:${PORT}/graphql`)\n logger.info(`🚀 Subscriptions ready at ws://0.0.0.0:${PORT}/graphql`)\n\n process.emit('bootstrap-module-start' as any, { app, config, builtSchema, httpServer } as any)\n })\n}\n\nbootstrap()\n"]}