pdfdancer-client-typescript 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/__tests__/e2e/test-helpers.d.ts +2 -1
- package/dist/__tests__/e2e/test-helpers.d.ts.map +1 -1
- package/dist/__tests__/e2e/test-helpers.js +7 -3
- package/dist/__tests__/e2e/test-helpers.js.map +1 -1
- package/dist/client-v1.js +1 -1
- package/dist/client-v1.js.map +1 -1
- package/dist/client-v2.d.ts +129 -0
- package/dist/client-v2.d.ts.map +1 -0
- package/dist/client-v2.js +696 -0
- package/dist/client-v2.js.map +1 -0
- package/dist/image-builder.d.ts +13 -0
- package/dist/image-builder.d.ts.map +1 -0
- package/dist/image-builder.js +44 -0
- package/dist/image-builder.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +5 -10
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +3 -13
- package/dist/models.js.map +1 -1
- package/dist/paragraph-builder.d.ts +19 -10
- package/dist/paragraph-builder.d.ts.map +1 -1
- package/dist/paragraph-builder.js +65 -26
- package/dist/paragraph-builder.js.map +1 -1
- package/dist/pdfdancer_v1.d.ts +202 -0
- package/dist/pdfdancer_v1.d.ts.map +1 -0
- package/dist/pdfdancer_v1.js +702 -0
- package/dist/pdfdancer_v1.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +92 -0
- package/dist/types.js.map +1 -0
- package/package.json +1 -1
- package/scripts/release.js +1 -1
- package/src/__tests__/client-v1.test.ts +46 -87
- package/src/__tests__/e2e/acroform.test.ts +60 -57
- package/src/__tests__/e2e/form_x_object.test.ts +17 -16
- package/src/__tests__/e2e/image.test.ts +53 -56
- package/src/__tests__/e2e/line.test.ts +47 -48
- package/src/__tests__/e2e/page.test.ts +37 -36
- package/src/__tests__/e2e/paragraph.test.ts +107 -101
- package/src/__tests__/e2e/path.test.ts +67 -64
- package/src/__tests__/e2e/test-helpers.ts +71 -67
- package/src/__tests__/e2e/token_from_env.test.ts +35 -0
- package/src/image-builder.ts +52 -0
- package/src/index.ts +1 -1
- package/src/models.ts +5 -21
- package/src/paragraph-builder.ts +217 -162
- package/src/{client-v1.ts → pdfdancer_v1.ts} +248 -53
- package/src/types.ts +133 -0
- package/example.ts +0 -99
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* E2E tests for paragraph operations
|
|
2
|
+
* E2E tests for paragraph operations — new PDFDancer API
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {Color, PDFDancer} from '../../index';
|
|
6
6
|
import {readFontFixture, requireEnvAndFixture} from './test-helpers';
|
|
7
|
-
import {expectWithin} from
|
|
7
|
+
import {expectWithin} from '../assertions';
|
|
8
8
|
|
|
9
|
-
describe('Paragraph E2E Tests', () => {
|
|
10
|
-
// Tests should fail properly if environment is not configured
|
|
9
|
+
describe('Paragraph E2E Tests (v2 API)', () => {
|
|
11
10
|
|
|
12
11
|
test('find paragraphs by position', async () => {
|
|
13
12
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
14
|
-
const
|
|
13
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
15
14
|
|
|
16
|
-
const paras = await
|
|
15
|
+
const paras = await pdf.selectParagraphs();
|
|
17
16
|
expect(paras).toHaveLength(172);
|
|
18
17
|
|
|
19
|
-
const parasPage0 = await
|
|
18
|
+
const parasPage0 = await pdf.page(0).selectParagraphs();
|
|
20
19
|
expect(parasPage0).toHaveLength(2);
|
|
21
20
|
|
|
22
21
|
const first = parasPage0[0];
|
|
@@ -34,10 +33,9 @@ describe('Paragraph E2E Tests', () => {
|
|
|
34
33
|
|
|
35
34
|
test('find paragraphs by text', async () => {
|
|
36
35
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
37
|
-
const
|
|
36
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
38
37
|
|
|
39
|
-
const
|
|
40
|
-
const paras = await client.findParagraphs(pos);
|
|
38
|
+
const paras = await pdf.page(0).selectParagraphsStartingWith('The Complete');
|
|
41
39
|
expect(paras).toHaveLength(1);
|
|
42
40
|
|
|
43
41
|
const p = paras[0];
|
|
@@ -47,147 +45,155 @@ describe('Paragraph E2E Tests', () => {
|
|
|
47
45
|
expectWithin(p.position.boundingRect?.y, 496, 2);
|
|
48
46
|
});
|
|
49
47
|
|
|
48
|
+
test('find paragraphs by pattern', async () => {
|
|
49
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
50
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
51
|
+
|
|
52
|
+
const paras = await pdf.page(0).selectParagraphsMatching('.*Complete.*');
|
|
53
|
+
expect(paras).toHaveLength(1);
|
|
54
|
+
const p = paras[0];
|
|
55
|
+
expect(p.internalId).toBe('PARAGRAPH_000004');
|
|
56
|
+
|
|
57
|
+
const paras2 = await pdf.page(0).selectParagraphsMatching('.*NOT FOUND.*');
|
|
58
|
+
expect(paras2).toHaveLength(0);
|
|
59
|
+
|
|
60
|
+
const paras3 = await pdf.page(0).selectParagraphsMatching('.*');
|
|
61
|
+
expect(paras3).toHaveLength(2);
|
|
62
|
+
});
|
|
63
|
+
|
|
50
64
|
test('delete paragraph', async () => {
|
|
51
65
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
52
|
-
const
|
|
66
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
53
67
|
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
expect(await client.delete(ref)).toBe(true);
|
|
68
|
+
const [target] = await pdf.page(0).selectParagraphsStartingWith('The Complete');
|
|
69
|
+
await target.delete();
|
|
57
70
|
|
|
58
|
-
const
|
|
59
|
-
expect(
|
|
71
|
+
const remaining = await pdf.page(0).selectParagraphsStartingWith('The Complete');
|
|
72
|
+
expect(remaining).toHaveLength(0);
|
|
60
73
|
});
|
|
61
74
|
|
|
62
75
|
test('move paragraph', async () => {
|
|
63
76
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
64
|
-
const
|
|
77
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
65
78
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
const newPos = Position.atPageCoordinates(0, 0.1, 300);
|
|
69
|
-
expect(await client.move(ref, newPos)).toBe(true);
|
|
79
|
+
const [para] = await pdf.page(0).selectParagraphsStartingWith('The Complete');
|
|
80
|
+
await para.moveTo(0.1, 300);
|
|
70
81
|
|
|
71
|
-
const
|
|
72
|
-
expect(
|
|
82
|
+
const moved = await pdf.page(0).selectParagraphsAt(0.1, 300);
|
|
83
|
+
expect(moved.length).toBeGreaterThan(0);
|
|
73
84
|
});
|
|
74
85
|
|
|
75
|
-
async function assertNewParagraphExists(
|
|
76
|
-
|
|
77
|
-
const pos = Position.atPage(0).withTextStarts('Awesomely');
|
|
78
|
-
const lines = await client.findTextLines(pos);
|
|
86
|
+
async function assertNewParagraphExists(pdf: PDFDancer) {
|
|
87
|
+
const lines = await pdf.page(0).selectTextLinesStartingWith('Awesomely');
|
|
79
88
|
expect(lines.length).toBeGreaterThanOrEqual(1);
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
test('modify paragraph', async () => {
|
|
83
92
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
84
|
-
const
|
|
93
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
85
94
|
|
|
86
|
-
const
|
|
87
|
-
const ref = (await client.findParagraphs(posMod))[0];
|
|
95
|
+
const [para] = await pdf.page(0).selectParagraphsStartingWith('The Complete');
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
.
|
|
91
|
-
.
|
|
92
|
-
.
|
|
93
|
-
.
|
|
94
|
-
.build();
|
|
97
|
+
await para.edit().replace('Awesomely\nObvious!')
|
|
98
|
+
.font("Helvetica", 12)
|
|
99
|
+
.lineSpacing(0.7)
|
|
100
|
+
.moveTo(300.1, 500)
|
|
101
|
+
.apply()
|
|
95
102
|
|
|
96
|
-
|
|
97
|
-
await assertNewParagraphExists(client);
|
|
103
|
+
await assertNewParagraphExists(pdf);
|
|
98
104
|
});
|
|
99
105
|
|
|
100
|
-
test('modify paragraph simple', async () => {
|
|
106
|
+
test('modify paragraph (simple)', async () => {
|
|
101
107
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
102
|
-
const
|
|
108
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
103
109
|
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
await assertNewParagraphExists(client);
|
|
110
|
+
const [para] = await pdf.page(0).selectParagraphsStartingWith('The Complete');
|
|
111
|
+
await para.edit().replace('Awesomely\nObvious!').apply();
|
|
112
|
+
await assertNewParagraphExists(pdf);
|
|
108
113
|
});
|
|
109
114
|
|
|
110
|
-
test('add paragraph with
|
|
115
|
+
test('add paragraph with missing font (expect error)', async () => {
|
|
111
116
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
118
|
+
|
|
119
|
+
await expect(
|
|
120
|
+
pdf.page(0).newParagraph()
|
|
121
|
+
.text('Awesomely\nObvious!')
|
|
122
|
+
.font('Roboto', 14)
|
|
123
|
+
.lineSpacing(0.7)
|
|
124
|
+
.at(300.1, 500)
|
|
125
|
+
.apply()
|
|
126
|
+
).rejects.toThrow('Font not found');
|
|
121
127
|
});
|
|
122
128
|
|
|
123
|
-
test('add paragraph with
|
|
129
|
+
test('add paragraph with known font', async () => {
|
|
124
130
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
125
|
-
const
|
|
131
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
126
132
|
|
|
127
|
-
const
|
|
128
|
-
.
|
|
129
|
-
.
|
|
130
|
-
.
|
|
131
|
-
.
|
|
133
|
+
const success = await pdf.page(0).newParagraph()
|
|
134
|
+
.text('Awesomely\nObvious!')
|
|
135
|
+
.font('Roboto-Regular', 14)
|
|
136
|
+
.lineSpacing(0.7)
|
|
137
|
+
.at(300.1, 500)
|
|
138
|
+
.apply()
|
|
132
139
|
|
|
133
|
-
expect(
|
|
134
|
-
await assertNewParagraphExists(
|
|
140
|
+
expect(success).toBe(true);
|
|
141
|
+
await assertNewParagraphExists(pdf);
|
|
135
142
|
});
|
|
136
143
|
|
|
137
|
-
test('add paragraph
|
|
144
|
+
test('add paragraph using font lookup', async () => {
|
|
138
145
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
139
|
-
const
|
|
146
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
140
147
|
|
|
141
|
-
const fonts = await
|
|
148
|
+
const fonts = await pdf.findFonts('Roboto', 14);
|
|
142
149
|
expect(fonts.length).toBeGreaterThan(0);
|
|
143
|
-
expect(fonts[0].name).toBe('Roboto-Regular');
|
|
144
|
-
|
|
145
150
|
const roboto = fonts[0];
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
.
|
|
149
|
-
.
|
|
150
|
-
.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
|
|
152
|
+
const success = await pdf.page(0).newParagraph()
|
|
153
|
+
.text('Awesomely\nObvious!')
|
|
154
|
+
.font(roboto)
|
|
155
|
+
.lineSpacing(0.7)
|
|
156
|
+
.at(300.1, 500)
|
|
157
|
+
.apply();
|
|
158
|
+
|
|
159
|
+
expect(success).toBe(true);
|
|
160
|
+
await assertNewParagraphExists(pdf);
|
|
154
161
|
});
|
|
155
162
|
|
|
156
163
|
test('add paragraph with Asimovian font', async () => {
|
|
157
164
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
158
|
-
const
|
|
165
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
159
166
|
|
|
160
|
-
const fonts = await
|
|
167
|
+
const fonts = await pdf.findFonts('Asimovian', 14);
|
|
161
168
|
expect(fonts.length).toBeGreaterThan(0);
|
|
162
|
-
expect(fonts[0].name).toBe('Asimovian-Regular');
|
|
163
|
-
|
|
164
169
|
const asimovian = fonts[0];
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
.
|
|
168
|
-
.
|
|
169
|
-
.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
|
|
171
|
+
const success = await pdf.page(0).newParagraph()
|
|
172
|
+
.text('Awesomely\nObvious!')
|
|
173
|
+
.font(asimovian)
|
|
174
|
+
.lineSpacing(0.7)
|
|
175
|
+
.at(300.1, 500)
|
|
176
|
+
.apply();
|
|
177
|
+
|
|
178
|
+
expect(success).toBe(true);
|
|
179
|
+
await assertNewParagraphExists(pdf);
|
|
173
180
|
});
|
|
174
181
|
|
|
175
182
|
test('add paragraph with custom TTF font', async () => {
|
|
176
183
|
const [baseUrl, token, pdfData] = await requireEnvAndFixture('ObviouslyAwesome.pdf');
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
// Use DancingScript-Regular.ttf from fixtures directory
|
|
180
|
-
const ttfData = readFontFixture('DancingScript-Regular.ttf');
|
|
184
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl);
|
|
181
185
|
|
|
182
|
-
const
|
|
183
|
-
.fromString('Awesomely\\nObvious!')
|
|
184
|
-
.withLineSpacing(1.8)
|
|
185
|
-
.withColor(new Color(0, 0, 255))
|
|
186
|
-
.withPosition(Position.atPageCoordinates(0, 300.1, 500));
|
|
186
|
+
const ttf = readFontFixture('DancingScript-Regular.ttf');
|
|
187
187
|
|
|
188
|
-
await
|
|
188
|
+
const success = await pdf.page(0).newParagraph()
|
|
189
|
+
.text('Awesomely\nObvious!')
|
|
190
|
+
.fontFile(ttf, 24)
|
|
191
|
+
.lineSpacing(1.8)
|
|
192
|
+
.color(new Color(0, 0, 255))
|
|
193
|
+
.at(300.1, 500)
|
|
194
|
+
.apply();
|
|
189
195
|
|
|
190
|
-
expect(
|
|
191
|
-
await assertNewParagraphExists(
|
|
196
|
+
expect(success).toBe(true);
|
|
197
|
+
await assertNewParagraphExists(pdf);
|
|
192
198
|
});
|
|
193
199
|
});
|
|
@@ -1,68 +1,71 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* E2E tests for path operations
|
|
2
|
+
* E2E tests for path operations (new PDFDancer API)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
describe('Path E2E Tests', () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
5
|
+
import {requireEnvAndFixture} from './test-helpers';
|
|
6
|
+
import {PDFDancer} from "../../pdfdancer_v1";
|
|
7
|
+
|
|
8
|
+
describe('Path E2E Tests (New API)', () => {
|
|
9
|
+
|
|
10
|
+
test('select paths', async () => {
|
|
11
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('basic-paths.pdf');
|
|
12
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl, 30000);
|
|
13
|
+
|
|
14
|
+
const paths = await pdf.selectPaths();
|
|
15
|
+
expect(paths).toHaveLength(9);
|
|
16
|
+
expect(paths[0].type).toBe('PATH');
|
|
17
|
+
|
|
18
|
+
const p1 = paths[0];
|
|
19
|
+
expect(p1).toBeDefined();
|
|
20
|
+
expect(p1.internalId).toBe('PATH_000001');
|
|
21
|
+
expect(p1.position.getX()).toBeCloseTo(80, 1);
|
|
22
|
+
expect(p1.position.getY()).toBeCloseTo(720, 1);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('select paths by position', async () => {
|
|
26
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('basic-paths.pdf');
|
|
27
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl, 30000);
|
|
28
|
+
|
|
29
|
+
const paths = await pdf.page(0).selectPathsAt(80, 720);
|
|
30
|
+
expect(paths).toHaveLength(1);
|
|
31
|
+
expect(paths[0].internalId).toBe('PATH_000001');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('delete path', async () => {
|
|
35
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('basic-paths.pdf');
|
|
36
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl, 30000);
|
|
37
|
+
|
|
38
|
+
let paths = await pdf.page(0).selectPathsAt(80, 720);
|
|
39
|
+
expect(paths).toHaveLength(1);
|
|
40
|
+
expect(paths[0].internalId).toBe('PATH_000001');
|
|
41
|
+
|
|
42
|
+
const path = paths[0];
|
|
43
|
+
await path.delete();
|
|
44
|
+
|
|
45
|
+
const remainingAtOldPos = await pdf.page(0).selectPathsAt(80, 720);
|
|
46
|
+
expect(remainingAtOldPos).toHaveLength(0);
|
|
47
|
+
|
|
48
|
+
const allPaths = await pdf.selectPaths();
|
|
49
|
+
expect(allPaths).toHaveLength(8);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('move path', async () => {
|
|
53
|
+
const [baseUrl, token, pdfData] = await requireEnvAndFixture('basic-paths.pdf');
|
|
54
|
+
const pdf = await PDFDancer.open(pdfData, token, baseUrl, 30000);
|
|
55
|
+
|
|
56
|
+
const [path] = await pdf.page(0).selectPathsAt(80, 720);
|
|
57
|
+
const pos = path.position;
|
|
58
|
+
expect(pos.getX()).toBeCloseTo(80, 1);
|
|
59
|
+
expect(pos.getY()).toBeCloseTo(720, 1);
|
|
60
|
+
|
|
61
|
+
await path.moveTo(50.1, 100);
|
|
62
|
+
|
|
63
|
+
const oldPos = await pdf.page(0).selectPathsAt(80, 720);
|
|
64
|
+
expect(oldPos).toHaveLength(0);
|
|
65
|
+
|
|
66
|
+
const moved = await pdf.page(0).selectPathsAt(50.1, 100);
|
|
67
|
+
const movedPos = moved[0].position;
|
|
68
|
+
expect(movedPos.getX()).toBeCloseTo(50.1, 1);
|
|
69
|
+
expect(movedPos.getY()).toBeCloseTo(100, 1);
|
|
70
|
+
});
|
|
68
71
|
});
|
|
@@ -9,124 +9,128 @@ import * as path from 'path';
|
|
|
9
9
|
* Get the base URL from environment variable or default
|
|
10
10
|
*/
|
|
11
11
|
export function getBaseUrl(): string {
|
|
12
|
-
|
|
12
|
+
return process.env.PDFDANCER_BASE_URL || 'http://localhost:8080';
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Read authentication token from environment or token files
|
|
17
17
|
*/
|
|
18
18
|
export function readToken(): string | null {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
const token = process.env.PDFDANCER_TOKEN;
|
|
20
|
+
if (token) {
|
|
21
|
+
return token.trim();
|
|
22
|
+
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
// Try common token files in project root
|
|
25
|
+
const projectRoot = path.resolve(__dirname, '../../..');
|
|
26
|
+
const candidates = findFiles(projectRoot, 'jwt-token-*.txt');
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
for (const file of candidates) {
|
|
29
|
+
try {
|
|
30
|
+
return fs.readFileSync(file, 'utf-8').trim();
|
|
31
|
+
} catch {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
33
34
|
}
|
|
34
|
-
}
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
return null;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* Check if server is up and running
|
|
41
41
|
*/
|
|
42
42
|
export async function serverUp(baseUrl: string): Promise<boolean> {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
try {
|
|
44
|
+
const response = await fetch(`${baseUrl}/ping`, {
|
|
45
|
+
signal: AbortSignal.timeout(3000)
|
|
46
|
+
});
|
|
47
|
+
const text = await response.text();
|
|
48
|
+
return response.status === 200 && text.includes('Pong');
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Helper to find files matching a pattern
|
|
56
56
|
*/
|
|
57
57
|
function findFiles(dir: string, pattern: string): string[] {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
try {
|
|
59
|
+
const files = fs.readdirSync(dir);
|
|
60
|
+
const regex = new RegExp(pattern.replace('*', '.*'));
|
|
61
|
+
return files
|
|
62
|
+
.filter(file => regex.test(file))
|
|
63
|
+
.map(file => path.join(dir, file));
|
|
64
|
+
} catch {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* Require environment variables and PDF fixture for testing
|
|
71
71
|
*/
|
|
72
72
|
export async function requireEnvAndFixture(pdfFilename: string): Promise<[string, string, Uint8Array]> {
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
const baseUrl = getBaseUrl();
|
|
74
|
+
const token = readToken();
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
if (!await serverUp(baseUrl)) {
|
|
77
|
+
throw new Error(`PDFDancer server not reachable at ${baseUrl}; set PDFDANCER_BASE_URL or start server`);
|
|
78
|
+
}
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
if (!token) {
|
|
81
|
+
throw new Error('PDFDANCER_TOKEN not set and no token file found; set env or place jwt-token-*.txt in repo');
|
|
82
|
+
}
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
// Look for PDF fixture file
|
|
85
|
+
const fixturesDir = path.resolve(__dirname, '../../../fixtures');
|
|
86
|
+
const pdfPath = path.join(fixturesDir, pdfFilename);
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
if (!fs.existsSync(pdfPath)) {
|
|
89
|
+
throw new Error(`${pdfFilename} fixture not found at ${pdfPath}`);
|
|
90
|
+
}
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
const pdfData = fs.readFileSync(pdfPath);
|
|
93
|
+
return [baseUrl, token, new Uint8Array(pdfData)];
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
|
-
* Helper to
|
|
97
|
+
* Helper to open temporary file path (for Node.js environment)
|
|
98
98
|
*/
|
|
99
99
|
export function createTempPath(filename: string): string {
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
const tmpDir = process.env.TMPDIR || '/tmp';
|
|
101
|
+
return path.join(tmpDir, filename);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
105
|
* Helper to read image file for tests
|
|
106
106
|
*/
|
|
107
107
|
export function readImageFixture(filename: string): Uint8Array {
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
const imagePath = getImagePath(filename);
|
|
109
|
+
|
|
110
|
+
if (!fs.existsSync(imagePath)) {
|
|
111
|
+
throw new Error(`Image fixture not found: ${filename}`);
|
|
112
|
+
}
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
const imageData = fs.readFileSync(imagePath);
|
|
115
|
+
return new Uint8Array(imageData);
|
|
116
|
+
}
|
|
114
117
|
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
export function getImagePath(filename: string): string {
|
|
119
|
+
const fixturesDir = path.resolve(__dirname, '../../../fixtures');
|
|
120
|
+
return path.join(fixturesDir, filename);
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
/**
|
|
120
124
|
* Helper to read font file for tests
|
|
121
125
|
*/
|
|
122
126
|
export function readFontFixture(filename: string): Uint8Array {
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
const fixturesDir = path.resolve(__dirname, '../../../fixtures');
|
|
128
|
+
const fontPath = path.join(fixturesDir, filename);
|
|
125
129
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
if (!fs.existsSync(fontPath)) {
|
|
131
|
+
throw new Error(`Font fixture not found: ${filename}`);
|
|
132
|
+
}
|
|
129
133
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
134
|
+
const fontData = fs.readFileSync(fontPath);
|
|
135
|
+
return new Uint8Array(fontData);
|
|
136
|
+
}
|