@things-factory/integration-headless 7.0.37

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 (45) hide show
  1. package/dist-server/engine/connector/headless-connector.d.ts +13 -0
  2. package/dist-server/engine/connector/headless-connector.js +51 -0
  3. package/dist-server/engine/connector/headless-connector.js.map +1 -0
  4. package/dist-server/engine/connector/headless-pool.d.ts +3 -0
  5. package/dist-server/engine/connector/headless-pool.js +63 -0
  6. package/dist-server/engine/connector/headless-pool.js.map +1 -0
  7. package/dist-server/engine/connector/index.d.ts +1 -0
  8. package/dist-server/engine/connector/index.js +4 -0
  9. package/dist-server/engine/connector/index.js.map +1 -0
  10. package/dist-server/engine/index.d.ts +2 -0
  11. package/dist-server/engine/index.js +5 -0
  12. package/dist-server/engine/index.js.map +1 -0
  13. package/dist-server/engine/task/headless-pdf-capture.d.ts +1 -0
  14. package/dist-server/engine/task/headless-pdf-capture.js +176 -0
  15. package/dist-server/engine/task/headless-pdf-capture.js.map +1 -0
  16. package/dist-server/engine/task/headless-pdf-open.d.ts +1 -0
  17. package/dist-server/engine/task/headless-pdf-open.js +61 -0
  18. package/dist-server/engine/task/headless-pdf-open.js.map +1 -0
  19. package/dist-server/engine/task/headless-pdf-save.d.ts +1 -0
  20. package/dist-server/engine/task/headless-pdf-save.js +72 -0
  21. package/dist-server/engine/task/headless-pdf-save.js.map +1 -0
  22. package/dist-server/engine/task/index.d.ts +3 -0
  23. package/dist-server/engine/task/index.js +6 -0
  24. package/dist-server/engine/task/index.js.map +1 -0
  25. package/dist-server/index.d.ts +1 -0
  26. package/dist-server/index.js +4 -0
  27. package/dist-server/index.js.map +1 -0
  28. package/dist-server/tsconfig.tsbuildinfo +1 -0
  29. package/package.json +31 -0
  30. package/server/engine/connector/headless-connector.ts +64 -0
  31. package/server/engine/connector/headless-pool.ts +69 -0
  32. package/server/engine/connector/index.ts +1 -0
  33. package/server/engine/index.ts +2 -0
  34. package/server/engine/task/headless-pdf-capture.ts +222 -0
  35. package/server/engine/task/headless-pdf-open.ts +75 -0
  36. package/server/engine/task/headless-pdf-save.ts +84 -0
  37. package/server/engine/task/index.ts +3 -0
  38. package/server/index.ts +1 -0
  39. package/server/tsconfig.json +10 -0
  40. package/things-factory.config.js +1 -0
  41. package/translations/en.json +19 -0
  42. package/translations/ja.json +19 -0
  43. package/translations/ko.json +19 -0
  44. package/translations/ms.json +19 -0
  45. package/translations/zh.json +19 -0
@@ -0,0 +1,13 @@
1
+ import { Connector } from '@things-factory/integration-base';
2
+ export declare class HeadlessConnector implements Connector {
3
+ ready(connectionConfigs: any): Promise<void>;
4
+ connect(connection: any): Promise<void>;
5
+ disconnect(connection: any): Promise<void>;
6
+ get parameterSpec(): {
7
+ type: string;
8
+ name: string;
9
+ label: string;
10
+ }[];
11
+ get taskPrefixes(): string[];
12
+ get description(): string;
13
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HeadlessConnector = void 0;
4
+ const integration_base_1 = require("@things-factory/integration-base");
5
+ const headless_pool_1 = require("./headless-pool");
6
+ class HeadlessConnector {
7
+ async ready(connectionConfigs) {
8
+ await Promise.all(connectionConfigs.map(this.connect.bind(this)));
9
+ integration_base_1.ConnectionManager.logger.info('headless-connector connections are ready');
10
+ }
11
+ async connect(connection) {
12
+ var { endpoint: uri = '1', params: { min = 2, max = 10 } } = connection;
13
+ const headlessPool = (0, headless_pool_1.createHeadlessPool)({
14
+ min,
15
+ max,
16
+ testOnBorrow: true,
17
+ acquireTimeoutMillis: 15000
18
+ });
19
+ integration_base_1.ConnectionManager.addConnectionInstance(connection, headlessPool);
20
+ integration_base_1.ConnectionManager.logger.info(`headless-connector connection(${connection.name}:${connection.endpoint}) is connected`);
21
+ }
22
+ async disconnect(connection) {
23
+ const headlessPool = integration_base_1.ConnectionManager.getConnectionInstance(connection);
24
+ (0, headless_pool_1.destroyHeadlessPool)(headlessPool);
25
+ integration_base_1.ConnectionManager.removeConnectionInstance(connection);
26
+ integration_base_1.ConnectionManager.logger.info(`headless-connector connection(${connection.name}) is disconnected`);
27
+ }
28
+ get parameterSpec() {
29
+ return [
30
+ {
31
+ type: 'number',
32
+ name: 'min',
33
+ label: 'pool-size-min'
34
+ },
35
+ {
36
+ type: 'number',
37
+ name: 'max',
38
+ label: 'pool-size-max'
39
+ }
40
+ ];
41
+ }
42
+ get taskPrefixes() {
43
+ return ['headless'];
44
+ }
45
+ get description() {
46
+ return 'Headless Pool Connector';
47
+ }
48
+ }
49
+ exports.HeadlessConnector = HeadlessConnector;
50
+ integration_base_1.ConnectionManager.registerConnector('headless-connector', new HeadlessConnector());
51
+ //# sourceMappingURL=headless-connector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless-connector.js","sourceRoot":"","sources":["../../../server/engine/connector/headless-connector.ts"],"names":[],"mappings":";;;AAAA,uEAA+E;AAC/E,mDAAyE;AAEzE,MAAa,iBAAiB;IAC5B,KAAK,CAAC,KAAK,CAAC,iBAAiB;QAC3B,MAAM,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAEjE,oCAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAA;IAC3E,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,UAAU;QACtB,IAAI,EACF,QAAQ,EAAE,GAAG,GAAG,GAAG,EACnB,MAAM,EAAE,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE,EAC9B,GAAG,UAAU,CAAA;QAEd,MAAM,YAAY,GAAG,IAAA,kCAAkB,EAAC;YACtC,GAAG;YACH,GAAG;YACH,YAAY,EAAE,IAAI;YAClB,oBAAoB,EAAE,KAAK;SAC5B,CAAC,CAAA;QAEF,oCAAiB,CAAC,qBAAqB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAA;QAEjE,oCAAiB,CAAC,MAAM,CAAC,IAAI,CAC3B,iCAAiC,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,QAAQ,gBAAgB,CACxF,CAAA;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,UAAU;QACzB,MAAM,YAAY,GAAG,oCAAiB,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAA;QACxE,IAAA,mCAAmB,EAAC,YAAY,CAAC,CAAA;QAEjC,oCAAiB,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAA;QAEtD,oCAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,iCAAiC,UAAU,CAAC,IAAI,mBAAmB,CAAC,CAAA;IACpG,CAAC;IAED,IAAI,aAAa;QACf,OAAO;YACL;gBACE,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,KAAK;gBACX,KAAK,EAAE,eAAe;aACvB;YACD;gBACE,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,KAAK;gBACX,KAAK,EAAE,eAAe;aACvB;SACF,CAAA;IACH,CAAC;IAED,IAAI,YAAY;QACd,OAAO,CAAC,UAAU,CAAC,CAAA;IACrB,CAAC;IAED,IAAI,WAAW;QACb,OAAO,yBAAyB,CAAA;IAClC,CAAC;CACF;AA1DD,8CA0DC;AAED,oCAAiB,CAAC,iBAAiB,CAAC,oBAAoB,EAAE,IAAI,iBAAiB,EAAE,CAAC,CAAA","sourcesContent":["import { ConnectionManager, Connector } from '@things-factory/integration-base'\nimport { createHeadlessPool, destroyHeadlessPool } from './headless-pool'\n\nexport class HeadlessConnector implements Connector {\n async ready(connectionConfigs) {\n await Promise.all(connectionConfigs.map(this.connect.bind(this)))\n\n ConnectionManager.logger.info('headless-connector connections are ready')\n }\n\n async connect(connection) {\n var {\n endpoint: uri = '1',\n params: { min = 2, max = 10 }\n } = connection\n\n const headlessPool = createHeadlessPool({\n min,\n max,\n testOnBorrow: true,\n acquireTimeoutMillis: 15000\n })\n\n ConnectionManager.addConnectionInstance(connection, headlessPool)\n\n ConnectionManager.logger.info(\n `headless-connector connection(${connection.name}:${connection.endpoint}) is connected`\n )\n }\n\n async disconnect(connection) {\n const headlessPool = ConnectionManager.getConnectionInstance(connection)\n destroyHeadlessPool(headlessPool)\n\n ConnectionManager.removeConnectionInstance(connection)\n\n ConnectionManager.logger.info(`headless-connector connection(${connection.name}) is disconnected`)\n }\n\n get parameterSpec() {\n return [\n {\n type: 'number',\n name: 'min',\n label: 'pool-size-min'\n },\n {\n type: 'number',\n name: 'max',\n label: 'pool-size-max'\n }\n ]\n }\n\n get taskPrefixes() {\n return ['headless']\n }\n\n get description() {\n return 'Headless Pool Connector'\n }\n}\n\nConnectionManager.registerConnector('headless-connector', new HeadlessConnector())\n"]}
@@ -0,0 +1,3 @@
1
+ import * as genericPool from 'generic-pool';
2
+ export declare function createHeadlessPool(options: genericPool.Options): genericPool.Pool<any>;
3
+ export declare function destroyHeadlessPool(headlessPool: genericPool.Pool<any>): Promise<void>;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createHeadlessPool = createHeadlessPool;
4
+ exports.destroyHeadlessPool = destroyHeadlessPool;
5
+ const tslib_1 = require("tslib");
6
+ const genericPool = tslib_1.__importStar(require("generic-pool"));
7
+ const env_1 = require("@things-factory/env");
8
+ try {
9
+ var puppeteer = require('puppeteer');
10
+ }
11
+ catch (err) {
12
+ env_1.logger.error(err);
13
+ }
14
+ function createHeadlessPool(options) {
15
+ return genericPool.createPool({
16
+ create() {
17
+ console.log('headless-pool-integration about to create');
18
+ return initializeChromium();
19
+ },
20
+ validate(browser) {
21
+ return Promise.race([
22
+ new Promise(res => setTimeout(() => res(false), 1500)),
23
+ browser
24
+ //@ts-ignore
25
+ .version()
26
+ .then(_ => true)
27
+ .catch(_ => false)
28
+ ]);
29
+ },
30
+ destroy(browser) {
31
+ //@ts-ignore
32
+ return browser.close();
33
+ }
34
+ }, options);
35
+ }
36
+ async function destroyHeadlessPool(headlessPool) {
37
+ if (headlessPool) {
38
+ console.log('headless-pool-integration about to destroy');
39
+ await headlessPool.drain();
40
+ await headlessPool.clear();
41
+ }
42
+ }
43
+ const CHROMIUM_PATH = env_1.config.get('CHROMIUM_PATH');
44
+ async function initializeChromium() {
45
+ try {
46
+ if (!puppeteer) {
47
+ return;
48
+ }
49
+ var launchSetting = {
50
+ args: ['--hide-scrollbars', '--mute-audio', '--no-sandbox', '--use-gl=egl'],
51
+ headless: 'shell'
52
+ };
53
+ if (CHROMIUM_PATH) {
54
+ launchSetting['executablePath'] = CHROMIUM_PATH;
55
+ }
56
+ const browser = await puppeteer.launch(launchSetting);
57
+ return browser;
58
+ }
59
+ catch (err) {
60
+ env_1.logger.error(err);
61
+ }
62
+ }
63
+ //# sourceMappingURL=headless-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless-pool.js","sourceRoot":"","sources":["../../../server/engine/connector/headless-pool.ts"],"names":[],"mappings":";;AAUA,gDAwBC;AAED,kDAOC;;AA3CD,kEAA2C;AAE3C,6CAAoD;AAEpD,IAAI,CAAC;IACH,IAAI,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;AACtC,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,YAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;AACnB,CAAC;AAED,SAAgB,kBAAkB,CAAC,OAA4B;IAC7D,OAAO,WAAW,CAAC,UAAU,CAC3B;QACE,MAAM;YACJ,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;YACxD,OAAO,kBAAkB,EAAE,CAAA;QAC7B,CAAC;QACD,QAAQ,CAAC,OAAO;YACd,OAAO,OAAO,CAAC,IAAI,CAAC;gBAClB,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;gBACtD,OAAO;oBACL,YAAY;qBACX,OAAO,EAAE;qBACT,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC;qBACf,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;aACrB,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,CAAC,OAAO;YACb,YAAY;YACZ,OAAO,OAAO,CAAC,KAAK,EAAE,CAAA;QACxB,CAAC;KAC0B,EAC7B,OAAO,CACR,CAAA;AACH,CAAC;AAEM,KAAK,UAAU,mBAAmB,CAAC,YAAmC;IAC3E,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAA;QAEzD,MAAM,YAAY,CAAC,KAAK,EAAE,CAAA;QAC1B,MAAM,YAAY,CAAC,KAAK,EAAE,CAAA;IAC5B,CAAC;AACH,CAAC;AAED,MAAM,aAAa,GAAG,YAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;AAEjD,KAAK,UAAU,kBAAkB;IAC/B,IAAI,CAAC;QACH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAM;QACR,CAAC;QAED,IAAI,aAAa,GAAG;YAClB,IAAI,EAAE,CAAC,mBAAmB,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,CAAC;YAC3E,QAAQ,EAAE,OAAO;SAClB,CAAA;QAED,IAAI,aAAa,EAAE,CAAC;YAClB,aAAa,CAAC,gBAAgB,CAAC,GAAG,aAAa,CAAA;QACjD,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;QAErD,OAAO,OAAO,CAAA;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,YAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACnB,CAAC;AACH,CAAC","sourcesContent":["import * as genericPool from 'generic-pool'\n\nimport { config, logger } from '@things-factory/env'\n\ntry {\n var puppeteer = require('puppeteer')\n} catch (err) {\n logger.error(err)\n}\n\nexport function createHeadlessPool(options: genericPool.Options) {\n return genericPool.createPool(\n {\n create() {\n console.log('headless-pool-integration about to create')\n return initializeChromium()\n },\n validate(browser) {\n return Promise.race([\n new Promise(res => setTimeout(() => res(false), 1500)),\n browser\n //@ts-ignore\n .version()\n .then(_ => true)\n .catch(_ => false)\n ])\n },\n destroy(browser) {\n //@ts-ignore\n return browser.close()\n }\n } as genericPool.Factory<any>,\n options\n )\n}\n\nexport async function destroyHeadlessPool(headlessPool: genericPool.Pool<any>) {\n if (headlessPool) {\n console.log('headless-pool-integration about to destroy')\n\n await headlessPool.drain()\n await headlessPool.clear()\n }\n}\n\nconst CHROMIUM_PATH = config.get('CHROMIUM_PATH')\n\nasync function initializeChromium() {\n try {\n if (!puppeteer) {\n return\n }\n\n var launchSetting = {\n args: ['--hide-scrollbars', '--mute-audio', '--no-sandbox', '--use-gl=egl'],\n headless: 'shell'\n }\n\n if (CHROMIUM_PATH) {\n launchSetting['executablePath'] = CHROMIUM_PATH\n }\n\n const browser = await puppeteer.launch(launchSetting)\n\n return browser\n } catch (err) {\n logger.error(err)\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ import './headless-connector';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ require("./headless-connector");
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/engine/connector/index.ts"],"names":[],"mappings":";;AAAA,gCAA6B","sourcesContent":["import './headless-connector'\n"]}
@@ -0,0 +1,2 @@
1
+ import './connector';
2
+ import './task';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ require("./connector");
4
+ require("./task");
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/engine/index.ts"],"names":[],"mappings":";;AAAA,uBAAoB;AACpB,kBAAe","sourcesContent":["import './connector'\nimport './task'\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const ejs = tslib_1.__importStar(require("ejs"));
5
+ const pdf_lib_1 = require("pdf-lib");
6
+ const integration_base_1 = require("@things-factory/integration-base");
7
+ const integration_base_2 = require("@things-factory/integration-base");
8
+ async function HeadlessPDFCapture(step, context) {
9
+ var { connection: connectionName, params: stepOptions } = step;
10
+ var { htmlContent, format, width, height, margin, scale, printBackground, landscape, displayHeaderFooter, headerTemplate, footerTemplate, preferCSSPageSize } = stepOptions || {};
11
+ var { domain, data, __headless_pdf } = context;
12
+ if (!__headless_pdf) {
13
+ throw new Error('it requires headless-pdf-open to be performed first');
14
+ }
15
+ var { pdf, header: headerTemplateFromContext, footer: footerTemplateFromContext, watermark, pageCount } = __headless_pdf;
16
+ var headlessPool = integration_base_2.ConnectionManager.getConnectionInstanceByName(domain, connectionName);
17
+ let browser;
18
+ try {
19
+ // Puppeteer를 사용하여 브라우저와 페이지 인스턴스를 생성
20
+ browser = await headlessPool.acquire();
21
+ const page = await browser.newPage();
22
+ // 설정된 HTML 콘텐츠를 페이지에 설정
23
+ await page.setContent(htmlContent);
24
+ // PDF 페이지 생성 옵션 설정
25
+ if (preferCSSPageSize) {
26
+ width = undefined;
27
+ height = undefined;
28
+ }
29
+ const pageOptions = {
30
+ format,
31
+ width,
32
+ height,
33
+ margin,
34
+ scale,
35
+ printBackground,
36
+ landscape,
37
+ displayHeaderFooter,
38
+ headerTemplate: displayHeaderFooter ? headerTemplate : undefined,
39
+ footerTemplate: displayHeaderFooter ? footerTemplate : undefined,
40
+ preferCSSPageSize
41
+ };
42
+ // 페이지를 PDF로 변환
43
+ const pageBuffer = await page.pdf(pageOptions);
44
+ // PDF-lib을 사용하여 PDF를 로드하고 추가 조작
45
+ const pdfDoc = await pdf_lib_1.PDFDocument.load(pageBuffer);
46
+ const pages = await pdf.copyPages(pdfDoc, pdfDoc.getPageIndices());
47
+ pages.forEach((newPage, index) => {
48
+ const currentPageNumber = pageCount + index + 1;
49
+ // 헤더와 푸터 렌더링 (페이지 번호 및 총 페이지 수 포함)
50
+ if (displayHeaderFooter && (headerTemplateFromContext || footerTemplateFromContext)) {
51
+ const renderedHeader = headerTemplateFromContext
52
+ ? ejs.render(headerTemplateFromContext, Object.assign(Object.assign({}, data), { pageNumber: currentPageNumber, totalPages: pageCount + pages.length }))
53
+ : '';
54
+ const renderedFooter = footerTemplateFromContext
55
+ ? ejs.render(footerTemplateFromContext, Object.assign(Object.assign({}, data), { pageNumber: currentPageNumber, totalPages: pageCount + pages.length }))
56
+ : '';
57
+ // Header/Footer 그리기
58
+ if (renderedHeader) {
59
+ newPage.drawText(renderedHeader, { x: 50, y: newPage.getHeight() - 30, size: 12, color: (0, pdf_lib_1.rgb)(0, 0, 0) });
60
+ }
61
+ if (renderedFooter) {
62
+ newPage.drawText(renderedFooter, { x: 50, y: 30, size: 12, color: (0, pdf_lib_1.rgb)(0, 0, 0) });
63
+ }
64
+ }
65
+ // 워터마크 추가
66
+ if (watermark) {
67
+ const fontSize = 50;
68
+ const pageWidth = newPage.getWidth();
69
+ const pageHeight = newPage.getHeight();
70
+ newPage.drawText(watermark, {
71
+ x: pageWidth / 2 - (fontSize * watermark.length) / 4,
72
+ y: pageHeight / 2 - fontSize / 2,
73
+ size: fontSize,
74
+ color: (0, pdf_lib_1.rgb)(0.75, 0.75, 0.75),
75
+ rotate: (0, pdf_lib_1.degrees)(-45),
76
+ opacity: 0.5
77
+ });
78
+ }
79
+ pdf.addPage(newPage);
80
+ });
81
+ // 페이지 카운트 업데이트
82
+ __headless_pdf.pageCount += pages.length;
83
+ await page.close();
84
+ headlessPool.release(browser);
85
+ return {
86
+ data: __headless_pdf
87
+ };
88
+ }
89
+ catch (error) {
90
+ if (browser) {
91
+ await browser.close();
92
+ }
93
+ throw error;
94
+ }
95
+ }
96
+ HeadlessPDFCapture.parameterSpec = [
97
+ {
98
+ type: 'string',
99
+ name: 'htmlContent',
100
+ label: 'html-content'
101
+ },
102
+ {
103
+ type: 'select',
104
+ name: 'format',
105
+ label: 'page-format',
106
+ options: [
107
+ { label: 'A4', value: 'A4' },
108
+ { label: 'A3', value: 'A3' },
109
+ { label: 'Letter', value: 'Letter' },
110
+ { label: 'Legal', value: 'Legal' }
111
+ ],
112
+ description: 'Select the paper format for the PDF'
113
+ },
114
+ {
115
+ type: 'string',
116
+ name: 'width',
117
+ label: 'page-width',
118
+ description: 'Specify the width of the page (e.g., "8.5in", "21cm", "600px")'
119
+ },
120
+ {
121
+ type: 'string',
122
+ name: 'height',
123
+ label: 'page-height',
124
+ description: 'Specify the height of the page (e.g., "11in", "29.7cm", "800px")'
125
+ },
126
+ {
127
+ type: 'json',
128
+ name: 'margin',
129
+ label: 'page-margins',
130
+ fields: [
131
+ { type: 'string', name: 'top', label: 'Top Margin', description: 'Top margin (e.g., "1in")' },
132
+ { type: 'string', name: 'right', label: 'Right Margin', description: 'Right margin (e.g., "1in")' },
133
+ { type: 'string', name: 'bottom', label: 'Bottom Margin', description: 'Bottom margin (e.g., "1in")' },
134
+ { type: 'string', name: 'left', label: 'Left Margin', description: 'Left margin (e.g., "1in")' }
135
+ ],
136
+ description: 'Set the margins for the page'
137
+ },
138
+ {
139
+ type: 'number',
140
+ name: 'scale',
141
+ label: 'scale',
142
+ defaultValue: 1,
143
+ description: 'Set the scale of the page content (default is 1)'
144
+ },
145
+ {
146
+ type: 'boolean',
147
+ name: 'printBackground',
148
+ label: 'print-background',
149
+ defaultValue: true,
150
+ description: 'Include background graphics when printing the page'
151
+ },
152
+ {
153
+ type: 'boolean',
154
+ name: 'landscape',
155
+ label: 'landscape',
156
+ defaultValue: false,
157
+ description: 'Print the PDF in landscape orientation'
158
+ },
159
+ {
160
+ type: 'boolean',
161
+ name: 'displayHeaderFooter',
162
+ label: 'display-header/footer',
163
+ defaultValue: false,
164
+ description: 'Display header and footer in the PDF'
165
+ },
166
+ {
167
+ type: 'boolean',
168
+ name: 'preferCSSPageSize',
169
+ label: 'prefer-css-page-size',
170
+ defaultValue: false,
171
+ description: 'Whether to prefer the CSS-defined page size over the given width and height'
172
+ }
173
+ ];
174
+ HeadlessPDFCapture.help = 'integration/task/headless-pdf-capture';
175
+ integration_base_1.TaskRegistry.registerTaskHandler('headless-pdf-capture', HeadlessPDFCapture);
176
+ //# sourceMappingURL=headless-pdf-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless-pdf-capture.js","sourceRoot":"","sources":["../../../server/engine/task/headless-pdf-capture.ts"],"names":[],"mappings":"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","sourcesContent":["import * as ejs from 'ejs'\nimport { PDFDocument, rgb, degrees } from 'pdf-lib'\n\nimport { TaskRegistry } from '@things-factory/integration-base'\nimport { ConnectionManager } from '@things-factory/integration-base'\n\nasync function HeadlessPDFCapture(step, context) {\n var { connection: connectionName, params: stepOptions } = step\n var {\n htmlContent,\n format,\n width,\n height,\n margin,\n scale,\n printBackground,\n landscape,\n displayHeaderFooter,\n headerTemplate,\n footerTemplate,\n preferCSSPageSize\n } = stepOptions || {}\n var { domain, data, __headless_pdf } = context\n\n if (!__headless_pdf) {\n throw new Error('it requires headless-pdf-open to be performed first')\n }\n\n var {\n pdf,\n header: headerTemplateFromContext,\n footer: footerTemplateFromContext,\n watermark,\n pageCount\n } = __headless_pdf\n\n var headlessPool = ConnectionManager.getConnectionInstanceByName(domain, connectionName)\n let browser\n\n try {\n // Puppeteer를 사용하여 브라우저와 페이지 인스턴스를 생성\n browser = await headlessPool.acquire()\n const page = await browser.newPage()\n\n // 설정된 HTML 콘텐츠를 페이지에 설정\n await page.setContent(htmlContent)\n\n // PDF 페이지 생성 옵션 설정\n if (preferCSSPageSize) {\n width = undefined\n height = undefined\n }\n\n const pageOptions = {\n format,\n width,\n height,\n margin,\n scale,\n printBackground,\n landscape,\n displayHeaderFooter,\n headerTemplate: displayHeaderFooter ? headerTemplate : undefined,\n footerTemplate: displayHeaderFooter ? footerTemplate : undefined,\n preferCSSPageSize\n }\n\n // 페이지를 PDF로 변환\n const pageBuffer = await page.pdf(pageOptions)\n\n // PDF-lib을 사용하여 PDF를 로드하고 추가 조작\n const pdfDoc = await PDFDocument.load(pageBuffer)\n const pages = await pdf.copyPages(pdfDoc, pdfDoc.getPageIndices())\n\n pages.forEach((newPage, index) => {\n const currentPageNumber = pageCount + index + 1\n\n // 헤더와 푸터 렌더링 (페이지 번호 및 총 페이지 수 포함)\n if (displayHeaderFooter && (headerTemplateFromContext || footerTemplateFromContext)) {\n const renderedHeader = headerTemplateFromContext\n ? ejs.render(headerTemplateFromContext, {\n ...data,\n pageNumber: currentPageNumber,\n totalPages: pageCount + pages.length\n })\n : ''\n const renderedFooter = footerTemplateFromContext\n ? ejs.render(footerTemplateFromContext, {\n ...data,\n pageNumber: currentPageNumber,\n totalPages: pageCount + pages.length\n })\n : ''\n\n // Header/Footer 그리기\n if (renderedHeader) {\n newPage.drawText(renderedHeader, { x: 50, y: newPage.getHeight() - 30, size: 12, color: rgb(0, 0, 0) })\n }\n if (renderedFooter) {\n newPage.drawText(renderedFooter, { x: 50, y: 30, size: 12, color: rgb(0, 0, 0) })\n }\n }\n\n // 워터마크 추가\n if (watermark) {\n const fontSize = 50\n const pageWidth = newPage.getWidth()\n const pageHeight = newPage.getHeight()\n\n newPage.drawText(watermark, {\n x: pageWidth / 2 - (fontSize * watermark.length) / 4,\n y: pageHeight / 2 - fontSize / 2,\n size: fontSize,\n color: rgb(0.75, 0.75, 0.75),\n rotate: degrees(-45),\n opacity: 0.5\n })\n }\n\n pdf.addPage(newPage)\n })\n\n // 페이지 카운트 업데이트\n __headless_pdf.pageCount += pages.length\n\n await page.close()\n headlessPool.release(browser)\n\n return {\n data: __headless_pdf\n }\n } catch (error) {\n if (browser) {\n await browser.close()\n }\n\n throw error\n }\n}\n\nHeadlessPDFCapture.parameterSpec = [\n {\n type: 'string',\n name: 'htmlContent',\n label: 'html-content'\n },\n {\n type: 'select',\n name: 'format',\n label: 'page-format',\n options: [\n { label: 'A4', value: 'A4' },\n { label: 'A3', value: 'A3' },\n { label: 'Letter', value: 'Letter' },\n { label: 'Legal', value: 'Legal' }\n ],\n description: 'Select the paper format for the PDF'\n },\n {\n type: 'string',\n name: 'width',\n label: 'page-width',\n description: 'Specify the width of the page (e.g., \"8.5in\", \"21cm\", \"600px\")'\n },\n {\n type: 'string',\n name: 'height',\n label: 'page-height',\n description: 'Specify the height of the page (e.g., \"11in\", \"29.7cm\", \"800px\")'\n },\n {\n type: 'json',\n name: 'margin',\n label: 'page-margins',\n fields: [\n { type: 'string', name: 'top', label: 'Top Margin', description: 'Top margin (e.g., \"1in\")' },\n { type: 'string', name: 'right', label: 'Right Margin', description: 'Right margin (e.g., \"1in\")' },\n { type: 'string', name: 'bottom', label: 'Bottom Margin', description: 'Bottom margin (e.g., \"1in\")' },\n { type: 'string', name: 'left', label: 'Left Margin', description: 'Left margin (e.g., \"1in\")' }\n ],\n description: 'Set the margins for the page'\n },\n {\n type: 'number',\n name: 'scale',\n label: 'scale',\n defaultValue: 1,\n description: 'Set the scale of the page content (default is 1)'\n },\n {\n type: 'boolean',\n name: 'printBackground',\n label: 'print-background',\n defaultValue: true,\n description: 'Include background graphics when printing the page'\n },\n {\n type: 'boolean',\n name: 'landscape',\n label: 'landscape',\n defaultValue: false,\n description: 'Print the PDF in landscape orientation'\n },\n {\n type: 'boolean',\n name: 'displayHeaderFooter',\n label: 'display-header/footer',\n defaultValue: false,\n description: 'Display header and footer in the PDF'\n },\n {\n type: 'boolean',\n name: 'preferCSSPageSize',\n label: 'prefer-css-page-size',\n defaultValue: false,\n description: 'Whether to prefer the CSS-defined page size over the given width and height'\n }\n]\n\nHeadlessPDFCapture.help = 'integration/task/headless-pdf-capture'\n\nTaskRegistry.registerTaskHandler('headless-pdf-capture', HeadlessPDFCapture)\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const pdf_lib_1 = require("pdf-lib");
4
+ const integration_base_1 = require("@things-factory/integration-base");
5
+ async function HeadlessPDFOpen(step, context) {
6
+ var { connection: connectionName, params: stepOptions } = step;
7
+ var { coverPage, lastPage, header, footer, watermark, fileName // 추가된 파일 이름
8
+ } = stepOptions || {};
9
+ // var { domain, data, variables } = context
10
+ // var headlessPool = ConnectionManager.getConnectionInstanceByName(domain, connectionName)
11
+ const pdf = await pdf_lib_1.PDFDocument.create();
12
+ const data = {
13
+ pdf,
14
+ coverPage,
15
+ lastPage,
16
+ header,
17
+ footer,
18
+ watermark,
19
+ fileName, // 파일 이름을 context.data에 저장
20
+ pageCount: 0 // 페이지 카운트를 초기화하여 context에 저장
21
+ };
22
+ context.__headless_pdf = data;
23
+ return {
24
+ data
25
+ };
26
+ }
27
+ HeadlessPDFOpen.parameterSpec = [
28
+ {
29
+ type: 'string',
30
+ name: 'coverPage',
31
+ label: 'pdf-cover-page'
32
+ },
33
+ {
34
+ type: 'string',
35
+ name: 'lastPage',
36
+ label: 'pdf-last-page'
37
+ },
38
+ {
39
+ type: 'string',
40
+ name: 'header',
41
+ label: 'header' // header template
42
+ },
43
+ {
44
+ type: 'string',
45
+ name: 'footer',
46
+ label: 'footer' // footer template
47
+ },
48
+ {
49
+ type: 'string',
50
+ name: 'watermark',
51
+ label: 'watermark' // watermark
52
+ },
53
+ {
54
+ type: 'string',
55
+ name: 'fileName',
56
+ label: 'filename' // 파일 이름 지정
57
+ }
58
+ ];
59
+ HeadlessPDFOpen.help = 'integration/task/headless-open';
60
+ integration_base_1.TaskRegistry.registerTaskHandler('headless-open', HeadlessPDFOpen);
61
+ //# sourceMappingURL=headless-pdf-open.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless-pdf-open.js","sourceRoot":"","sources":["../../../server/engine/task/headless-pdf-open.ts"],"names":[],"mappings":";;AACA,qCAAqC;AAErC,uEAA+D;AAG/D,KAAK,UAAU,eAAe,CAAC,IAAI,EAAE,OAAO;IAC1C,IAAI,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAA;IAC9D,IAAI,EACF,SAAS,EACT,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,EACT,QAAQ,CAAC,YAAY;MACtB,GAAG,WAAW,IAAI,EAAE,CAAA;IAErB,4CAA4C;IAC5C,2FAA2F;IAE3F,MAAM,GAAG,GAAG,MAAM,qBAAW,CAAC,MAAM,EAAE,CAAA;IAEtC,MAAM,IAAI,GAAG;QACX,GAAG;QACH,SAAS;QACT,QAAQ;QACR,MAAM;QACN,MAAM;QACN,SAAS;QACT,QAAQ,EAAE,0BAA0B;QACpC,SAAS,EAAE,CAAC,CAAC,6BAA6B;KAC3C,CAAA;IAED,OAAO,CAAC,cAAc,GAAG,IAAI,CAAA;IAE7B,OAAO;QACL,IAAI;KACL,CAAA;AACH,CAAC;AAED,eAAe,CAAC,aAAa,GAAG;IAC9B;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,gBAAgB;KACxB;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,eAAe;KACvB;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,QAAQ,CAAC,kBAAkB;KACnC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,QAAQ,CAAC,kBAAkB;KACnC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,WAAW,CAAC,YAAY;KAChC;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,UAAU,CAAC,WAAW;KAC9B;CACF,CAAA;AACD,eAAe,CAAC,IAAI,GAAG,gCAAgC,CAAA;AAEvD,+BAAY,CAAC,mBAAmB,CAAC,eAAe,EAAE,eAAe,CAAC,CAAA","sourcesContent":["import * as ejs from 'ejs'\nimport { PDFDocument } from 'pdf-lib'\n\nimport { TaskRegistry } from '@things-factory/integration-base'\nimport { ConnectionManager } from '@things-factory/integration-base'\n\nasync function HeadlessPDFOpen(step, context) {\n var { connection: connectionName, params: stepOptions } = step\n var {\n coverPage,\n lastPage,\n header,\n footer,\n watermark,\n fileName // 추가된 파일 이름\n } = stepOptions || {}\n\n // var { domain, data, variables } = context\n // var headlessPool = ConnectionManager.getConnectionInstanceByName(domain, connectionName)\n\n const pdf = await PDFDocument.create()\n\n const data = {\n pdf,\n coverPage,\n lastPage,\n header,\n footer,\n watermark,\n fileName, // 파일 이름을 context.data에 저장\n pageCount: 0 // 페이지 카운트를 초기화하여 context에 저장\n }\n\n context.__headless_pdf = data\n\n return {\n data\n }\n}\n\nHeadlessPDFOpen.parameterSpec = [\n {\n type: 'string',\n name: 'coverPage',\n label: 'pdf-cover-page'\n },\n {\n type: 'string',\n name: 'lastPage',\n label: 'pdf-last-page'\n },\n {\n type: 'string',\n name: 'header',\n label: 'header' // header template\n },\n {\n type: 'string',\n name: 'footer',\n label: 'footer' // footer template\n },\n {\n type: 'string',\n name: 'watermark',\n label: 'watermark' // watermark\n },\n {\n type: 'string',\n name: 'fileName',\n label: 'filename' // 파일 이름 지정\n }\n]\nHeadlessPDFOpen.help = 'integration/task/headless-open'\n\nTaskRegistry.registerTaskHandler('headless-open', HeadlessPDFOpen)\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const fs = tslib_1.__importStar(require("fs"));
5
+ const path = tslib_1.__importStar(require("path"));
6
+ const pdf_lib_1 = require("pdf-lib");
7
+ const integration_base_1 = require("@things-factory/integration-base");
8
+ async function HeadlessPDFSave(step, context) {
9
+ var { params: stepOptions } = step;
10
+ var { outputPath } = stepOptions || {};
11
+ var { pdf, coverPage, lastPage, header, footer, watermark } = context.data;
12
+ // 파일 이름이 설정되지 않았을 경우 기본 파일 이름 생성
13
+ const finalFileName = context.data.fileName || `document-${Date.now()}.pdf`;
14
+ const savePath = path.join(outputPath || '/path/to/default/storage', finalFileName);
15
+ // PDF 문서에 coverPage 및 lastPage 추가
16
+ if (coverPage) {
17
+ const coverPageDoc = await pdf_lib_1.PDFDocument.load(coverPage);
18
+ const [cover] = await pdf.copyPages(coverPageDoc, [0]);
19
+ // 커버 페이지에 워터마크 추가
20
+ if (watermark) {
21
+ const fontSize = 50;
22
+ const pageWidth = cover.getWidth();
23
+ const pageHeight = cover.getHeight();
24
+ cover.drawText(watermark, {
25
+ x: pageWidth / 2 - (fontSize * watermark.length) / 4,
26
+ y: pageHeight / 2 - fontSize / 2,
27
+ size: fontSize,
28
+ color: (0, pdf_lib_1.rgb)(0.75, 0.75, 0.75),
29
+ rotate: (0, pdf_lib_1.degrees)(-45),
30
+ opacity: 0.5
31
+ });
32
+ }
33
+ pdf.insertPage(0, cover);
34
+ }
35
+ if (lastPage) {
36
+ const lastPageDoc = await pdf_lib_1.PDFDocument.load(lastPage);
37
+ const [last] = await pdf.copyPages(lastPageDoc, [0]);
38
+ // 마지막 페이지에 워터마크 추가
39
+ if (watermark) {
40
+ const fontSize = 50;
41
+ const pageWidth = last.getWidth();
42
+ const pageHeight = last.getHeight();
43
+ last.drawText(watermark, {
44
+ x: pageWidth / 2 - (fontSize * watermark.length) / 4,
45
+ y: pageHeight / 2 - fontSize / 2,
46
+ size: fontSize,
47
+ color: (0, pdf_lib_1.rgb)(0.75, 0.75, 0.75),
48
+ rotate: (0, pdf_lib_1.degrees)(-45),
49
+ opacity: 0.5
50
+ });
51
+ }
52
+ pdf.addPage(last);
53
+ }
54
+ // PDF 파일로 저장
55
+ const pdfBytes = await pdf.save();
56
+ fs.writeFileSync(savePath, pdfBytes);
57
+ return {
58
+ data: {
59
+ link: savePath // 저장된 PDF 파일의 경로를 반환
60
+ }
61
+ };
62
+ }
63
+ HeadlessPDFSave.parameterSpec = [
64
+ {
65
+ type: 'string',
66
+ name: 'outputPath',
67
+ label: 'output-path' // PDF를 저장할 경로
68
+ }
69
+ ];
70
+ HeadlessPDFSave.help = 'integration/task/headless-pdf-save';
71
+ integration_base_1.TaskRegistry.registerTaskHandler('headless-pdf-save', HeadlessPDFSave);
72
+ //# sourceMappingURL=headless-pdf-save.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless-pdf-save.js","sourceRoot":"","sources":["../../../server/engine/task/headless-pdf-save.ts"],"names":[],"mappings":";;;AAAA,+CAAwB;AACxB,mDAA4B;AAC5B,qCAAmD;AAEnD,uEAA+D;AAE/D,KAAK,UAAU,eAAe,CAAC,IAAI,EAAE,OAAO;IAC1C,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAA;IAClC,IAAI,EAAE,UAAU,EAAE,GAAG,WAAW,IAAI,EAAE,CAAA;IACtC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAA;IAE1E,iCAAiC;IACjC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,IAAI,YAAY,IAAI,CAAC,GAAG,EAAE,MAAM,CAAA;IAC3E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,0BAA0B,EAAE,aAAa,CAAC,CAAA;IAEnF,kCAAkC;IAClC,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,YAAY,GAAG,MAAM,qBAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACtD,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QAEtD,kBAAkB;QAClB,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,QAAQ,GAAG,EAAE,CAAA;YACnB,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAA;YAClC,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,EAAE,CAAA;YAEpC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE;gBACxB,CAAC,EAAE,SAAS,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC;gBACpD,CAAC,EAAE,UAAU,GAAG,CAAC,GAAG,QAAQ,GAAG,CAAC;gBAChC,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,IAAA,aAAG,EAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;gBAC5B,MAAM,EAAE,IAAA,iBAAO,EAAC,CAAC,EAAE,CAAC;gBACpB,OAAO,EAAE,GAAG;aACb,CAAC,CAAA;QACJ,CAAC;QAED,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,WAAW,GAAG,MAAM,qBAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACpD,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QAEpD,mBAAmB;QACnB,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,QAAQ,GAAG,EAAE,CAAA;YACnB,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;YACjC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,CAAA;YAEnC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE;gBACvB,CAAC,EAAE,SAAS,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC;gBACpD,CAAC,EAAE,UAAU,GAAG,CAAC,GAAG,QAAQ,GAAG,CAAC;gBAChC,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,IAAA,aAAG,EAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;gBAC5B,MAAM,EAAE,IAAA,iBAAO,EAAC,CAAC,EAAE,CAAC;gBACpB,OAAO,EAAE,GAAG;aACb,CAAC,CAAA;QACJ,CAAC;QAED,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACnB,CAAC;IAED,aAAa;IACb,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;IACjC,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAEpC,OAAO;QACL,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ,CAAC,qBAAqB;SACrC;KACF,CAAA;AACH,CAAC;AAED,eAAe,CAAC,aAAa,GAAG;IAC9B;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,aAAa,CAAC,cAAc;KACpC;CACF,CAAA;AAED,eAAe,CAAC,IAAI,GAAG,oCAAoC,CAAA;AAE3D,+BAAY,CAAC,mBAAmB,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAA","sourcesContent":["import * as fs from 'fs'\nimport * as path from 'path'\nimport { PDFDocument, rgb, degrees } from 'pdf-lib'\n\nimport { TaskRegistry } from '@things-factory/integration-base'\n\nasync function HeadlessPDFSave(step, context) {\n var { params: stepOptions } = step\n var { outputPath } = stepOptions || {}\n var { pdf, coverPage, lastPage, header, footer, watermark } = context.data\n\n // 파일 이름이 설정되지 않았을 경우 기본 파일 이름 생성\n const finalFileName = context.data.fileName || `document-${Date.now()}.pdf`\n const savePath = path.join(outputPath || '/path/to/default/storage', finalFileName)\n\n // PDF 문서에 coverPage 및 lastPage 추가\n if (coverPage) {\n const coverPageDoc = await PDFDocument.load(coverPage)\n const [cover] = await pdf.copyPages(coverPageDoc, [0])\n\n // 커버 페이지에 워터마크 추가\n if (watermark) {\n const fontSize = 50\n const pageWidth = cover.getWidth()\n const pageHeight = cover.getHeight()\n\n cover.drawText(watermark, {\n x: pageWidth / 2 - (fontSize * watermark.length) / 4,\n y: pageHeight / 2 - fontSize / 2,\n size: fontSize,\n color: rgb(0.75, 0.75, 0.75),\n rotate: degrees(-45),\n opacity: 0.5\n })\n }\n\n pdf.insertPage(0, cover)\n }\n\n if (lastPage) {\n const lastPageDoc = await PDFDocument.load(lastPage)\n const [last] = await pdf.copyPages(lastPageDoc, [0])\n\n // 마지막 페이지에 워터마크 추가\n if (watermark) {\n const fontSize = 50\n const pageWidth = last.getWidth()\n const pageHeight = last.getHeight()\n\n last.drawText(watermark, {\n x: pageWidth / 2 - (fontSize * watermark.length) / 4,\n y: pageHeight / 2 - fontSize / 2,\n size: fontSize,\n color: rgb(0.75, 0.75, 0.75),\n rotate: degrees(-45),\n opacity: 0.5\n })\n }\n\n pdf.addPage(last)\n }\n\n // PDF 파일로 저장\n const pdfBytes = await pdf.save()\n fs.writeFileSync(savePath, pdfBytes)\n\n return {\n data: {\n link: savePath // 저장된 PDF 파일의 경로를 반환\n }\n }\n}\n\nHeadlessPDFSave.parameterSpec = [\n {\n type: 'string',\n name: 'outputPath',\n label: 'output-path' // PDF를 저장할 경로\n }\n]\n\nHeadlessPDFSave.help = 'integration/task/headless-pdf-save'\n\nTaskRegistry.registerTaskHandler('headless-pdf-save', HeadlessPDFSave)\n"]}
@@ -0,0 +1,3 @@
1
+ import './headless-pdf-capture';
2
+ import './headless-pdf-open';
3
+ import './headless-pdf-save';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ require("./headless-pdf-capture");
4
+ require("./headless-pdf-open");
5
+ require("./headless-pdf-save");
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/engine/task/index.ts"],"names":[],"mappings":";;AAAA,kCAA+B;AAC/B,+BAA4B;AAC5B,+BAA4B","sourcesContent":["import './headless-pdf-capture'\nimport './headless-pdf-open'\nimport './headless-pdf-save'\n"]}
@@ -0,0 +1 @@
1
+ import './engine';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ require("./engine");
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;AAAA,oBAAiB","sourcesContent":["import './engine'\n"]}