@marvalt/digivalt-core 0.2.9 → 0.2.11
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/CHANGELOG.md +16 -0
- package/README.md +3 -1
- package/dist/generators/index.d.ts +1 -0
- package/dist/generators/sitemap-paths.d.ts +11 -0
- package/dist/generators.cjs +213 -0
- package/dist/generators.cjs.map +1 -1
- package/dist/generators.d.ts +14 -1
- package/dist/generators.esm.js +212 -1
- package/dist/generators.esm.js.map +1 -1
- package/dist/index.cjs +215 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +19 -9
- package/dist/index.esm.js +214 -1
- package/dist/index.esm.js.map +1 -1
- package/docs/SEO-PERFORMANCE.md +9 -1
- package/package.json +3 -2
- package/template/DIGIVALT_SETUP.md +1 -1
- package/template/functions/sitemap.xml.ts +1 -1
- package/template/public/sitemap-static-paths.json +3 -0
- package/template/scripts/deploy-secrets.js +9 -7
- package/template/scripts/generate.ts +9 -5
package/dist/index.d.ts
CHANGED
|
@@ -14,21 +14,31 @@ declare function generateSuiteCRMData(options?: {
|
|
|
14
14
|
outputPath?: string;
|
|
15
15
|
}): Promise<boolean>;
|
|
16
16
|
|
|
17
|
+
type GenerateSitemapPathsOptions = {
|
|
18
|
+
cwd?: string;
|
|
19
|
+
wpDataPath?: string;
|
|
20
|
+
staticInputPath?: string;
|
|
21
|
+
outputPath?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Merge sitemap-static-paths.json, navigation_menu URLs, and CPT/post links from wordpress-data.json.
|
|
25
|
+
*/
|
|
26
|
+
declare function generateSitemapPaths(options?: GenerateSitemapPathsOptions): Promise<void>;
|
|
27
|
+
declare function generateSitemapPathsSafe(options?: GenerateSitemapPathsOptions): Promise<void>;
|
|
28
|
+
|
|
17
29
|
declare function generateAllData(): Promise<void>;
|
|
18
30
|
|
|
31
|
+
type index_GenerateSitemapPathsOptions = GenerateSitemapPathsOptions;
|
|
19
32
|
declare const index_generateAllData: typeof generateAllData;
|
|
20
33
|
declare const index_generateGravityFormsData: typeof generateGravityFormsData;
|
|
21
34
|
declare const index_generateMauticData: typeof generateMauticData;
|
|
35
|
+
declare const index_generateSitemapPaths: typeof generateSitemapPaths;
|
|
36
|
+
declare const index_generateSitemapPathsSafe: typeof generateSitemapPathsSafe;
|
|
22
37
|
declare const index_generateSuiteCRMData: typeof generateSuiteCRMData;
|
|
23
38
|
declare const index_generateWordPressData: typeof generateWordPressData;
|
|
24
39
|
declare namespace index {
|
|
25
|
-
export {
|
|
26
|
-
|
|
27
|
-
index_generateGravityFormsData as generateGravityFormsData,
|
|
28
|
-
index_generateMauticData as generateMauticData,
|
|
29
|
-
index_generateSuiteCRMData as generateSuiteCRMData,
|
|
30
|
-
index_generateWordPressData as generateWordPressData,
|
|
31
|
-
};
|
|
40
|
+
export { index_generateAllData as generateAllData, index_generateGravityFormsData as generateGravityFormsData, index_generateMauticData as generateMauticData, index_generateSitemapPaths as generateSitemapPaths, index_generateSitemapPathsSafe as generateSitemapPathsSafe, index_generateSuiteCRMData as generateSuiteCRMData, index_generateWordPressData as generateWordPressData };
|
|
41
|
+
export type { index_GenerateSitemapPathsOptions as GenerateSitemapPathsOptions };
|
|
32
42
|
}
|
|
33
43
|
|
|
34
44
|
interface WordPressPost {
|
|
@@ -170,5 +180,5 @@ interface StaticDataStore {
|
|
|
170
180
|
*/
|
|
171
181
|
declare const getDigiValtVersion: () => string;
|
|
172
182
|
|
|
173
|
-
export { generateAllData, generateGravityFormsData, generateMauticData, generateSuiteCRMData, generateWordPressData, index as generators, getDigiValtVersion };
|
|
174
|
-
export type { KudoData, StaticDataConfig, StaticDataStore, Testimonial, WordPressCaseStudy, WordPressMember, WordPressPage, WordPressPost, WordPressProject };
|
|
183
|
+
export { generateAllData, generateGravityFormsData, generateMauticData, generateSitemapPaths, generateSitemapPathsSafe, generateSuiteCRMData, generateWordPressData, index as generators, getDigiValtVersion };
|
|
184
|
+
export type { GenerateSitemapPathsOptions, KudoData, StaticDataConfig, StaticDataStore, Testimonial, WordPressCaseStudy, WordPressMember, WordPressPage, WordPressPost, WordPressProject };
|
package/dist/index.esm.js
CHANGED
|
@@ -2451,6 +2451,216 @@ async function generateSuiteCRMData(options) {
|
|
|
2451
2451
|
}
|
|
2452
2452
|
}
|
|
2453
2453
|
|
|
2454
|
+
const SITEMAP_SKIP_TOP_LEVEL_KEYS = new Set([
|
|
2455
|
+
'config',
|
|
2456
|
+
'site_settings',
|
|
2457
|
+
'header',
|
|
2458
|
+
'footer',
|
|
2459
|
+
'theme_styles',
|
|
2460
|
+
'navigation_menu',
|
|
2461
|
+
'menus',
|
|
2462
|
+
'categories',
|
|
2463
|
+
'tags',
|
|
2464
|
+
'generated_at',
|
|
2465
|
+
'frontend_id',
|
|
2466
|
+
'frontend_name',
|
|
2467
|
+
'front_page',
|
|
2468
|
+
]);
|
|
2469
|
+
function normalizePathname(pathname) {
|
|
2470
|
+
const decoded = decodeURIComponent(pathname);
|
|
2471
|
+
if (!decoded || decoded === '/')
|
|
2472
|
+
return '/';
|
|
2473
|
+
const stripped = decoded.replace(/\/+$/, '');
|
|
2474
|
+
return stripped === '' ? '/' : stripped;
|
|
2475
|
+
}
|
|
2476
|
+
function getAllowedHosts() {
|
|
2477
|
+
const hosts = new Set();
|
|
2478
|
+
const api = process.env.VITE_WORDPRESS_API_URL || process.env.WORDPRESS_API_URL;
|
|
2479
|
+
if (api) {
|
|
2480
|
+
try {
|
|
2481
|
+
hosts.add(new URL(api).hostname);
|
|
2482
|
+
}
|
|
2483
|
+
catch {
|
|
2484
|
+
/* ignore */
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
return hosts;
|
|
2488
|
+
}
|
|
2489
|
+
/**
|
|
2490
|
+
* When CMS host is unknown, accept any http(s) URL so local/offline merges still produce paths.
|
|
2491
|
+
*/
|
|
2492
|
+
function urlToPath(urlStr, allowedHosts) {
|
|
2493
|
+
const t = urlStr.trim();
|
|
2494
|
+
if (!t || t === '#' || t.toLowerCase().startsWith('mailto:') || t.toLowerCase().startsWith('tel:')) {
|
|
2495
|
+
return null;
|
|
2496
|
+
}
|
|
2497
|
+
if (!/^https?:\/\//i.test(t)) {
|
|
2498
|
+
return null;
|
|
2499
|
+
}
|
|
2500
|
+
let u;
|
|
2501
|
+
try {
|
|
2502
|
+
u = new URL(t);
|
|
2503
|
+
}
|
|
2504
|
+
catch {
|
|
2505
|
+
return null;
|
|
2506
|
+
}
|
|
2507
|
+
if (allowedHosts.size > 0 && !allowedHosts.has(u.hostname)) {
|
|
2508
|
+
return null;
|
|
2509
|
+
}
|
|
2510
|
+
return normalizePathname(u.pathname);
|
|
2511
|
+
}
|
|
2512
|
+
function parsePathsJson(raw) {
|
|
2513
|
+
try {
|
|
2514
|
+
const data = JSON.parse(raw);
|
|
2515
|
+
if (Array.isArray(data)) {
|
|
2516
|
+
return data.filter((p) => typeof p === 'string' && p.startsWith('/'));
|
|
2517
|
+
}
|
|
2518
|
+
if (data && typeof data === 'object' && Array.isArray(data.paths)) {
|
|
2519
|
+
return data.paths.filter((p) => typeof p === 'string' && p.startsWith('/'));
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
catch {
|
|
2523
|
+
/* ignore */
|
|
2524
|
+
}
|
|
2525
|
+
return [];
|
|
2526
|
+
}
|
|
2527
|
+
function loadStaticPaths(cwd, staticInputPath, allowedHosts) {
|
|
2528
|
+
const full = path.join(cwd, staticInputPath);
|
|
2529
|
+
if (!fs.existsSync(full)) {
|
|
2530
|
+
return [];
|
|
2531
|
+
}
|
|
2532
|
+
const raw = fs.readFileSync(full, 'utf8');
|
|
2533
|
+
const paths = parsePathsJson(raw);
|
|
2534
|
+
const out = [];
|
|
2535
|
+
for (const p of paths) {
|
|
2536
|
+
if (p.startsWith('http://') || p.startsWith('https://')) {
|
|
2537
|
+
const normalized = urlToPath(p, allowedHosts);
|
|
2538
|
+
if (normalized)
|
|
2539
|
+
out.push(normalized);
|
|
2540
|
+
}
|
|
2541
|
+
else {
|
|
2542
|
+
out.push(normalizePathname(p));
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
return out;
|
|
2546
|
+
}
|
|
2547
|
+
function walkMenuItems(items, allowedHosts, out) {
|
|
2548
|
+
if (!Array.isArray(items))
|
|
2549
|
+
return;
|
|
2550
|
+
for (const item of items) {
|
|
2551
|
+
if (!item || typeof item !== 'object')
|
|
2552
|
+
continue;
|
|
2553
|
+
const rec = item;
|
|
2554
|
+
if (typeof rec.url === 'string') {
|
|
2555
|
+
const p = urlToPath(rec.url, allowedHosts);
|
|
2556
|
+
if (p)
|
|
2557
|
+
out.add(p);
|
|
2558
|
+
}
|
|
2559
|
+
if (Array.isArray(rec.children)) {
|
|
2560
|
+
walkMenuItems(rec.children, allowedHosts, out);
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
function collectLinksFromArray(arr, allowedHosts, out) {
|
|
2565
|
+
for (const item of arr) {
|
|
2566
|
+
if (!item || typeof item !== 'object')
|
|
2567
|
+
continue;
|
|
2568
|
+
const link = item.link;
|
|
2569
|
+
if (typeof link === 'string') {
|
|
2570
|
+
const p = urlToPath(link, allowedHosts);
|
|
2571
|
+
if (p)
|
|
2572
|
+
out.add(p);
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
function collectPathsFromWpData(data, allowedHosts) {
|
|
2577
|
+
const out = new Set();
|
|
2578
|
+
const menu = data.navigation_menu;
|
|
2579
|
+
if (menu?.items) {
|
|
2580
|
+
walkMenuItems(menu.items, allowedHosts, out);
|
|
2581
|
+
}
|
|
2582
|
+
const config = data.config;
|
|
2583
|
+
const postTypeKeys = config?.post_types && typeof config.post_types === 'object'
|
|
2584
|
+
? Object.keys(config.post_types)
|
|
2585
|
+
: null;
|
|
2586
|
+
if (postTypeKeys && postTypeKeys.length > 0) {
|
|
2587
|
+
for (const key of postTypeKeys) {
|
|
2588
|
+
const arr = data[key];
|
|
2589
|
+
if (Array.isArray(arr)) {
|
|
2590
|
+
collectLinksFromArray(arr, allowedHosts, out);
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
else {
|
|
2595
|
+
for (const [key, value] of Object.entries(data)) {
|
|
2596
|
+
if (SITEMAP_SKIP_TOP_LEVEL_KEYS.has(key))
|
|
2597
|
+
continue;
|
|
2598
|
+
if (Array.isArray(value)) {
|
|
2599
|
+
collectLinksFromArray(value, allowedHosts, out);
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
return out;
|
|
2604
|
+
}
|
|
2605
|
+
function writeFallback(cwd, outputPath) {
|
|
2606
|
+
const full = path.join(cwd, outputPath);
|
|
2607
|
+
fs.mkdirSync(path.dirname(full), { recursive: true });
|
|
2608
|
+
fs.writeFileSync(full, `${JSON.stringify({ paths: ['/'] }, null, 2)}\n`, 'utf8');
|
|
2609
|
+
}
|
|
2610
|
+
/**
|
|
2611
|
+
* Merge sitemap-static-paths.json, navigation_menu URLs, and CPT/post links from wordpress-data.json.
|
|
2612
|
+
*/
|
|
2613
|
+
async function generateSitemapPaths(options = {}) {
|
|
2614
|
+
dotenv.config();
|
|
2615
|
+
dotenv.config({ path: '.env.local' });
|
|
2616
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2617
|
+
const wpDataPath = options.wpDataPath ?? 'public/wordpress-data.json';
|
|
2618
|
+
const staticInputPath = options.staticInputPath ?? 'public/sitemap-static-paths.json';
|
|
2619
|
+
const outputPath = options.outputPath ?? 'public/sitemap-paths.json';
|
|
2620
|
+
const allowedHosts = getAllowedHosts();
|
|
2621
|
+
const merged = new Set();
|
|
2622
|
+
for (const p of loadStaticPaths(cwd, staticInputPath, allowedHosts)) {
|
|
2623
|
+
merged.add(normalizePathname(p));
|
|
2624
|
+
}
|
|
2625
|
+
const wpFull = path.join(cwd, wpDataPath);
|
|
2626
|
+
if (fs.existsSync(wpFull)) {
|
|
2627
|
+
try {
|
|
2628
|
+
const raw = fs.readFileSync(wpFull, 'utf8');
|
|
2629
|
+
const data = JSON.parse(raw);
|
|
2630
|
+
const fromWp = collectPathsFromWpData(data, allowedHosts);
|
|
2631
|
+
for (const p of fromWp) {
|
|
2632
|
+
merged.add(p);
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
catch (e) {
|
|
2636
|
+
console.warn('⚠️ Could not parse wordpress-data.json for sitemap paths:', e.message);
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
merged.add('/');
|
|
2640
|
+
const sorted = [...merged].sort((a, b) => {
|
|
2641
|
+
if (a === '/')
|
|
2642
|
+
return -1;
|
|
2643
|
+
if (b === '/')
|
|
2644
|
+
return 1;
|
|
2645
|
+
return a.localeCompare(b);
|
|
2646
|
+
});
|
|
2647
|
+
const outFull = path.join(cwd, outputPath);
|
|
2648
|
+
fs.mkdirSync(path.dirname(outFull), { recursive: true });
|
|
2649
|
+
fs.writeFileSync(outFull, `${JSON.stringify({ paths: sorted }, null, 2)}\n`, 'utf8');
|
|
2650
|
+
console.log(`📍 Sitemap paths written (${sorted.length} URLs): ${outFull}`);
|
|
2651
|
+
}
|
|
2652
|
+
async function generateSitemapPathsSafe(options = {}) {
|
|
2653
|
+
try {
|
|
2654
|
+
await generateSitemapPaths(options);
|
|
2655
|
+
}
|
|
2656
|
+
catch (e) {
|
|
2657
|
+
console.error('❌ Sitemap path generation failed; writing minimal / only:', e.message);
|
|
2658
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2659
|
+
const outputPath = options.outputPath ?? 'public/sitemap-paths.json';
|
|
2660
|
+
writeFallback(cwd, outputPath);
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2454
2664
|
async function generateAllData() {
|
|
2455
2665
|
// Load .env files if they exist (for local development)
|
|
2456
2666
|
dotenv.config();
|
|
@@ -2468,6 +2678,7 @@ async function generateAllData() {
|
|
|
2468
2678
|
console.error('❌ Some generation tasks failed. See above for details.');
|
|
2469
2679
|
process.exit(1);
|
|
2470
2680
|
}
|
|
2681
|
+
await generateSitemapPathsSafe();
|
|
2471
2682
|
console.log('✅ Generation complete!');
|
|
2472
2683
|
}
|
|
2473
2684
|
|
|
@@ -2476,6 +2687,8 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
2476
2687
|
generateAllData: generateAllData,
|
|
2477
2688
|
generateGravityFormsData: generateGravityFormsData,
|
|
2478
2689
|
generateMauticData: generateMauticData,
|
|
2690
|
+
generateSitemapPaths: generateSitemapPaths,
|
|
2691
|
+
generateSitemapPathsSafe: generateSitemapPathsSafe,
|
|
2479
2692
|
generateSuiteCRMData: generateSuiteCRMData,
|
|
2480
2693
|
generateWordPressData: generateWordPressData
|
|
2481
2694
|
});
|
|
@@ -2488,5 +2701,5 @@ const getDigiValtVersion = () => {
|
|
|
2488
2701
|
return "0.2.6";
|
|
2489
2702
|
};
|
|
2490
2703
|
|
|
2491
|
-
export { generateAllData, generateGravityFormsData, generateMauticData, generateSuiteCRMData, generateWordPressData, index as generators, getDigiValtVersion };
|
|
2704
|
+
export { generateAllData, generateGravityFormsData, generateMauticData, generateSitemapPaths, generateSitemapPathsSafe, generateSuiteCRMData, generateWordPressData, index as generators, getDigiValtVersion };
|
|
2492
2705
|
//# sourceMappingURL=index.esm.js.map
|