@things-factory/board-service 10.0.0-beta.51 → 10.0.0-beta.53

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.
@@ -0,0 +1,18 @@
1
+ export interface HeadlessRenderOptions {
2
+ id?: string;
3
+ model?: any;
4
+ data?: any;
5
+ width?: number;
6
+ height?: number;
7
+ options?: any;
8
+ context?: any;
9
+ draft?: boolean;
10
+ /** true 이면 thumbnail 크기(400x300)로 축소 */
11
+ isThumbnail?: boolean;
12
+ }
13
+ /**
14
+ * headless 브라우저 페이지를 준비하고 renderFn 을 실행한 결과를 반환한다.
15
+ *
16
+ * 공통 처리: pool acquire → headlessModel → fonts → viewport → request intercept → goto → data 주입 → renderFn → cleanup
17
+ */
18
+ export declare function withHeadlessPage<T>({ id, model, data, width: w, height: h, options, context, draft, isThumbnail }: HeadlessRenderOptions, renderFn: (page: any) => Promise<T>): Promise<T | null>;
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withHeadlessPage = withHeadlessPage;
4
+ const fonts_js_1 = require("./fonts.js");
5
+ const headless_pool_for_board_js_1 = require("./headless-pool-for-board.js");
6
+ const headless_model_js_1 = require("./headless-model.js");
7
+ const protocol = 'http';
8
+ const host = 'localhost';
9
+ const path = '/internal-board-service-view';
10
+ /** headless page 에 console/error 이벤트 핸들러를 일괄 등록한다. */
11
+ function attachPageListeners(page) {
12
+ page.on('console', async (msg) => {
13
+ const args = await Promise.all(msg.args().map(arg => arg.jsonValue().catch(() => undefined)));
14
+ if (args.some(a => a !== undefined)) {
15
+ console.log(`[headless ${msg.type()}]`, ...args.filter(a => a !== undefined));
16
+ }
17
+ else {
18
+ const text = msg.text();
19
+ if (text)
20
+ console.log(`[headless ${msg.type()}]`, text);
21
+ }
22
+ });
23
+ page.on('pageerror', error => {
24
+ console.log(`[headless pageerror] ${error.message}`);
25
+ console.log(error.stack);
26
+ });
27
+ page.on('error', error => {
28
+ console.log(`[headless fault] ${error}`);
29
+ console.log(error.stack);
30
+ });
31
+ page.on('requestfailed', request => {
32
+ console.log('Request failed:', request.url());
33
+ });
34
+ }
35
+ /**
36
+ * headless 브라우저 페이지를 준비하고 renderFn 을 실행한 결과를 반환한다.
37
+ *
38
+ * 공통 처리: pool acquire → headlessModel → fonts → viewport → request intercept → goto → data 주입 → renderFn → cleanup
39
+ */
40
+ async function withHeadlessPage({ id = '', model = null, data = null, width: w = 0, height: h = 0, options = {}, context = {}, draft = false, isThumbnail = false }, renderFn) {
41
+ const browser = (await (0, headless_pool_for_board_js_1.getHeadlessPool)().acquire());
42
+ if (!browser)
43
+ return null;
44
+ const { domain, user } = context.state;
45
+ var { model: resolvedModel, base } = await (0, headless_model_js_1.headlessModel)({ domain, id, model }, draft);
46
+ const [fontsToUse, fontStyles] = await (0, fonts_js_1.fonts)(domain);
47
+ resolvedModel.fonts = fontsToUse;
48
+ resolvedModel.fontStyles = fontStyles;
49
+ let { width, height } = resolvedModel;
50
+ if (isThumbnail) {
51
+ const ratio = Math.min(400 / width, 300 / height);
52
+ width = width * ratio;
53
+ height = height * ratio;
54
+ }
55
+ else if (w || h) {
56
+ const ratio = Math.min((w || width) / width, (h || height) / height);
57
+ width = width * ratio;
58
+ height = height * ratio;
59
+ }
60
+ width = Math.floor(w || Number(width));
61
+ height = Math.floor(h || Number(height));
62
+ const port = process.env.PORT ? `:${process.env.PORT}` : '';
63
+ const url = `${protocol}://${host}${port}${path}`;
64
+ const page = await browser.newPage();
65
+ let result = null;
66
+ try {
67
+ await page.setViewport({ width, height });
68
+ await page.setRequestInterception(true);
69
+ await page.setDefaultTimeout(10000);
70
+ attachPageListeners(page);
71
+ const token = await user?.sign();
72
+ page.on('request', request => {
73
+ if (request.url() === url) {
74
+ request.continue({
75
+ method: 'POST',
76
+ headers: {
77
+ 'Content-Type': 'application/json',
78
+ 'x-things-factory-domain': domain?.subdomain,
79
+ Authorization: 'Bearer ' + token
80
+ },
81
+ postData: JSON.stringify({ model: resolvedModel, base })
82
+ });
83
+ }
84
+ else if (request.url().startsWith(`${protocol}://${host}${port}`)) {
85
+ request.continue({
86
+ headers: {
87
+ ...request.headers(),
88
+ 'x-things-factory-domain': domain?.subdomain,
89
+ Authorization: 'Bearer ' + token
90
+ }
91
+ });
92
+ }
93
+ else {
94
+ request.continue();
95
+ }
96
+ });
97
+ await page.goto(url);
98
+ await page.evaluate(async (data) => {
99
+ if (data) {
100
+ // @ts-ignore
101
+ s.data = data;
102
+ }
103
+ return new Promise(resolve => {
104
+ // @ts-ignore
105
+ requestAnimationFrame(() => resolve());
106
+ });
107
+ }, data);
108
+ result = await renderFn(page);
109
+ }
110
+ catch (error) {
111
+ console.log(error);
112
+ }
113
+ finally {
114
+ await page.close();
115
+ (0, headless_pool_for_board_js_1.getHeadlessPool)().release(browser);
116
+ }
117
+ return result;
118
+ }
119
+ //# sourceMappingURL=headless-render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless-render.js","sourceRoot":"","sources":["../../server/controllers/headless-render.ts"],"names":[],"mappings":"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","sourcesContent":["import { fonts } from './fonts.js'\nimport { getHeadlessPool } from './headless-pool-for-board.js'\nimport { headlessModel } from './headless-model.js'\n\nconst protocol = 'http'\nconst host = 'localhost'\nconst path = '/internal-board-service-view'\n\n/** headless page 에 console/error 이벤트 핸들러를 일괄 등록한다. */\nfunction attachPageListeners(page: any) {\n page.on('console', async msg => {\n const args = await Promise.all(msg.args().map(arg => arg.jsonValue().catch(() => undefined)))\n\n if (args.some(a => a !== undefined)) {\n console.log(`[headless ${msg.type()}]`, ...args.filter(a => a !== undefined))\n } else {\n const text = msg.text()\n if (text) console.log(`[headless ${msg.type()}]`, text)\n }\n })\n\n page.on('pageerror', error => {\n console.log(`[headless pageerror] ${error.message}`)\n console.log(error.stack)\n })\n\n page.on('error', error => {\n console.log(`[headless fault] ${error}`)\n console.log(error.stack)\n })\n\n page.on('requestfailed', request => {\n console.log('Request failed:', request.url())\n })\n}\n\nexport interface HeadlessRenderOptions {\n id?: string\n model?: any\n data?: any\n width?: number\n height?: number\n options?: any\n context?: any\n draft?: boolean\n /** true 이면 thumbnail 크기(400x300)로 축소 */\n isThumbnail?: boolean\n}\n\n/**\n * headless 브라우저 페이지를 준비하고 renderFn 을 실행한 결과를 반환한다.\n *\n * 공통 처리: pool acquire → headlessModel → fonts → viewport → request intercept → goto → data 주입 → renderFn → cleanup\n */\nexport async function withHeadlessPage<T>(\n {\n id = '',\n model = null,\n data = null,\n width: w = 0,\n height: h = 0,\n options = {} as any,\n context = {} as any,\n draft = false,\n isThumbnail = false\n }: HeadlessRenderOptions,\n renderFn: (page: any) => Promise<T>\n): Promise<T | null> {\n const browser = (await getHeadlessPool().acquire()) as any\n if (!browser) return null\n\n const { domain, user } = context.state\n\n var { model: resolvedModel, base } = await headlessModel({ domain, id, model }, draft)\n const [fontsToUse, fontStyles] = await fonts(domain)\n\n resolvedModel.fonts = fontsToUse\n resolvedModel.fontStyles = fontStyles\n\n let { width, height } = resolvedModel\n\n if (isThumbnail) {\n const ratio = Math.min(400 / width, 300 / height)\n width = width * ratio\n height = height * ratio\n } else if (w || h) {\n const ratio = Math.min((w || width) / width, (h || height) / height)\n width = width * ratio\n height = height * ratio\n }\n\n width = Math.floor(w || Number(width))\n height = Math.floor(h || Number(height))\n\n const port = process.env.PORT ? `:${process.env.PORT}` : ''\n const url = `${protocol}://${host}${port}${path}`\n const page = await browser.newPage()\n\n let result: T | null = null\n\n try {\n await page.setViewport({ width, height })\n await page.setRequestInterception(true)\n await page.setDefaultTimeout(10000)\n\n attachPageListeners(page)\n\n const token = await user?.sign()\n\n page.on('request', request => {\n if (request.url() === url) {\n request.continue({\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-things-factory-domain': domain?.subdomain,\n Authorization: 'Bearer ' + token\n },\n postData: JSON.stringify({ model: resolvedModel, base })\n })\n } else if (request.url().startsWith(`${protocol}://${host}${port}`)) {\n request.continue({\n headers: {\n ...request.headers(),\n 'x-things-factory-domain': domain?.subdomain,\n Authorization: 'Bearer ' + token\n }\n })\n } else {\n request.continue()\n }\n })\n\n await page.goto(url)\n\n await page.evaluate(async data => {\n if (data) {\n // @ts-ignore\n s.data = data\n }\n return new Promise(resolve => {\n // @ts-ignore\n requestAnimationFrame(() => resolve())\n })\n }, data)\n\n result = await renderFn(page)\n } catch (error) {\n console.log(error)\n } finally {\n await page.close()\n getHeadlessPool().release(browser)\n }\n\n return result\n}\n"]}
@@ -9,7 +9,7 @@ export declare const BoardFunc: {
9
9
  context: any;
10
10
  draft?: boolean;
11
11
  }) => Promise<string>;
12
- boardToPdf: ({ id, model, data, width: w, height: h, options, context }?: {
12
+ boardToPdf: ({ id, model, data, width, height, options, context }?: {
13
13
  id?: string;
14
14
  model?: any;
15
15
  data?: any;
@@ -17,7 +17,7 @@ export declare const BoardFunc: {
17
17
  height?: number;
18
18
  options?: any;
19
19
  context?: any;
20
- }) => Promise<any>;
20
+ }) => Promise<unknown>;
21
21
  headlessModel: (target: any, draft?: boolean) => Promise<{
22
22
  base: string;
23
23
  model: any;
@@ -1,4 +1,4 @@
1
- export declare const pdf: ({ id, model, data, width: w, height: h, options, context }?: {
1
+ export declare const pdf: ({ id, model, data, width, height, options, context }?: {
2
2
  id?: string;
3
3
  model?: any;
4
4
  data?: any;
@@ -6,4 +6,4 @@ export declare const pdf: ({ id, model, data, width: w, height: h, options, cont
6
6
  height?: number;
7
7
  options?: any;
8
8
  context?: any;
9
- }) => Promise<any>;
9
+ }) => Promise<unknown>;
@@ -1,118 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.pdf = void 0;
4
- const fonts_js_1 = require("./fonts.js");
5
- const headless_pool_for_board_js_1 = require("./headless-pool-for-board.js");
6
- const headless_model_js_1 = require("./headless-model.js");
7
- const protocol = 'http';
8
- const host = 'localhost';
9
- const path = '/internal-board-service-view';
10
- const pdf = async ({ id = '', model = null, data = null, width: w = 0, height: h = 0, options = {}, context = {} } = {}) => {
11
- const browser = (await (0, headless_pool_for_board_js_1.getHeadlessPool)().acquire());
12
- if (!browser) {
13
- return;
14
- }
15
- const { domain, user } = context.state;
16
- var { model, base } = await (0, headless_model_js_1.headlessModel)({ domain, id, model });
17
- const [fontsToUse, fontStyles] = await (0, fonts_js_1.fonts)(domain);
18
- model.fonts = fontsToUse;
19
- model.fontStyles = fontStyles;
20
- let { width, height } = model;
21
- width = Number(width);
22
- height = Number(height);
23
- if (!w) {
24
- w = width;
25
- }
26
- if (!h) {
27
- h = height;
28
- }
29
- let ratio = Math.min(w / width, h / height);
30
- width = Math.floor(width * ratio);
31
- height = Math.floor(height * ratio);
32
- const port = process.env.PORT ? `:${process.env.PORT}` : '';
33
- const url = `${protocol}://${host}${port}${path}`;
34
- const page = await browser.newPage();
35
- var result = null;
36
- try {
37
- /* @remember-me width, height should be a integer */
38
- await page.setViewport({ width, height });
39
- await page.setRequestInterception(true);
40
- page.on('console', async (msg) => {
41
- const args = await Promise.all(msg.args().map(arg => arg.jsonValue().catch(() => undefined)));
42
- if (args.some(a => a !== undefined)) {
43
- console.log(`[headless ${msg.type()}]`, ...args.filter(a => a !== undefined));
44
- }
45
- else {
46
- const text = msg.text();
47
- if (text)
48
- console.log(`[headless ${msg.type()}]`, text);
49
- }
50
- });
51
- page.on('pageerror', error => {
52
- console.log(`[headless pageerror] ${error.message}`);
53
- console.log(error.stack);
54
- });
55
- page.on('error', error => {
56
- console.log(`[headless fault] ${error}`);
57
- console.log(error.stack);
58
- });
59
- page.on('requestfailed', request => {
60
- console.log('Request failed:', request.url());
61
- });
62
- const token = await user?.sign(); // TODO improve performance
63
- page.on('request', request => {
64
- if (request.url() === url) {
65
- request.continue({
66
- method: 'POST',
67
- headers: {
68
- 'Content-Type': 'application/json',
69
- 'x-things-factory-domain': domain?.subdomain,
70
- Authorization: 'Bearer ' + token
71
- },
72
- postData: JSON.stringify({
73
- model,
74
- base
75
- })
76
- });
77
- }
78
- else if (request.url().startsWith(`${protocol}://${host}${port}`)) {
79
- request.continue({
80
- headers: {
81
- ...request.headers(),
82
- 'x-things-factory-domain': domain?.subdomain,
83
- Authorization: 'Bearer ' + token
84
- }
85
- });
86
- }
87
- else {
88
- request.continue();
89
- }
90
- });
91
- await page.goto(url);
92
- await page.evaluate(async (data) => {
93
- if (data) {
94
- // @ts-ignore
95
- s.data = data;
96
- }
97
- // data 주입 후 강제 지연시킴.
98
- return new Promise(resolve => {
99
- // @ts-ignore
100
- requestAnimationFrame(() => resolve());
101
- });
102
- }, data);
103
- result = await page.pdf({
104
- format: 'A4',
105
- ...options
106
- });
107
- }
108
- catch (error) {
109
- console.log(error);
110
- }
111
- finally {
112
- await page.close();
113
- (0, headless_pool_for_board_js_1.getHeadlessPool)().release(browser);
114
- }
115
- return result;
4
+ const headless_render_js_1 = require("./headless-render.js");
5
+ const pdf = async ({ id = '', model = null, data = null, width = 0, height = 0, options = {}, context = {} } = {}) => {
6
+ return (0, headless_render_js_1.withHeadlessPage)({ id, model, data, width, height, options, context }, page => page.pdf({ format: 'A4', ...options }));
116
7
  };
117
8
  exports.pdf = pdf;
118
9
  //# sourceMappingURL=pdf.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../server/controllers/pdf.ts"],"names":[],"mappings":"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","sourcesContent":["import { fonts } from './fonts.js'\nimport { getHeadlessPool } from './headless-pool-for-board.js'\nimport { headlessModel } from './headless-model.js'\n\nconst protocol = 'http'\nconst host = 'localhost'\nconst path = '/internal-board-service-view'\n\nexport const pdf = async ({\n id = '',\n model = null,\n data = null,\n width: w = 0,\n height: h = 0,\n options = {} as any,\n context = {} as any\n} = {}) => {\n const browser = (await getHeadlessPool().acquire()) as any\n\n if (!browser) {\n return\n }\n\n const { domain, user } = context.state\n\n var { model, base } = await headlessModel({ domain, id, model })\n const [fontsToUse, fontStyles] = await fonts(domain)\n\n model.fonts = fontsToUse\n model.fontStyles = fontStyles\n\n let { width, height } = model\n\n width = Number(width)\n height = Number(height)\n\n if (!w) {\n w = width\n }\n if (!h) {\n h = height\n }\n\n let ratio = Math.min(w / width, h / height)\n\n width = Math.floor(width * ratio)\n height = Math.floor(height * ratio)\n\n const port = process.env.PORT ? `:${process.env.PORT}` : ''\n const url = `${protocol}://${host}${port}${path}`\n const page = await browser.newPage()\n\n var result = null as any\n\n try {\n /* @remember-me width, height should be a integer */\n await page.setViewport({ width, height })\n await page.setRequestInterception(true)\n\n page.on('console', async msg => {\n const args = await Promise.all(msg.args().map(arg => arg.jsonValue().catch(() => undefined)))\n\n if (args.some(a => a !== undefined)) {\n console.log(`[headless ${msg.type()}]`, ...args.filter(a => a !== undefined))\n } else {\n const text = msg.text()\n if (text) console.log(`[headless ${msg.type()}]`, text)\n }\n })\n\n page.on('pageerror', error => {\n console.log(`[headless pageerror] ${error.message}`)\n console.log(error.stack)\n })\n\n page.on('error', error => {\n console.log(`[headless fault] ${error}`)\n console.log(error.stack)\n })\n\n page.on('requestfailed', request => {\n console.log('Request failed:', request.url())\n })\n\n const token = await user?.sign() // TODO improve performance\n\n page.on('request', request => {\n if (request.url() === url) {\n request.continue({\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-things-factory-domain': domain?.subdomain,\n Authorization: 'Bearer ' + token\n },\n postData: JSON.stringify({\n model,\n base\n })\n })\n } else if (request.url().startsWith(`${protocol}://${host}${port}`)) {\n request.continue({\n headers: {\n ...request.headers(),\n 'x-things-factory-domain': domain?.subdomain,\n Authorization: 'Bearer ' + token\n }\n })\n } else {\n request.continue()\n }\n })\n\n await page.goto(url)\n\n await page.evaluate(async data => {\n if (data) {\n // @ts-ignore\n s.data = data\n }\n\n // data 주입 후 강제 지연시킴.\n return new Promise(resolve => {\n // @ts-ignore\n requestAnimationFrame(() => resolve())\n })\n }, data)\n\n result = await page.pdf({\n format: 'A4',\n ...options\n })\n } catch (error) {\n console.log(error)\n } finally {\n await page.close()\n getHeadlessPool().release(browser)\n }\n\n return result\n}\n"]}
1
+ {"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../server/controllers/pdf.ts"],"names":[],"mappings":";;;AAAA,6DAAuD;AAEhD,MAAM,GAAG,GAAG,KAAK,EAAE,EACxB,EAAE,GAAG,EAAE,EACP,KAAK,GAAG,IAAI,EACZ,IAAI,GAAG,IAAI,EACX,KAAK,GAAG,CAAC,EACT,MAAM,GAAG,CAAC,EACV,OAAO,GAAG,EAAS,EACnB,OAAO,GAAG,EAAS,KACjB,EAAE,EAAE,EAAE;IACR,OAAO,IAAA,qCAAgB,EACrB,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,EACpD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC,CAC/C,CAAA;AACH,CAAC,CAAA;AAbY,QAAA,GAAG,OAaf","sourcesContent":["import { withHeadlessPage } from './headless-render.js'\n\nexport const pdf = async ({\n id = '',\n model = null,\n data = null,\n width = 0,\n height = 0,\n options = {} as any,\n context = {} as any\n} = {}) => {\n return withHeadlessPage(\n { id, model, data, width, height, options, context },\n page => page.pdf({ format: 'A4', ...options })\n )\n}\n"]}
@@ -1,4 +1,4 @@
1
- export declare const screenshot: ({ id, model, data, width: w, height: h, options, isThumbnail, context, draft }?: {
1
+ export declare const screenshot: ({ id, model, data, width, height, options, isThumbnail, context, draft }?: {
2
2
  id?: string;
3
3
  model?: any;
4
4
  data?: any;
@@ -8,4 +8,4 @@ export declare const screenshot: ({ id, model, data, width: w, height: h, option
8
8
  isThumbnail?: boolean;
9
9
  context?: any;
10
10
  draft?: boolean;
11
- }) => Promise<any>;
11
+ }) => Promise<unknown>;
@@ -1,113 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.screenshot = void 0;
4
- const fonts_js_1 = require("./fonts.js");
5
- const headless_pool_for_board_js_1 = require("./headless-pool-for-board.js");
6
- const headless_model_js_1 = require("./headless-model.js");
7
- const protocol = 'http';
8
- const host = 'localhost';
9
- const path = '/internal-board-service-view';
10
- const screenshot = async ({ id = '', model = null, data = null, width: w = 0, height: h = 0, options = { encoding: 'base64' }, isThumbnail = false, context = {}, draft = false } = {}) => {
11
- const browser = (await (0, headless_pool_for_board_js_1.getHeadlessPool)().acquire());
12
- var screenshot = null;
13
- if (!browser) {
14
- return;
15
- }
16
- const { domain, user } = context.state;
17
- var { model, base } = await (0, headless_model_js_1.headlessModel)({ domain, id, model }, draft);
18
- const [fontsToUse, fontStyles] = await (0, fonts_js_1.fonts)(domain);
19
- model.fonts = fontsToUse;
20
- model.fontStyles = fontStyles;
21
- var { width, height } = model;
22
- if (isThumbnail) {
23
- var widthRatio = 400 / width, heightRatio = 300 / height;
24
- var ratio = widthRatio < heightRatio ? widthRatio : heightRatio;
25
- width = width * ratio;
26
- height = height * ratio;
27
- }
28
- width = Math.floor(w || Number(width));
29
- height = Math.floor(h || Number(height));
30
- const port = process.env.PORT ? `:${process.env.PORT}` : '';
31
- const url = `${protocol}://${host}${port}${path}`;
32
- var page = await browser.newPage();
33
- try {
34
- /* @remember-me width, height should be a integer */
35
- await page.setViewport({ width, height });
36
- await page.setRequestInterception(true);
37
- await page.setDefaultTimeout(10000);
38
- page.on('console', async (msg) => {
39
- const args = await Promise.all(msg.args().map(arg => arg.jsonValue().catch(() => undefined)));
40
- if (args.some(a => a !== undefined)) {
41
- console.log(`[headless ${msg.type()}]`, ...args.filter(a => a !== undefined));
42
- }
43
- else {
44
- const text = msg.text();
45
- if (text)
46
- console.log(`[headless ${msg.type()}]`, text);
47
- }
48
- });
49
- page.on('pageerror', error => {
50
- console.log(`[headless pageerror] ${error.message}`);
51
- console.log(error.stack);
52
- });
53
- page.on('error', error => {
54
- console.log(`[headless fault] ${error}`);
55
- console.log(error.stack);
56
- });
57
- page.on('requestfailed', request => {
58
- console.log('Request failed:', request.url());
59
- });
60
- const token = await user?.sign(); // TODO improve performance
61
- page.on('request', request => {
62
- if (request.url() === url) {
63
- request.continue({
64
- method: 'POST',
65
- headers: {
66
- 'Content-Type': 'application/json',
67
- 'x-things-factory-domain': domain?.subdomain,
68
- Authorization: 'Bearer ' + token
69
- },
70
- postData: JSON.stringify({
71
- model,
72
- base
73
- })
74
- });
75
- }
76
- else if (request.url().startsWith(`${protocol}://${host}${port}`)) {
77
- request.continue({
78
- headers: {
79
- ...request.headers(),
80
- 'x-things-factory-domain': domain?.subdomain,
81
- Authorization: 'Bearer ' + token
82
- }
83
- });
84
- }
85
- else {
86
- request.continue();
87
- }
88
- });
89
- await page.goto(url);
90
- await page.evaluate(async (data) => {
91
- if (data) {
92
- // @ts-ignore
93
- s.data = data;
94
- }
95
- // data 주입 후 강제 지연시킴.
96
- return new Promise(resolve => {
97
- // @ts-ignore
98
- requestAnimationFrame(() => resolve());
99
- });
100
- }, data);
101
- screenshot = await page.screenshot(options);
102
- }
103
- catch (error) {
104
- console.log(error);
105
- }
106
- finally {
107
- await page.close();
108
- (0, headless_pool_for_board_js_1.getHeadlessPool)().release(browser);
109
- }
110
- return screenshot;
4
+ const headless_render_js_1 = require("./headless-render.js");
5
+ const screenshot = async ({ id = '', model = null, data = null, width = 0, height = 0, options = { encoding: 'base64' }, isThumbnail = false, context = {}, draft = false } = {}) => {
6
+ return (0, headless_render_js_1.withHeadlessPage)({ id, model, data, width, height, options, context, draft, isThumbnail }, page => page.screenshot(options));
111
7
  };
112
8
  exports.screenshot = screenshot;
113
9
  //# sourceMappingURL=screenshot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../server/controllers/screenshot.ts"],"names":[],"mappings":"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","sourcesContent":["import { fonts } from './fonts.js'\nimport { getHeadlessPool } from './headless-pool-for-board.js'\nimport { headlessModel } from './headless-model.js'\n\nconst protocol = 'http'\nconst host = 'localhost'\nconst path = '/internal-board-service-view'\n\nexport const screenshot = async ({\n id = '',\n model = null,\n data = null,\n width: w = 0,\n height: h = 0,\n options = { encoding: 'base64' } as any,\n isThumbnail = false,\n context = {} as any,\n draft = false\n} = {}) => {\n const browser = (await getHeadlessPool().acquire()) as any\n var screenshot = null\n\n if (!browser) {\n return\n }\n const { domain, user } = context.state\n\n var { model, base } = await headlessModel({ domain, id, model }, draft)\n const [fontsToUse, fontStyles] = await fonts(domain)\n\n model.fonts = fontsToUse\n model.fontStyles = fontStyles\n\n var { width, height } = model\n\n if (isThumbnail) {\n var widthRatio = 400 / width,\n heightRatio = 300 / height\n var ratio = widthRatio < heightRatio ? widthRatio : heightRatio\n width = width * ratio\n height = height * ratio\n }\n width = Math.floor(w || Number(width))\n height = Math.floor(h || Number(height))\n\n const port = process.env.PORT ? `:${process.env.PORT}` : ''\n const url = `${protocol}://${host}${port}${path}`\n\n var page = await browser.newPage()\n\n try {\n /* @remember-me width, height should be a integer */\n await page.setViewport({ width, height })\n await page.setRequestInterception(true)\n await page.setDefaultTimeout(10000)\n\n page.on('console', async msg => {\n const args = await Promise.all(msg.args().map(arg => arg.jsonValue().catch(() => undefined)))\n\n if (args.some(a => a !== undefined)) {\n console.log(`[headless ${msg.type()}]`, ...args.filter(a => a !== undefined))\n } else {\n const text = msg.text()\n if (text) console.log(`[headless ${msg.type()}]`, text)\n }\n })\n\n page.on('pageerror', error => {\n console.log(`[headless pageerror] ${error.message}`)\n console.log(error.stack)\n })\n\n page.on('error', error => {\n console.log(`[headless fault] ${error}`)\n console.log(error.stack)\n })\n\n page.on('requestfailed', request => {\n console.log('Request failed:', request.url())\n })\n\n const token = await user?.sign() // TODO improve performance\n\n page.on('request', request => {\n if (request.url() === url) {\n request.continue({\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-things-factory-domain': domain?.subdomain,\n Authorization: 'Bearer ' + token\n },\n postData: JSON.stringify({\n model,\n base\n })\n })\n } else if (request.url().startsWith(`${protocol}://${host}${port}`)) {\n request.continue({\n headers: {\n ...request.headers(),\n 'x-things-factory-domain': domain?.subdomain,\n Authorization: 'Bearer ' + token\n }\n })\n } else {\n request.continue()\n }\n })\n await page.goto(url)\n\n await page.evaluate(async data => {\n if (data) {\n // @ts-ignore\n s.data = data\n }\n\n // data 주입 후 강제 지연시킴.\n return new Promise(resolve => {\n // @ts-ignore\n requestAnimationFrame(() => resolve())\n })\n }, data)\n\n screenshot = await page.screenshot(options)\n } catch (error) {\n console.log(error)\n } finally {\n await page.close()\n getHeadlessPool().release(browser)\n }\n\n return screenshot\n}\n"]}
1
+ {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../server/controllers/screenshot.ts"],"names":[],"mappings":";;;AAAA,6DAAuD;AAEhD,MAAM,UAAU,GAAG,KAAK,EAAE,EAC/B,EAAE,GAAG,EAAE,EACP,KAAK,GAAG,IAAI,EACZ,IAAI,GAAG,IAAI,EACX,KAAK,GAAG,CAAC,EACT,MAAM,GAAG,CAAC,EACV,OAAO,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAS,EACvC,WAAW,GAAG,KAAK,EACnB,OAAO,GAAG,EAAS,EACnB,KAAK,GAAG,KAAK,KACX,EAAE,EAAE,EAAE;IACR,OAAO,IAAA,qCAAgB,EACrB,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,EACxE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CACjC,CAAA;AACH,CAAC,CAAA;AAfY,QAAA,UAAU,cAetB","sourcesContent":["import { withHeadlessPage } from './headless-render.js'\n\nexport const screenshot = async ({\n id = '',\n model = null,\n data = null,\n width = 0,\n height = 0,\n options = { encoding: 'base64' } as any,\n isThumbnail = false,\n context = {} as any,\n draft = false\n} = {}) => {\n return withHeadlessPage(\n { id, model, data, width, height, options, context, draft, isThumbnail },\n page => page.screenshot(options)\n )\n}\n"]}
@@ -4,4 +4,4 @@ export declare const thumbnail: ({ id, model, data, options, context }?: {
4
4
  data?: any;
5
5
  options?: any;
6
6
  context?: {};
7
- }) => Promise<any>;
7
+ }) => Promise<unknown>;
@@ -165,7 +165,7 @@ let BoardMutation = class BoardMutation {
165
165
  thumbnailPromise,
166
166
  new Promise((_, reject) => setTimeout(() => reject(new Error('5 seconds timeout')), 5000))
167
167
  ]);
168
- patch.thumbnail = 'data:image/png;base64,' + thumbnailBase64.toString('base64');
168
+ patch.thumbnail = 'data:image/png;base64,' + thumbnailBase64;
169
169
  }
170
170
  catch (e) {
171
171
  console.warn(`Failed to get thumbnail for '${board.name}' in first 5 seconds`);
@@ -181,7 +181,7 @@ let BoardMutation = class BoardMutation {
181
181
  await (0, shell_1.getDataSource)().transaction(async (tx) => {
182
182
  await (0, shell_1.getRepository)(board_js_1.Board, tx).save({
183
183
  id: updated.id,
184
- thumbnail: 'data:image/png;base64,' + thumbnailBase64.toString('base64')
184
+ thumbnail: 'data:image/png;base64,' + thumbnailBase64
185
185
  });
186
186
  });
187
187
  })