@things-factory/integration-headless 8.0.0 → 9.0.0-beta.3

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 (35) hide show
  1. package/dist-server/engine/index.d.ts +0 -1
  2. package/dist-server/engine/index.js +0 -1
  3. package/dist-server/engine/index.js.map +1 -1
  4. package/dist-server/engine/task/pdf-capture-util.d.ts +1 -1
  5. package/dist-server/engine/task/pdf-capture-util.js +3 -3
  6. package/dist-server/engine/task/pdf-capture-util.js.map +1 -1
  7. package/dist-server/tsconfig.tsbuildinfo +1 -1
  8. package/helps/integration/connector/headless-connector.ja.md +183 -31
  9. package/helps/integration/connector/headless-connector.ko.md +177 -32
  10. package/helps/integration/connector/headless-connector.md +178 -31
  11. package/helps/integration/connector/headless-connector.ms.md +180 -32
  12. package/helps/integration/connector/headless-connector.zh.md +178 -31
  13. package/package.json +6 -6
  14. package/dist-server/engine/connector/headless-connector.d.ts +0 -14
  15. package/dist-server/engine/connector/headless-connector.js +0 -54
  16. package/dist-server/engine/connector/headless-connector.js.map +0 -1
  17. package/dist-server/engine/connector/headless-pool.d.ts +0 -3
  18. package/dist-server/engine/connector/headless-pool.js +0 -63
  19. package/dist-server/engine/connector/headless-pool.js.map +0 -1
  20. package/dist-server/engine/connector/index.d.ts +0 -1
  21. package/dist-server/engine/connector/index.js +0 -4
  22. package/dist-server/engine/connector/index.js.map +0 -1
  23. package/server/engine/connector/headless-connector.ts +0 -68
  24. package/server/engine/connector/headless-pool.ts +0 -69
  25. package/server/engine/connector/index.ts +0 -1
  26. package/server/engine/index.ts +0 -2
  27. package/server/engine/task/headless-pdf-capture-board.ts +0 -182
  28. package/server/engine/task/headless-pdf-capture-markdown.ts +0 -47
  29. package/server/engine/task/headless-pdf-capture.ts +0 -39
  30. package/server/engine/task/headless-pdf-open.ts +0 -98
  31. package/server/engine/task/headless-pdf-save.ts +0 -88
  32. package/server/engine/task/index.ts +0 -9
  33. package/server/engine/task/pdf-capture-util.ts +0 -331
  34. package/server/index.ts +0 -3
  35. package/server/tsconfig.json +0 -10
@@ -1,182 +0,0 @@
1
- import { TaskRegistry } from '@things-factory/integration-base'
2
- import { PDFCaptureUtil, getCommonParameterSpec } from './pdf-capture-util'
3
- import { BoardFunc } from '@things-factory/board-service'
4
- import { access } from '@things-factory/utils'
5
-
6
- const PAGE_FORMATS = {
7
- A4: { width: 595.28, height: 841.89 },
8
- A3: { width: 841.89, height: 1190.55 },
9
- Letter: { width: 612, height: 792 },
10
- Legal: { width: 612, height: 1008 }
11
- }
12
-
13
- function convertToPixels(value: string): number {
14
- const dpi = 96 // PDF에서 기본적으로 사용하는 DPI
15
-
16
- if (value.endsWith('px')) {
17
- return parseFloat(value)
18
- } else if (value.endsWith('in')) {
19
- const inches = parseFloat(value)
20
- return inches * dpi
21
- } else if (value.endsWith('cm')) {
22
- const cm = parseFloat(value)
23
- return cm * (dpi / 2.54)
24
- }
25
-
26
- return 0
27
- }
28
-
29
- export async function HeadlessPDFCaptureBoard(step, context) {
30
- const pdfUtil = new PDFCaptureUtil(context)
31
- await pdfUtil.initBrowser(step.connection)
32
-
33
- try {
34
- var {
35
- board: boardObject,
36
- accessor,
37
- boardAccessor,
38
- draft,
39
- format = 'A4',
40
- width,
41
- height,
42
- landscape,
43
- marginLeft = 0,
44
- marginRight = 0,
45
- marginTop = 0,
46
- marginBottom = 0
47
- } = step.params
48
- var { domain, data, user, logger } = context
49
-
50
- const boardId = boardAccessor ? access(boardAccessor, data) : boardObject?.id
51
-
52
- if (!boardId) {
53
- throw new Error('The board property must be set')
54
- }
55
-
56
- const boardInput = access(accessor, data)
57
-
58
- const { model, base } = await BoardFunc.headlessModel({ domain, id: boardId }, draft)
59
- const [fontsToUse, fontStyles] = await BoardFunc.fonts(domain)
60
-
61
- model.fonts = fontsToUse
62
- model.fontStyles = fontStyles
63
-
64
- var widthN = width ? convertToPixels(width) : 0
65
- var heightN = height ? convertToPixels(height) : 0
66
-
67
- if (!widthN && !heightN && PAGE_FORMATS[format]) {
68
- const pageDimensions = PAGE_FORMATS[format]
69
- widthN = pageDimensions.width * (96 / 72)
70
- heightN = pageDimensions.height * (96 / 72)
71
- }
72
-
73
- if (landscape && widthN && heightN) {
74
- ;[widthN, heightN] = [heightN, widthN]
75
- }
76
-
77
- marginLeft = convertToPixels(marginLeft)
78
- marginTop = convertToPixels(marginTop)
79
- marginBottom = convertToPixels(marginBottom)
80
- marginRight = convertToPixels(marginRight)
81
-
82
- const contentWidth = widthN - marginLeft - marginRight
83
- const contentHeight = heightN - marginTop - marginBottom
84
-
85
- const page = await pdfUtil.browser!.newPage()
86
-
87
- await page.setViewport({ width: Math.round(contentWidth), height: Math.round(contentHeight) })
88
- await page.setRequestInterception(true)
89
- await page.setDefaultTimeout(10000)
90
-
91
- page.on('console', async msg => {
92
- console.log(`[browser ${msg.type()}] ${msg.text()}`)
93
- })
94
-
95
- page.on('requestfailed', request => {
96
- console.log('Request failed:', request.url())
97
- })
98
-
99
- const protocol = 'http'
100
- const host = 'localhost'
101
- const port = process.env.PORT ? `:${process.env.PORT}` : ''
102
- const path = '/internal-board-service-view'
103
- const url = `${protocol}://${host}${port}${path}`
104
-
105
- const token = await user?.sign()
106
-
107
- page.on('request', request => {
108
- if (request.url() === url) {
109
- request.continue({
110
- method: 'POST',
111
- headers: {
112
- 'Content-Type': 'application/json',
113
- 'x-things-factory-domain': domain?.subdomain,
114
- Authorization: 'Bearer ' + token
115
- },
116
- postData: JSON.stringify({
117
- model,
118
- base
119
- })
120
- })
121
- } else if (request.url().startsWith(`${protocol}://${host}${port}`)) {
122
- request.continue({
123
- headers: {
124
- ...request.headers(),
125
- 'x-things-factory-domain': domain?.subdomain,
126
- Authorization: 'Bearer ' + token
127
- }
128
- })
129
- } else {
130
- request.continue()
131
- }
132
- })
133
-
134
- await page.goto(url)
135
-
136
- await page.evaluate(data => {
137
- //@ts-ignore
138
- s.data = data
139
- return new Promise(resolve => {
140
- requestAnimationFrame(() => resolve(0))
141
- })
142
- }, boardInput)
143
-
144
- await pdfUtil.processPageAndGeneratePDF(step.params, null, page)
145
-
146
- return {
147
- data: context.__headless_pdf
148
- }
149
- } catch (error) {
150
- throw error
151
- } finally {
152
- await pdfUtil.closeBrowser()
153
- }
154
- }
155
-
156
- HeadlessPDFCaptureBoard.parameterSpec = [
157
- ...getCommonParameterSpec(),
158
- {
159
- type: 'string',
160
- name: 'boardAccessor',
161
- label: 'board-accessor'
162
- },
163
- {
164
- type: 'resource-object',
165
- name: 'board',
166
- label: 'board',
167
- property: {
168
- queryName: 'boards'
169
- }
170
- },
171
- {
172
- type: 'boolean',
173
- name: 'draft',
174
- label: 'board-draft',
175
- defaultValue: false,
176
- description: 'Set whether to get the current working version or the last released version'
177
- }
178
- ]
179
-
180
- HeadlessPDFCaptureBoard.help = 'integration/task/headless-pdf-capture-board'
181
-
182
- TaskRegistry.registerTaskHandler('headless-pdf-capture-board', HeadlessPDFCaptureBoard)
@@ -1,47 +0,0 @@
1
- import { TaskRegistry } from '@things-factory/integration-base'
2
- import { access } from '@things-factory/utils'
3
- import { marked } from 'marked'
4
-
5
- import { PDFCaptureUtil, getCommonParameterSpec } from './pdf-capture-util'
6
-
7
- export async function HeadlessPDFCaptureMarkdown(step, context) {
8
- const pdfUtil = new PDFCaptureUtil(context)
9
- await pdfUtil.initBrowser(step.connection)
10
-
11
- try {
12
- const { accessor, markdownContent, markdownContentAccessor } = step.params
13
- const templateInput = access(accessor, context.data)
14
- const markdownTemplate = markdownContentAccessor ? access(markdownContentAccessor, context.data) : markdownContent
15
-
16
- const renderedMarkdown = pdfUtil.renderTemplate(markdownTemplate, templateInput)
17
- const htmlContent = marked(renderedMarkdown)
18
-
19
- await pdfUtil.processPageAndGeneratePDF(step.params, htmlContent)
20
-
21
- return {
22
- data: context.__headless_pdf
23
- }
24
- } catch (error) {
25
- throw error
26
- } finally {
27
- await pdfUtil.closeBrowser()
28
- }
29
- }
30
-
31
- HeadlessPDFCaptureMarkdown.parameterSpec = [
32
- ...getCommonParameterSpec(),
33
- {
34
- type: 'scenario-step-input',
35
- name: 'markdownContentAccessor',
36
- label: 'markdown-content-accessor'
37
- },
38
- {
39
- type: 'textarea',
40
- name: 'markdownContent',
41
- label: 'markdown-content'
42
- }
43
- ]
44
-
45
- HeadlessPDFCaptureMarkdown.help = 'integration/task/headless-pdf-capture-markdown'
46
-
47
- TaskRegistry.registerTaskHandler('headless-pdf-capture-markdown', HeadlessPDFCaptureMarkdown)
@@ -1,39 +0,0 @@
1
- import { TaskRegistry } from '@things-factory/integration-base'
2
- import { access } from '@things-factory/utils'
3
-
4
- import { PDFCaptureUtil, getCommonParameterSpec } from './pdf-capture-util'
5
-
6
- export async function HeadlessPDFCapture(step, context) {
7
- const pdfUtil = new PDFCaptureUtil(context)
8
- await pdfUtil.initBrowser(step.connection)
9
-
10
- try {
11
- const { accessor, htmlContent } = step.params
12
- const templateInput = access(accessor, context.data)
13
-
14
- const renderedHtmlContent = pdfUtil.renderTemplate(htmlContent, templateInput)
15
-
16
- await pdfUtil.processPageAndGeneratePDF(step.params, renderedHtmlContent)
17
-
18
- return {
19
- data: context.__headless_pdf
20
- }
21
- } catch (error) {
22
- throw error
23
- } finally {
24
- await pdfUtil.closeBrowser()
25
- }
26
- }
27
-
28
- HeadlessPDFCapture.parameterSpec = [
29
- ...getCommonParameterSpec(),
30
- {
31
- type: 'textarea',
32
- name: 'htmlContent',
33
- label: 'html-content'
34
- }
35
- ]
36
-
37
- HeadlessPDFCapture.help = 'integration/task/headless-pdf-capture'
38
-
39
- TaskRegistry.registerTaskHandler('headless-pdf-capture', HeadlessPDFCapture)
@@ -1,98 +0,0 @@
1
- import { PDFDocument } from 'pdf-lib'
2
- import { TaskRegistry } from '@things-factory/integration-base'
3
- import { access } from '@things-factory/utils'
4
- import { PDFCaptureUtil, getCommonParameterSpec } from './pdf-capture-util'
5
-
6
- async function HeadlessPDFOpen(step, context) {
7
- const { connection: connectionName, params: stepOptions } = step
8
- const { accessor, coverPage, lastPage, header, footer, watermark, fileName } = stepOptions || {}
9
-
10
- const { data } = context
11
-
12
- // Create a new PDF document using pdf-lib
13
- const pdfDoc = await PDFDocument.create()
14
-
15
- try {
16
- const fileNameEncoded = fileName ? new TextEncoder().encode(access(fileName, data)) : undefined
17
-
18
- const pdfInfo = {
19
- pdfDoc,
20
- watermark,
21
- fileName: fileNameEncoded,
22
- pageCount: 0
23
- } as any
24
- context.__headless_pdf = pdfInfo
25
-
26
- var pdfUtil = new PDFCaptureUtil(context)
27
- await pdfUtil.initBrowser(connectionName)
28
-
29
- const templateInput = access(accessor, data)
30
-
31
- // Convert Cover Page to PDF and add it to the document (if provided)
32
- if (coverPage) {
33
- const renderedCoverPage = pdfUtil.renderTemplate(coverPage, templateInput)
34
- await pdfUtil.processPageAndGeneratePDF(stepOptions, renderedCoverPage)
35
- }
36
-
37
- var lastPageBuffer
38
-
39
- // Process Last Page (if provided) but add it later in the save task
40
- if (lastPage) {
41
- const renderedLastPage = pdfUtil.renderTemplate(lastPage, templateInput)
42
- lastPageBuffer = await pdfUtil.generateLastPageBuffer(stepOptions, renderedLastPage)
43
- }
44
-
45
- pdfInfo.lastPageBuffer = lastPageBuffer
46
- pdfInfo.pageCount = pdfDoc.getPageCount()
47
- pdfInfo.header = header
48
- pdfInfo.footer = footer
49
-
50
- return {
51
- data: pdfInfo
52
- }
53
- } catch (error) {
54
- throw error
55
- } finally {
56
- await pdfUtil?.closeBrowser()
57
- }
58
- }
59
-
60
- HeadlessPDFOpen.parameterSpec = [
61
- ...getCommonParameterSpec(),
62
- {
63
- type: 'textarea',
64
- name: 'coverPage',
65
- label: 'pdf-cover-page'
66
- },
67
- {
68
- type: 'textarea',
69
- name: 'lastPage',
70
- label: 'pdf-last-page'
71
- },
72
- {
73
- type: 'string',
74
- name: 'header',
75
- label: 'header',
76
- placeholder: 'Page <%= pageNumber %> of <%= totalPages %>'
77
- },
78
- {
79
- type: 'string',
80
- name: 'footer',
81
- label: 'footer',
82
- placeholder: 'Page <%= pageNumber %> of <%= totalPages %>'
83
- },
84
- {
85
- type: 'string',
86
- name: 'watermark',
87
- label: 'watermark'
88
- },
89
- {
90
- type: 'string',
91
- name: 'fileName',
92
- label: 'filename'
93
- }
94
- ]
95
-
96
- HeadlessPDFOpen.help = 'integration/task/headless-pdf-open'
97
-
98
- TaskRegistry.registerTaskHandler('headless-pdf-open', HeadlessPDFOpen)
@@ -1,88 +0,0 @@
1
- import { PDFDocument } from 'pdf-lib'
2
- import { Readable } from 'stream'
3
- import { TaskRegistry } from '@things-factory/integration-base'
4
- import { Attachment, createAttachment } from '@things-factory/attachment-base'
5
- import { getRepository } from '@things-factory/shell'
6
-
7
- async function HeadlessPDFSave(step, context) {
8
- const { domain, user, __headless_pdf } = context
9
-
10
- if (!__headless_pdf || !__headless_pdf.pdfDoc) {
11
- throw new Error(
12
- 'No PDF document found. Ensure that headless-pdf-open and headless-pdf-capture tasks are executed before saving.'
13
- )
14
- }
15
-
16
- const pdfDoc = __headless_pdf.pdfDoc
17
-
18
- // Add last page if it exists
19
- if (__headless_pdf.lastPageBuffer) {
20
- await appendLastPageToPDF(pdfDoc, __headless_pdf.lastPageBuffer)
21
- }
22
-
23
- const pdfBytes = await pdfDoc.save()
24
- const finalFileName = generateFileName(__headless_pdf.fileName)
25
-
26
- const savedAttachment = await savePDFToFile(pdfBytes, finalFileName, domain, user)
27
- const attachment = await getAttachmentDetails(savedAttachment.id)
28
-
29
- return {
30
- data: {
31
- id: attachment.id,
32
- name: attachment.name,
33
- path: attachment.path,
34
- mimetype: attachment.mimetype,
35
- refBy: attachment.refBy,
36
- fullpath: attachment.fullpath
37
- }
38
- }
39
- }
40
-
41
- async function appendLastPageToPDF(pdfDoc, lastPageBuffer) {
42
- const lastPageDoc = await PDFDocument.load(lastPageBuffer)
43
- const copiedLastPages = await pdfDoc.copyPages(lastPageDoc, lastPageDoc.getPageIndices())
44
- copiedLastPages.forEach(page => pdfDoc.addPage(page))
45
- }
46
-
47
- function generateFileName(fileName) {
48
- return fileName || `document-${Date.now()}.pdf`
49
- }
50
-
51
- async function savePDFToFile(pdfBytes, finalFileName, domain, user) {
52
- return await createAttachment(
53
- null,
54
- {
55
- attachment: {
56
- file: {
57
- createReadStream: () =>
58
- new Readable({
59
- read() {
60
- this.push(pdfBytes)
61
- this.push(null)
62
- }
63
- }),
64
- filename: finalFileName,
65
- mimetype: 'application/pdf',
66
- encoding: 'binary'
67
- },
68
- refType: 'headless-pdf-save',
69
- refBy: 'pdf-published'
70
- }
71
- },
72
- {
73
- state: { domain, user }
74
- }
75
- )
76
- }
77
-
78
- async function getAttachmentDetails(attachmentId) {
79
- return await getRepository(Attachment).findOne({
80
- where: { id: attachmentId }
81
- })
82
- }
83
-
84
- HeadlessPDFSave.parameterSpec = []
85
-
86
- HeadlessPDFSave.help = 'integration/task/headless-pdf-save'
87
-
88
- TaskRegistry.registerTaskHandler('headless-pdf-save', HeadlessPDFSave)
@@ -1,9 +0,0 @@
1
- import './headless-pdf-capture'
2
- import './headless-pdf-capture-markdown'
3
- import './headless-pdf-capture-board'
4
- import './headless-pdf-open'
5
- import './headless-pdf-save'
6
- import './pdf-capture-util'
7
-
8
- export * from './pdf-capture-util'
9
- export * from './headless-pdf-capture-board'