@inizioevoke/veeva-astroclm-core 1.4.0 → 1.4.2
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/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 +29 -9
- package/package.json +17 -10
- package/src/apps/veeva-config-manager/templates/config.ts.txt +1 -0
- package/src/tasks/create-zips.ts +10 -2
- package/src/tasks/deploy.ts +29 -5
- package/src/tasks/generate-thumbs.ts +36 -10
|
@@ -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
|
+
}
|
|
@@ -2,6 +2,7 @@ import { writeFile } from "node:fs/promises";
|
|
|
2
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,25 +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
|
|
21
25
|
if (!slide.thumbnails || !slide.thumbnails.settings)
|
|
22
26
|
continue;
|
|
23
27
|
for (const settings of slide.thumbnails.settings) {
|
|
24
28
|
const settingsPath = settings.path ?? slide.path;
|
|
25
29
|
const urlPath = `${settingsPath.startsWith('/') ? '' : '/'}${settingsPath}${extname(settingsPath) !== '' ? '' : '/'}`;
|
|
26
30
|
logger.info(`Generating ${urlPath}`);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
+
}
|
|
34
51
|
}
|
|
35
|
-
let screenshot = await page.screenshot();
|
|
36
52
|
let thumb = await (sharp(screenshot)
|
|
37
53
|
.resize({
|
|
38
54
|
width: settings.width,
|
|
39
|
-
height: settings.height
|
|
55
|
+
height: settings.height,
|
|
56
|
+
fit: 'inside'
|
|
40
57
|
})
|
|
41
58
|
.png({
|
|
42
59
|
palette: settings.palette ?? true,
|
|
@@ -206,6 +223,9 @@ function initThumbSettings(config) {
|
|
|
206
223
|
}
|
|
207
224
|
}
|
|
208
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
|
+
}
|
|
209
229
|
}
|
|
210
230
|
}
|
|
211
231
|
function sleep(timeout = 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inizioevoke/veeva-astroclm-core",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "",
|
|
@@ -33,18 +33,25 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@clack/prompts": "^1.4.0",
|
|
36
|
-
"adm-zip": "^0.
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
36
|
+
"adm-zip": "^0.6.1",
|
|
37
|
+
"pdf-to-img": "^7.0.0",
|
|
38
|
+
"puppeteer": "^25.13.0",
|
|
39
|
+
"sharp": "^0.35.5",
|
|
40
|
+
"yaml": "^2.9.1"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
|
-
"@astrojs/check": "^0.9.
|
|
43
|
-
"@astrojs/ts-plugin": "^1.10.
|
|
43
|
+
"@astrojs/check": "^0.9.10",
|
|
44
|
+
"@astrojs/ts-plugin": "^1.10.12",
|
|
44
45
|
"@types/adm-zip": "^0.5.8",
|
|
45
|
-
"@types/node": "^
|
|
46
|
-
"astro": "^
|
|
47
|
-
"tsx": "^4.
|
|
46
|
+
"@types/node": "^26.6.4",
|
|
47
|
+
"astro": "^7.3.8",
|
|
48
|
+
"tsx": "^4.23.15",
|
|
48
49
|
"typescript": "^6.0.3"
|
|
50
|
+
},
|
|
51
|
+
"allowScripts": {
|
|
52
|
+
"sharp": true,
|
|
53
|
+
"esbuild": true,
|
|
54
|
+
"fsevents": true,
|
|
55
|
+
"puppeteer": true
|
|
49
56
|
}
|
|
50
57
|
}
|
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
|
|
|
@@ -2,6 +2,7 @@ import { writeFile } from "node:fs/promises";
|
|
|
2
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,27 +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
|
-
if (
|
|
38
|
+
if (slide.thumbnails === false) continue;
|
|
39
|
+
|
|
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
|
+
|
|
38
45
|
|
|
39
46
|
for (const settings of slide.thumbnails.settings) {
|
|
40
47
|
const settingsPath = settings.path ?? slide.path;
|
|
41
48
|
const urlPath = `${settingsPath.startsWith('/') ? '' : '/'}${settingsPath}${extname(settingsPath) !== '' ? '' : '/'}`;
|
|
42
49
|
logger.info(`Generating ${urlPath}`);
|
|
43
|
-
const url = `${server.protocol ?? 'http'}://${server.host}:${server.port}${urlPath}${settings.queryStringParams ? `?${objToQS(settings.queryStringParams)}` : ''}`
|
|
44
50
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
+
}
|
|
51
72
|
}
|
|
52
|
-
|
|
73
|
+
|
|
53
74
|
let thumb = await (
|
|
54
75
|
sharp(screenshot)
|
|
55
76
|
.resize({
|
|
56
77
|
width: settings.width,
|
|
57
|
-
height: settings.height
|
|
78
|
+
height: settings.height,
|
|
79
|
+
fit: 'inside'
|
|
58
80
|
})
|
|
59
81
|
.png({
|
|
60
82
|
palette: settings.palette ?? true,
|
|
@@ -230,6 +252,10 @@ function initThumbSettings(config: IVeevaConfig) {
|
|
|
230
252
|
}
|
|
231
253
|
}
|
|
232
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
|
+
}
|
|
233
259
|
}
|
|
234
260
|
|
|
235
261
|
}
|