@inizioevoke/veeva-astroclm-core 1.3.9 → 1.4.1
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/dist/apps/veeva-config-manager/templates/config.ts.txt +1 -0
- package/dist/lib/utils.js +1 -1
- package/dist/tasks/create-csv.js +2 -2
- package/dist/tasks/create-zips.d.ts +3 -1
- package/dist/tasks/create-zips.js +6 -2
- package/dist/tasks/deploy.js +28 -3
- package/dist/tasks/generate-thumbs.js +37 -11
- package/dist/tasks/update-shared.js +10 -3
- package/dist/types/config.d.ts +3 -1
- package/package.json +2 -1
- package/src/apps/veeva-config-manager/templates/config.ts.txt +1 -0
- package/src/lib/utils.ts +1 -1
- package/src/tasks/create-csv.ts +2 -2
- package/src/tasks/create-zips.ts +10 -2
- package/src/tasks/deploy.ts +29 -5
- package/src/tasks/generate-thumbs.ts +44 -12
- package/src/tasks/update-shared.ts +9 -3
- package/src/types/config.d.ts +3 -1
package/dist/lib/utils.js
CHANGED
|
@@ -2,7 +2,7 @@ export function formatExtId(...ids) {
|
|
|
2
2
|
return ids.map((id) => { return id.toUpperCase(); }).join('_');
|
|
3
3
|
}
|
|
4
4
|
export function pathToSlideZip(path) {
|
|
5
|
-
return `${flattenPath(path, { slashes: false })}.zip`;
|
|
5
|
+
return `${flattenPath(path, { slashes: false }).replace(/\.zip$/i, '')}.zip`;
|
|
6
6
|
}
|
|
7
7
|
export function flattenPath(path, { slashes = true } = {}) {
|
|
8
8
|
return `${slashes ? '/' : ''}${path.toLowerCase().split('/').filter(s => s !== '').join('-')}${slashes ? '/' : ''}`;
|
package/dist/tasks/create-csv.js
CHANGED
|
@@ -152,7 +152,7 @@ function createSlideRow(headers, config, slide, additional) {
|
|
|
152
152
|
addColumn(headers, row, HEADER_SLIDE_REACTIONS, disable.has('Reactions') ? ',a,b,c' : '');
|
|
153
153
|
disable.delete('Reactions');
|
|
154
154
|
addColumn(headers, row, HEADER_SLIDE_DISABLE_ACTIONS, [...disable].join(','));
|
|
155
|
-
addColumn(headers, row, HEADER_SLIDE_FILE_NAME, pathToSlideZip(slide.path));
|
|
155
|
+
addColumn(headers, row, HEADER_SLIDE_FILE_NAME, pathToSlideZip(slide.zipFileName ?? slide.path));
|
|
156
156
|
addColumn(headers, row, HEADER_SLIDE_RELATED_SHARED, config.presentation.shared?.externalId ?? '');
|
|
157
157
|
addColumn(headers, row, HEADER_SLIDE_CLM_CONTENT, VEEVA_YES);
|
|
158
158
|
addColumn(headers, row, HEADER_PRESENTATION, config.presentation.externalId);
|
|
@@ -180,7 +180,7 @@ function createSharedRow(headers, config, additional) {
|
|
|
180
180
|
addColumn(headers, row, HEADER_SLIDE_PRODUCT, config.presentation.product);
|
|
181
181
|
addColumn(headers, row, HEADER_SLIDE_COUNTRY, config.presentation.country);
|
|
182
182
|
addColumn(headers, row, HEADER_SLIDE_MEDIA_TYPE, shared.mediaType ?? VEEVA_MEDIATYPE_HTML);
|
|
183
|
-
addColumn(headers, row, HEADER_SLIDE_FILE_NAME, pathToSlideZip(shared.path ?? 'shared'));
|
|
183
|
+
addColumn(headers, row, HEADER_SLIDE_FILE_NAME, pathToSlideZip(shared.zipFileName ?? shared.path ?? 'shared'));
|
|
184
184
|
addColumn(headers, row, HEADER_SLIDE_CLM_CONTENT, VEEVA_YES);
|
|
185
185
|
addColumn(headers, row, HEADER_SLIDE_CRM_SHARED, VEEVA_YES);
|
|
186
186
|
addColumn(headers, row, HEADER_LIFECYCLE, VEEVA_LIFECYCLE_CRM_CONTENT);
|
|
@@ -3,14 +3,18 @@ import { join } from 'node:path';
|
|
|
3
3
|
import Zip from 'adm-zip';
|
|
4
4
|
import logger from '../lib/logger.js';
|
|
5
5
|
import { pathToSlideZip } from '../lib/utils.js';
|
|
6
|
-
export default async function ({ deployDir }) {
|
|
6
|
+
export default async function ({ config, deployDir }) {
|
|
7
7
|
logger.info('Creating ZIP files');
|
|
8
8
|
const dirs = await readdir(deployDir);
|
|
9
9
|
for (const dir of dirs) {
|
|
10
10
|
const dirPath = join(deployDir, dir);
|
|
11
11
|
const zip = new Zip();
|
|
12
12
|
zip.addLocalFolder(dirPath);
|
|
13
|
-
await zip.writeZipPromise(join(deployDir,
|
|
13
|
+
await zip.writeZipPromise(join(deployDir, getZipFileName(config, dir)));
|
|
14
14
|
await rm(dirPath, { recursive: true });
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
+
function getZipFileName(config, dir) {
|
|
18
|
+
const zipFileName = dir === 'shared' ? config.presentation.shared?.zipFileName : config.presentation.slides.find(s => s.zipFileName === dir)?.zipFileName;
|
|
19
|
+
return pathToSlideZip(zipFileName ?? dir);
|
|
20
|
+
}
|
package/dist/tasks/deploy.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { mkdir, rm, readdir } from 'node:fs/promises';
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
4
5
|
import { preview } from "astro";
|
|
6
|
+
import { validateConfig } from "astro/config";
|
|
5
7
|
import parseArgv from '../lib/parse-argv.js';
|
|
6
8
|
import copyFiles from './copy-files.js';
|
|
7
9
|
import generateThumbs from './generate-thumbs.js';
|
|
@@ -15,10 +17,12 @@ const argv = parseArgv({
|
|
|
15
17
|
export default async function ({ root, config, env, csvOnly = false, serverPort = 4320 }) {
|
|
16
18
|
const rootDir = root ?? process.cwd();
|
|
17
19
|
// we could import the astro config and see if the outDir was set but right now it's not necessary
|
|
18
|
-
const
|
|
20
|
+
const astroConfig = await getAstroConfig(root);
|
|
21
|
+
const outDir = astroConfig ? fileURLToPath(astroConfig.outDir).replace(root, '') : 'dist';
|
|
22
|
+
const astroDistDir = join(rootDir, outDir);
|
|
19
23
|
const buildName = `${env}${config.presentation.isTraining === true ? '-training' : ''}`;
|
|
20
24
|
const buildType = argv.mode ?? buildName;
|
|
21
|
-
const deployDir = join(rootDir, 'deploy', buildType);
|
|
25
|
+
const deployDir = join(rootDir, outDir !== 'deploy' ? 'deploy' : 'deploy-veeva', buildType);
|
|
22
26
|
if (existsSync(deployDir)) {
|
|
23
27
|
const items = await readdir(deployDir);
|
|
24
28
|
for (const item of items) {
|
|
@@ -44,7 +48,28 @@ export default async function ({ root, config, env, csvOnly = false, serverPort
|
|
|
44
48
|
root
|
|
45
49
|
});
|
|
46
50
|
await server.stop();
|
|
47
|
-
await createZips({ deployDir });
|
|
51
|
+
await createZips({ config, deployDir });
|
|
48
52
|
}
|
|
49
53
|
await createCsv({ config, deployDir, buildName, fieldsOnly: csvOnly });
|
|
50
54
|
}
|
|
55
|
+
async function getAstroConfig(root) {
|
|
56
|
+
let config = undefined;
|
|
57
|
+
try {
|
|
58
|
+
config = await validateConfig({}, root, 'build');
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
console.error('Failed to parse Astro config');
|
|
62
|
+
}
|
|
63
|
+
return config;
|
|
64
|
+
// console.log('Searching for Astro config');
|
|
65
|
+
// const files = await readdir(root, { withFileTypes: true });
|
|
66
|
+
// const configFile = files.find((f) => {
|
|
67
|
+
// return f.isFile() || /^astro\.config\.(?:js|cjs|mjs|ts)$/i.test(f.name);
|
|
68
|
+
// });
|
|
69
|
+
// if (!configFile) {
|
|
70
|
+
// throw new Error('Could not locate Astro config file');
|
|
71
|
+
// }
|
|
72
|
+
// const { default: astroConfig } = await import(pathToFileURL(join(root, configFile.name)).toString());
|
|
73
|
+
// console.log(astroConfig);
|
|
74
|
+
// return astroConfig;
|
|
75
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { writeFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
2
|
+
import { extname, join } from "node:path";
|
|
3
3
|
import puppeteer from "puppeteer";
|
|
4
4
|
import sharp from 'sharp';
|
|
5
|
+
import { pdf } from "pdf-to-img";
|
|
5
6
|
import logger from '../lib/logger.js';
|
|
6
7
|
export default async function ({ config, root, deployDir, server }) {
|
|
7
8
|
logger.info('Generating thumbnails');
|
|
@@ -18,21 +19,41 @@ export default async function ({ config, root, deployDir, server }) {
|
|
|
18
19
|
});
|
|
19
20
|
try {
|
|
20
21
|
for (const slide of config.presentation.slides) {
|
|
22
|
+
if (slide.thumbnails === false)
|
|
23
|
+
continue;
|
|
24
|
+
// this shouldn't ever be the case after initThumbSettings runs but it keeps typescript happy
|
|
25
|
+
if (!slide.thumbnails || !slide.thumbnails.settings)
|
|
26
|
+
continue;
|
|
21
27
|
for (const settings of slide.thumbnails.settings) {
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const settingsPath = settings.path ?? slide.path;
|
|
29
|
+
const urlPath = `${settingsPath.startsWith('/') ? '' : '/'}${settingsPath}${extname(settingsPath) !== '' ? '' : '/'}`;
|
|
30
|
+
logger.info(`Generating ${urlPath}`);
|
|
31
|
+
let screenshot;
|
|
32
|
+
switch (slide.mediaType) {
|
|
33
|
+
case 'PDF': {
|
|
34
|
+
await using document = await pdf(join(deployDir, settingsPath), { scale: 2 });
|
|
35
|
+
screenshot = await document.getPage(1);
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
case 'HTML':
|
|
39
|
+
default: {
|
|
40
|
+
const url = `${server.protocol ?? 'http'}://${server.host}:${server.port}${urlPath}${settings.queryStringParams ? `?${objToQS(settings.queryStringParams)}` : ''}`;
|
|
41
|
+
await page.goto(url, {
|
|
42
|
+
waitUntil: 'networkidle0'
|
|
43
|
+
});
|
|
44
|
+
if (settings.delay && settings.delay > 0) {
|
|
45
|
+
logger.info(`Delaying thumbnail generation for ${settings.delay}ms`);
|
|
46
|
+
await sleep(settings.delay);
|
|
47
|
+
}
|
|
48
|
+
screenshot = await page.screenshot();
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
30
51
|
}
|
|
31
|
-
let screenshot = await page.screenshot();
|
|
32
52
|
let thumb = await (sharp(screenshot)
|
|
33
53
|
.resize({
|
|
34
54
|
width: settings.width,
|
|
35
|
-
height: settings.height
|
|
55
|
+
height: settings.height,
|
|
56
|
+
fit: 'inside'
|
|
36
57
|
})
|
|
37
58
|
.png({
|
|
38
59
|
palette: settings.palette ?? true,
|
|
@@ -165,6 +186,8 @@ function initThumbSettings(config) {
|
|
|
165
186
|
// }
|
|
166
187
|
// }
|
|
167
188
|
for (const slide of config.presentation.slides) {
|
|
189
|
+
if (slide.thumbnails === false)
|
|
190
|
+
continue;
|
|
168
191
|
if (!slide.thumbnails) {
|
|
169
192
|
slide.thumbnails = {};
|
|
170
193
|
}
|
|
@@ -200,6 +223,9 @@ function initThumbSettings(config) {
|
|
|
200
223
|
}
|
|
201
224
|
}
|
|
202
225
|
}
|
|
226
|
+
for (let i = 0; i < slide.thumbnails.settings.length; i++) {
|
|
227
|
+
slide.thumbnails.settings[i].width ??= config.thumbnails[0]?.width ?? DEFAULT_WIDTH;
|
|
228
|
+
}
|
|
203
229
|
}
|
|
204
230
|
}
|
|
205
231
|
function sleep(timeout = 0) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
2
3
|
import { join, extname } from 'node:path';
|
|
3
4
|
import logger from '../lib/logger.js';
|
|
4
5
|
export default async function ({ deployDir }) {
|
|
@@ -29,13 +30,19 @@ async function handleShared(deployDir, dir) {
|
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
async function handleHTML(deployDir, dir) {
|
|
32
|
-
|
|
33
|
+
const index = join(deployDir, dir, 'index.html');
|
|
34
|
+
if (!existsSync(index))
|
|
35
|
+
return;
|
|
36
|
+
await updateSharedPath(index);
|
|
33
37
|
}
|
|
34
38
|
async function updateSharedPath(filepath) {
|
|
35
39
|
const str = await readFile(filepath, 'utf8');
|
|
36
40
|
let shared = './shared/';
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
switch (extname(filepath)) {
|
|
42
|
+
case '.css':
|
|
43
|
+
case '.js':
|
|
44
|
+
shared = './';
|
|
45
|
+
break;
|
|
39
46
|
}
|
|
40
47
|
await writeFile(filepath, str.replace(/(?:\.*\/)*shared\//g, shared));
|
|
41
48
|
}
|
package/dist/types/config.d.ts
CHANGED
|
@@ -37,12 +37,14 @@ export interface ISlideThumbnailSettings {
|
|
|
37
37
|
export interface IVeevaConfigSlide extends IVeevaClmSlide {
|
|
38
38
|
path: string;
|
|
39
39
|
enableActions?: Actions[];
|
|
40
|
-
thumbnails?: ISlideThumbnailSettings;
|
|
40
|
+
thumbnails?: false | ISlideThumbnailSettings;
|
|
41
|
+
zipFileName?: string;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
export interface IVeevaConfigPresentation extends IVeevaClmPresentation {
|
|
44
45
|
shared?: IVeevaClmSharedResource & {
|
|
45
46
|
path?: string;
|
|
47
|
+
zipFileName?: string;
|
|
46
48
|
},
|
|
47
49
|
slides: IVeevaConfigSlide[]
|
|
48
50
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inizioevoke/veeva-astroclm-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@clack/prompts": "^1.4.0",
|
|
36
36
|
"adm-zip": "^0.5.17",
|
|
37
|
+
"pdf-to-img": "^7.0.0",
|
|
37
38
|
"puppeteer": "^24.43.1",
|
|
38
39
|
"sharp": "^0.34.5",
|
|
39
40
|
"yaml": "^2.9.0"
|
package/src/lib/utils.ts
CHANGED
|
@@ -5,7 +5,7 @@ export function formatExtId(...ids: string[]) {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export function pathToSlideZip(path: string) {
|
|
8
|
-
return `${flattenPath(path, { slashes: false })}.zip`;
|
|
8
|
+
return `${flattenPath(path, { slashes: false }).replace(/\.zip$/i,'')}.zip`;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export function flattenPath(path: string, { slashes = true }: { slashes?: boolean } = {}) {
|
package/src/tasks/create-csv.ts
CHANGED
|
@@ -229,7 +229,7 @@ function createSlideRow(headers: string[], config: IVeevaConfig, slide: IVeevaCo
|
|
|
229
229
|
disable.delete('Reactions');
|
|
230
230
|
addColumn(headers, row, HEADER_SLIDE_DISABLE_ACTIONS, [...disable].join(','));
|
|
231
231
|
|
|
232
|
-
addColumn(headers, row, HEADER_SLIDE_FILE_NAME, pathToSlideZip(slide.path));
|
|
232
|
+
addColumn(headers, row, HEADER_SLIDE_FILE_NAME, pathToSlideZip(slide.zipFileName ?? slide.path));
|
|
233
233
|
addColumn(headers, row, HEADER_SLIDE_RELATED_SHARED, config.presentation.shared?.externalId ?? '');
|
|
234
234
|
addColumn(headers, row, HEADER_SLIDE_CLM_CONTENT, VEEVA_YES);
|
|
235
235
|
addColumn(headers, row, HEADER_PRESENTATION, config.presentation.externalId);
|
|
@@ -260,7 +260,7 @@ function createSharedRow(headers: string[], config: IVeevaConfig, additional?: A
|
|
|
260
260
|
addColumn(headers, row, HEADER_SLIDE_PRODUCT, config.presentation.product);
|
|
261
261
|
addColumn(headers, row, HEADER_SLIDE_COUNTRY, config.presentation.country);
|
|
262
262
|
addColumn(headers, row, HEADER_SLIDE_MEDIA_TYPE, shared.mediaType ?? VEEVA_MEDIATYPE_HTML);
|
|
263
|
-
addColumn(headers, row, HEADER_SLIDE_FILE_NAME, pathToSlideZip(shared.path ?? 'shared'));
|
|
263
|
+
addColumn(headers, row, HEADER_SLIDE_FILE_NAME, pathToSlideZip(shared.zipFileName ?? shared.path ?? 'shared'));
|
|
264
264
|
addColumn(headers, row, HEADER_SLIDE_CLM_CONTENT, VEEVA_YES);
|
|
265
265
|
addColumn(headers, row, HEADER_SLIDE_CRM_SHARED, VEEVA_YES);
|
|
266
266
|
addColumn(headers, row, HEADER_LIFECYCLE, VEEVA_LIFECYCLE_CRM_CONTENT);
|
package/src/tasks/create-zips.ts
CHANGED
|
@@ -3,11 +3,13 @@ import { join } from 'node:path';
|
|
|
3
3
|
import Zip from 'adm-zip';
|
|
4
4
|
import logger from '../lib/logger.js';
|
|
5
5
|
import { pathToSlideZip } from '../lib/utils.js';
|
|
6
|
+
import { IVeevaConfig } from '../types';
|
|
6
7
|
|
|
7
8
|
interface Params {
|
|
9
|
+
config: IVeevaConfig;
|
|
8
10
|
deployDir: string;
|
|
9
11
|
}
|
|
10
|
-
export default async function({ deployDir }: Params) {
|
|
12
|
+
export default async function({ config, deployDir }: Params) {
|
|
11
13
|
logger.info('Creating ZIP files');
|
|
12
14
|
const dirs = await readdir(deployDir);
|
|
13
15
|
|
|
@@ -15,7 +17,13 @@ export default async function({ deployDir }: Params) {
|
|
|
15
17
|
const dirPath = join(deployDir, dir);
|
|
16
18
|
const zip = new Zip();
|
|
17
19
|
zip.addLocalFolder(dirPath);
|
|
18
|
-
await zip.writeZipPromise(join(deployDir,
|
|
20
|
+
await zip.writeZipPromise(join(deployDir, getZipFileName(config, dir)));
|
|
19
21
|
await rm(dirPath, { recursive: true });
|
|
20
22
|
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getZipFileName(config: IVeevaConfig, dir: string) {
|
|
26
|
+
const zipFileName = dir === 'shared' ? config.presentation.shared?.zipFileName : config.presentation.slides.find(s => s.zipFileName === dir)?.zipFileName;
|
|
27
|
+
|
|
28
|
+
return pathToSlideZip(zipFileName ?? dir);
|
|
21
29
|
}
|
package/src/tasks/deploy.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { mkdir, rm, readdir } from 'node:fs/promises';
|
|
3
|
-
import { join, resolve as resolvePath } from "node:path"
|
|
4
|
-
import {
|
|
3
|
+
import { join, resolve as resolvePath } from "node:path";
|
|
4
|
+
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
5
|
+
import { AstroConfig, preview } from "astro";
|
|
6
|
+
import { validateConfig } from "astro/config";
|
|
5
7
|
import { IVeevaConfig } from '../types';
|
|
6
8
|
import loadEnv from '../lib/env.js';
|
|
7
9
|
import logger from '../lib/logger.js';
|
|
@@ -29,10 +31,12 @@ interface Opts {
|
|
|
29
31
|
export default async function({ root, config, env, csvOnly = false, serverPort = 4320 }: Opts) {
|
|
30
32
|
const rootDir = root ?? process.cwd();
|
|
31
33
|
// we could import the astro config and see if the outDir was set but right now it's not necessary
|
|
32
|
-
const
|
|
34
|
+
const astroConfig = await getAstroConfig(root);
|
|
35
|
+
const outDir = astroConfig ? fileURLToPath(astroConfig.outDir).replace(root, '') : 'dist';
|
|
36
|
+
const astroDistDir = join(rootDir, outDir);
|
|
33
37
|
const buildName = `${env}${config.presentation.isTraining === true ? '-training' : ''}`;
|
|
34
38
|
const buildType = argv.mode ?? buildName;
|
|
35
|
-
const deployDir = join(rootDir, 'deploy', buildType);
|
|
39
|
+
const deployDir = join(rootDir, outDir !== 'deploy' ? 'deploy' : 'deploy-veeva', buildType);
|
|
36
40
|
|
|
37
41
|
if (existsSync(deployDir)) {
|
|
38
42
|
const items = await readdir(deployDir);
|
|
@@ -63,11 +67,31 @@ export default async function({ root, config, env, csvOnly = false, serverPort =
|
|
|
63
67
|
|
|
64
68
|
await server.stop();
|
|
65
69
|
|
|
66
|
-
await createZips({ deployDir });
|
|
70
|
+
await createZips({ config, deployDir });
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
await createCsv({ config, deployDir, buildName, fieldsOnly: csvOnly })
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
|
|
77
|
+
async function getAstroConfig(root: string) {
|
|
78
|
+
let config: AstroConfig | undefined = undefined;
|
|
79
|
+
try {
|
|
80
|
+
config = await validateConfig({}, root, 'build');
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.error('Failed to parse Astro config')
|
|
83
|
+
}
|
|
84
|
+
return config;
|
|
85
|
+
// console.log('Searching for Astro config');
|
|
86
|
+
// const files = await readdir(root, { withFileTypes: true });
|
|
87
|
+
// const configFile = files.find((f) => {
|
|
88
|
+
// return f.isFile() || /^astro\.config\.(?:js|cjs|mjs|ts)$/i.test(f.name);
|
|
89
|
+
// });
|
|
90
|
+
// if (!configFile) {
|
|
91
|
+
// throw new Error('Could not locate Astro config file');
|
|
92
|
+
// }
|
|
93
|
+
// const { default: astroConfig } = await import(pathToFileURL(join(root, configFile.name)).toString());
|
|
94
|
+
// console.log(astroConfig);
|
|
95
|
+
// return astroConfig;
|
|
96
|
+
}
|
|
73
97
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { writeFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
2
|
+
import { extname, join } from "node:path";
|
|
3
3
|
import puppeteer, { type Viewport } from "puppeteer";
|
|
4
4
|
import sharp from 'sharp';
|
|
5
|
+
import { pdf } from "pdf-to-img";
|
|
5
6
|
|
|
6
7
|
import logger from '../lib/logger.js';
|
|
7
8
|
import type { IVeevaConfig, IThumbnailSettings, IScreenshotSettings } from "../types";
|
|
@@ -34,23 +35,48 @@ export default async function({ config, root, deployDir, server }: Params) {
|
|
|
34
35
|
|
|
35
36
|
try {
|
|
36
37
|
for (const slide of config.presentation.slides) {
|
|
37
|
-
|
|
38
|
-
logger.info(`Generating /${settings.path ?? slide.path}/`);
|
|
39
|
-
const url = `${server.protocol ?? 'http'}://${server.host}:${server.port}/${settings.path ?? slide.path}/${settings.queryStringParams ? `?${objToQS(settings.queryStringParams)}` : ''}`
|
|
38
|
+
if (slide.thumbnails === false) continue;
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
// this shouldn't ever be the case after initThumbSettings runs but it keeps typescript happy
|
|
41
|
+
if (!slide.thumbnails || !slide.thumbnails.settings) continue;
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
for (const settings of slide.thumbnails.settings) {
|
|
47
|
+
const settingsPath = settings.path ?? slide.path;
|
|
48
|
+
const urlPath = `${settingsPath.startsWith('/') ? '' : '/'}${settingsPath}${extname(settingsPath) !== '' ? '' : '/'}`;
|
|
49
|
+
logger.info(`Generating ${urlPath}`);
|
|
50
|
+
|
|
51
|
+
let screenshot: Buffer | Uint8Array;
|
|
52
|
+
switch (slide.mediaType) {
|
|
53
|
+
case 'PDF': {
|
|
54
|
+
await using document = await pdf(join(deployDir, settingsPath), { scale: 2 });
|
|
55
|
+
screenshot = await document.getPage(1);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case 'HTML':
|
|
59
|
+
default: {
|
|
60
|
+
const url = `${server.protocol ?? 'http'}://${server.host}:${server.port}${urlPath}${settings.queryStringParams ? `?${objToQS(settings.queryStringParams)}` : ''}`
|
|
61
|
+
|
|
62
|
+
await page.goto(url, {
|
|
63
|
+
waitUntil: 'networkidle0'
|
|
64
|
+
});
|
|
65
|
+
if (settings.delay && settings.delay > 0) {
|
|
66
|
+
logger.info(`Delaying thumbnail generation for ${settings.delay}ms`);
|
|
67
|
+
await sleep(settings.delay);
|
|
68
|
+
}
|
|
69
|
+
screenshot = await page.screenshot();
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
47
72
|
}
|
|
48
|
-
|
|
73
|
+
|
|
49
74
|
let thumb = await (
|
|
50
75
|
sharp(screenshot)
|
|
51
76
|
.resize({
|
|
52
77
|
width: settings.width,
|
|
53
|
-
height: settings.height
|
|
78
|
+
height: settings.height,
|
|
79
|
+
fit: 'inside'
|
|
54
80
|
})
|
|
55
81
|
.png({
|
|
56
82
|
palette: settings.palette ?? true,
|
|
@@ -189,6 +215,8 @@ function initThumbSettings(config: IVeevaConfig) {
|
|
|
189
215
|
// }
|
|
190
216
|
|
|
191
217
|
for (const slide of config.presentation.slides) {
|
|
218
|
+
if (slide.thumbnails === false) continue;
|
|
219
|
+
|
|
192
220
|
if (!slide.thumbnails) {
|
|
193
221
|
slide.thumbnails = {};
|
|
194
222
|
}
|
|
@@ -224,6 +252,10 @@ function initThumbSettings(config: IVeevaConfig) {
|
|
|
224
252
|
}
|
|
225
253
|
}
|
|
226
254
|
}
|
|
255
|
+
for (let i=0; i<slide.thumbnails.settings.length; i++) {
|
|
256
|
+
slide.thumbnails.settings[i].width ??= config.thumbnails[0]?.width ?? DEFAULT_WIDTH;
|
|
257
|
+
|
|
258
|
+
}
|
|
227
259
|
}
|
|
228
260
|
|
|
229
261
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
2
3
|
import { join, extname } from 'node:path';
|
|
3
4
|
|
|
4
5
|
import logger from '../lib/logger.js';
|
|
@@ -36,14 +37,19 @@ async function handleShared(deployDir: string, dir: string) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
async function handleHTML(deployDir: string, dir: string) {
|
|
39
|
-
|
|
40
|
+
const index = join(deployDir, dir, 'index.html');
|
|
41
|
+
if (!existsSync(index)) return;
|
|
42
|
+
await updateSharedPath(index);
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
async function updateSharedPath(filepath: string) {
|
|
43
46
|
const str = await readFile(filepath, 'utf8');
|
|
44
47
|
let shared = './shared/';
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
switch (extname(filepath)) {
|
|
49
|
+
case '.css':
|
|
50
|
+
case '.js':
|
|
51
|
+
shared = './';
|
|
52
|
+
break;
|
|
47
53
|
}
|
|
48
54
|
await writeFile(filepath, str.replace(/(?:\.*\/)*shared\//g, shared));
|
|
49
55
|
}
|
package/src/types/config.d.ts
CHANGED
|
@@ -37,12 +37,14 @@ export interface ISlideThumbnailSettings {
|
|
|
37
37
|
export interface IVeevaConfigSlide extends IVeevaClmSlide {
|
|
38
38
|
path: string;
|
|
39
39
|
enableActions?: Actions[];
|
|
40
|
-
thumbnails?: ISlideThumbnailSettings;
|
|
40
|
+
thumbnails?: false | ISlideThumbnailSettings;
|
|
41
|
+
zipFileName?: string;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
export interface IVeevaConfigPresentation extends IVeevaClmPresentation {
|
|
44
45
|
shared?: IVeevaClmSharedResource & {
|
|
45
46
|
path?: string;
|
|
47
|
+
zipFileName?: string;
|
|
46
48
|
},
|
|
47
49
|
slides: IVeevaConfigSlide[]
|
|
48
50
|
}
|