@hkdigital/lib-core 0.5.94 → 0.5.95

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.
@@ -0,0 +1,150 @@
1
+ # Meta Configuration Template
2
+
3
+ This template provides a complete setup for SEO, PWA, and favicon configuration in your SvelteKit project.
4
+
5
+ ## Quick Start
6
+
7
+ ### 1. Copy template files to your project
8
+
9
+ ```bash
10
+ # From your project root
11
+ cp -r node_modules/@hkdigital/lib-core/meta/templates/lib/* src/lib/
12
+ cp -r node_modules/@hkdigital/lib-core/meta/templates/routes/* src/routes/
13
+ ```
14
+
15
+ This copies:
16
+ - `src/lib/config/meta.js` - Your configuration file
17
+ - `src/lib/assets/meta/*.png` - Placeholder images
18
+ - `src/lib/meta.js` - Glue file connecting library and config
19
+ - `src/routes/(meta)/*.json/+server.js` - Route endpoints
20
+
21
+ ### 2. Customize your configuration
22
+
23
+ Edit `src/lib/config/meta.js` with your app's information:
24
+
25
+ ```javascript
26
+ export const name = 'Your App Name';
27
+ export const shortName = 'YourApp';
28
+ export const description = 'Your app description';
29
+ export const backgroundAndThemeColor = '#your-color';
30
+ // ... etc
31
+ ```
32
+
33
+ ### 3. Replace placeholder images
34
+
35
+ Replace these files in `src/lib/assets/meta/` with your own:
36
+ - `favicon.png` - 512×512px or larger (PNG with transparency)
37
+ - `preview-landscape.png` - 1200×630px landscape preview (JPG or PNG)
38
+ - `preview-square.png` - 1200×1200px square preview (JPG or PNG)
39
+
40
+ ### 4. Add to your root layout
41
+
42
+ In `src/routes/+layout.svelte`:
43
+
44
+ ```svelte
45
+ <script>
46
+ import { Favicons, PWA, SEO, config } from '$lib/meta.js';
47
+
48
+ let { children, data } = $props();
49
+ </script>
50
+
51
+ <Favicons {config} />
52
+ <PWA {config} />
53
+ <SEO {config} locale={data?.locale} />
54
+
55
+ {@render children()}
56
+ ```
57
+
58
+ ### 5. Update app.html
59
+
60
+ Add placeholders to `src/app.html`:
61
+
62
+ ```html
63
+ <!doctype html>
64
+ <html lang="%lang%">
65
+ <head>
66
+ <meta charset="utf-8" />
67
+ <title>%title%</title>
68
+ <meta name="description" content="%description%">
69
+ %sveltekit.head%
70
+ </head>
71
+ <body>
72
+ %sveltekit.body%
73
+ </body>
74
+ </html>
75
+ ```
76
+
77
+ ### 6. Configure hooks (optional)
78
+
79
+ For language detection, add to `src/hooks.server.js`:
80
+
81
+ ```javascript
82
+ import { handleLang } from '$lib/meta.js';
83
+
84
+ export async function handle({ event, resolve }) {
85
+ return handleLang(event, resolve);
86
+ }
87
+ ```
88
+
89
+ ## File Structure
90
+
91
+ After copying the template, your project will have:
92
+
93
+ ```
94
+ src/
95
+ lib/
96
+ config/
97
+ meta.js # Your configuration (customize this)
98
+ assets/
99
+ meta/
100
+ favicon.png # Your favicon image
101
+ preview-landscape.png
102
+ preview-square.png
103
+ meta.js # Glue file (imports library + config)
104
+ routes/
105
+ (meta)/ # Route group (not in URL)
106
+ manifest.json/
107
+ +server.js # PWA manifest endpoint
108
+ robots.txt/
109
+ +server.js # Robots.txt endpoint
110
+ sitemap.xml/
111
+ +server.js # Sitemap endpoint
112
+ +layout.svelte # Import from $lib/meta.js
113
+ hooks.server.js # Optional: language detection
114
+ app.html # Add %lang%, %title%, %description%
115
+ ```
116
+
117
+ ## How It Works
118
+
119
+ **Library code** (automatically updated):
120
+ - Components imported from `@hkdigital/lib-core/meta/components`
121
+ - Utilities imported from `@hkdigital/lib-core/meta/utils`
122
+ - When you update the library, components get bug fixes automatically
123
+
124
+ **Your code** (you customize):
125
+ - `src/lib/config/meta.js` - Your app's configuration
126
+ - `src/lib/assets/meta/*.png` - Your images
127
+ - `src/lib/meta.js` - Connects library components with your config
128
+ - `src/routes/(meta)/` - Route endpoints that use your config
129
+
130
+ ## Configuration Not in Routes
131
+
132
+ Note that `config/meta.js` is in `src/lib/`, NOT in `src/routes/`. This is intentional:
133
+
134
+ - Files in `src/routes/` can be served via HTTP
135
+ - Route groups like `(meta)` only affect layout grouping, not HTTP access
136
+ - Keeping config in `src/lib/` prevents accidental HTTP exposure
137
+ - Images in `src/lib/assets/` are processed by Vite imagetools at build time
138
+
139
+ ## Updating
140
+
141
+ When you update `@hkdigital/lib-core`:
142
+ 1. Library components are automatically updated
143
+ 2. Your config and images remain untouched
144
+ 3. Check changelog for breaking config changes
145
+
146
+ ## Documentation
147
+
148
+ For complete documentation, see:
149
+ - Main docs: `node_modules/@hkdigital/lib-core/meta/README.md`
150
+ - Component API: Check library source in `node_modules/@hkdigital/lib-core/meta/`
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Meta configuration
3
+ *
4
+ * Customize this file with your app's information.
5
+ * After copying to your project, update all values below.
6
+ */
7
+ /**
8
+ * App identity
9
+ */
10
+ export const name: "Your App Name";
11
+ export const shortName: "YourApp";
12
+ export const description: "Your app description for search engines";
13
+ /**
14
+ * Language and locale configuration
15
+ *
16
+ * @type {Record<string, {lang: string, locale: string}>}
17
+ */
18
+ export const languages: Record<string, {
19
+ lang: string;
20
+ locale: string;
21
+ }>;
22
+ export const defaultLanguage: "en";
23
+ export const defaultLocale: string;
24
+ /**
25
+ * PWA theme and colors
26
+ */
27
+ export const backgroundAndThemeColor: "#082962";
28
+ export const themeColor: "#082962";
29
+ export const backgroundColor: "#082962";
30
+ /**
31
+ * iOS PWA configuration
32
+ */
33
+ export const statusBarStyle: "black-translucent";
34
+ /**
35
+ * Screen orientation
36
+ */
37
+ export const orientation: "any";
38
+ /**
39
+ * Disable pinch-to-zoom
40
+ *
41
+ * Only enable for games or canvas apps where zoom breaks functionality
42
+ */
43
+ export const disablePageZoom: false;
44
+ export const SeoImageLandscape: string;
45
+ export const SeoImageSquare: string;
46
+ export const faviconImages: import("../../../../config/typedef").ImageSource;
47
+ export const appleTouchIcons: import("../../../../config/typedef").ImageSource;
48
+ /**
49
+ * Site routes for sitemap.xml
50
+ *
51
+ * @type {import('../../../typedef.js').SitemapRoute[]}
52
+ *
53
+ * @see @hkdigital/lib-core/meta/README.md for configuration options
54
+ */
55
+ export const siteRoutes: import("../../../typedef.js").SitemapRoute[];
56
+ /**
57
+ * Robots.txt configuration
58
+ *
59
+ * @type {import('../../../typedef.js').RobotsConfig}
60
+ *
61
+ * @see @hkdigital/lib-core/meta/README.md for configuration options
62
+ */
63
+ export const robotsConfig: import("../../../typedef.js").RobotsConfig;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Meta configuration
3
+ *
4
+ * Customize this file with your app's information.
5
+ * After copying to your project, update all values below.
6
+ */
7
+
8
+ /**
9
+ * App identity
10
+ */
11
+ export const name = 'Your App Name';
12
+ export const shortName = 'YourApp'; // max 12 characters
13
+ export const description = 'Your app description for search engines';
14
+
15
+ /**
16
+ * Language and locale configuration
17
+ *
18
+ * @type {Record<string, {lang: string, locale: string}>}
19
+ */
20
+ export const languages = {
21
+ 'en': { lang: 'en-GB', locale: 'en_GB' },
22
+ 'nl': { lang: 'nl-NL', locale: 'nl_NL' }
23
+
24
+ // Add more languages as needed:
25
+ // 'es': { lang: 'es-ES', locale: 'es_ES' },
26
+ // 'en-us': { lang: 'en-US', locale: 'en_US' }
27
+ };
28
+
29
+ export const defaultLanguage = 'en';
30
+ export const defaultLocale = languages[defaultLanguage].locale;
31
+
32
+ /**
33
+ * PWA theme and colors
34
+ */
35
+ export const backgroundAndThemeColor = '#082962';
36
+ export const themeColor = backgroundAndThemeColor;
37
+ export const backgroundColor = backgroundAndThemeColor;
38
+
39
+ /**
40
+ * iOS PWA configuration
41
+ */
42
+ export const statusBarStyle = 'black-translucent'; // 'default' | 'black' | 'black-translucent'
43
+
44
+ /**
45
+ * Screen orientation
46
+ */
47
+ export const orientation = 'any'; // 'any' | 'landscape' | 'portrait'
48
+
49
+ /**
50
+ * Disable pinch-to-zoom
51
+ *
52
+ * Only enable for games or canvas apps where zoom breaks functionality
53
+ */
54
+ export const disablePageZoom = false;
55
+
56
+ /**
57
+ * SEO social media preview images
58
+ *
59
+ * Replace the image files with your own designs.
60
+ * The images are processed by Vite imagetools to correct dimensions.
61
+ *
62
+ * To disable: comment out imports and set to null
63
+ */
64
+ import SeoLandscapeImg from '../../../../assets/meta/preview-landscape.png?seo-landscape';
65
+ import SeoSquareImg from '../../../../assets/meta/preview-square.png?seo-square';
66
+
67
+ export const SeoImageLandscape = SeoLandscapeImg; // 1200×630
68
+ export const SeoImageSquare = SeoSquareImg; // 1200×1200
69
+
70
+ // To disable SEO images:
71
+ // export const SeoImageLandscape = null;
72
+ // export const SeoImageSquare = null;
73
+
74
+ /**
75
+ * Favicon images (processed by Vite imagetools)
76
+ */
77
+ import FaviconImgs from '../../../../assets/meta/favicon.png?favicons';
78
+ import AppleTouchImgs from '../../../../assets/meta/favicon.png?apple-touch-icons';
79
+
80
+ export const faviconImages = FaviconImgs;
81
+ export const appleTouchIcons = AppleTouchImgs;
82
+
83
+ /**
84
+ * Site routes for sitemap.xml
85
+ *
86
+ * @type {import('../../../typedef.js').SitemapRoute[]}
87
+ *
88
+ * @see @hkdigital/lib-core/meta/README.md for configuration options
89
+ */
90
+ export const siteRoutes = [
91
+ '/'
92
+ // Add your routes:
93
+ // '/about',
94
+ // '/contact',
95
+ // { path: '/blog', priority: 0.9, changefreq: 'daily' }
96
+ ];
97
+
98
+ /**
99
+ * Robots.txt configuration
100
+ *
101
+ * @type {import('../../../typedef.js').RobotsConfig}
102
+ *
103
+ * @see @hkdigital/lib-core/meta/README.md for configuration options
104
+ */
105
+ export const robotsConfig = {
106
+ allowedHosts: '*', // '*' allows all hosts
107
+ disallowedPaths: [], // e.g., ['/admin', '/api']
108
+
109
+ // AI bot control (site-wide via robots.txt)
110
+ allowAiTraining: true, // GPTBot, Google-Extended, CCBot, anthropic-ai
111
+ allowAiReading: true // ChatGPT-User, Claude-Web, cohere-ai
112
+ };
@@ -0,0 +1,7 @@
1
+ import { Favicons } from '../../components.js';
2
+ import { PWA } from '../../components.js';
3
+ import { SEO } from '../../components.js';
4
+ export const getLangFromPath: Function;
5
+ export const injectLang: Function;
6
+ export const handleLang: Function;
7
+ export { Favicons, PWA, SEO, config };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Meta components configured for your app
3
+ *
4
+ * This file imports the library components and configures them with your
5
+ * app's config. Components are automatically updated when you update the
6
+ * @hkdigital/lib-core library.
7
+ */
8
+
9
+ import { Favicons, PWA, SEO } from '../../components.js';
10
+ import { createLangUtils } from '../../utils.js';
11
+ import * as config from '../../../config/meta.js';
12
+
13
+ // Create configured language utilities
14
+ const { getLangFromPath, injectLang, handleLang } = createLangUtils(config);
15
+
16
+ // Re-export components (they'll receive config as a prop in your layout)
17
+ export { Favicons, PWA, SEO };
18
+
19
+ // Export language utilities
20
+ export { getLangFromPath, injectLang, handleLang };
21
+
22
+ // Export config for convenience
23
+ export { config };
@@ -0,0 +1,2 @@
1
+ /** @type {import('@sveltejs/kit').RequestHandler} */
2
+ export const GET: import("@sveltejs/kit").RequestHandler;
@@ -0,0 +1,42 @@
1
+ // @see https://developer.mozilla.org/en-US/docs/
2
+ // Web/Progressive_web_apps/Manifest/Reference
3
+
4
+ import {
5
+ name,
6
+ shortName,
7
+ description,
8
+ backgroundAndThemeColor,
9
+ orientation
10
+ } from '../../../../../config/meta.js';
11
+
12
+ import faviconImages from '../../../../../assets/meta/favicon.png?favicons';
13
+
14
+ /* Generate manifest data */
15
+
16
+ const manifest = {
17
+ name,
18
+ short_name: shortName,
19
+ description,
20
+
21
+ start_url: '/',
22
+ scope: '/',
23
+
24
+ icons: faviconImages.map((item) => {
25
+ return {
26
+ src: item.src,
27
+ sizes: `${item.width}x${item.width}`,
28
+ type: 'image/png'
29
+ };
30
+ }),
31
+
32
+ theme_color: backgroundAndThemeColor,
33
+ background_color: backgroundAndThemeColor,
34
+
35
+ display: 'fullscreen',
36
+ orientation
37
+ };
38
+
39
+ /** @type {import('@sveltejs/kit').RequestHandler} */
40
+ export const GET = async () => {
41
+ return new Response(JSON.stringify(manifest));
42
+ };
@@ -0,0 +1,2 @@
1
+ /** @type {import('@sveltejs/kit').RequestHandler} */
2
+ export const GET: import("@sveltejs/kit").RequestHandler;
@@ -0,0 +1,9 @@
1
+ import { text } from '@sveltejs/kit';
2
+ import { generateRobotsTxt } from '../../../../utils.js';
3
+ import { robotsConfig } from '../../../../../config/meta.js';
4
+
5
+ /** @type {import('@sveltejs/kit').RequestHandler} */
6
+ export const GET = async ({ url }) => {
7
+ const robotsTxt = generateRobotsTxt(url, robotsConfig);
8
+ return text(robotsTxt);
9
+ };
@@ -0,0 +1,2 @@
1
+ /** @type {import('@sveltejs/kit').RequestHandler} */
2
+ export const GET: import("@sveltejs/kit").RequestHandler;
@@ -0,0 +1,14 @@
1
+ import { generateSitemap } from '../../../../utils.js';
2
+ import { siteRoutes } from '../../../../../config/meta.js';
3
+
4
+ /** @type {import('@sveltejs/kit').RequestHandler} */
5
+ export const GET = async ({ url }) => {
6
+ const sitemap = generateSitemap(url.origin, siteRoutes);
7
+
8
+ return new Response(sitemap, {
9
+ headers: {
10
+ 'Content-Type': 'application/xml',
11
+ 'Cache-Control': 'max-age=0, s-maxage=3600'
12
+ }
13
+ });
14
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-core",
3
- "version": "0.5.94",
3
+ "version": "0.5.95",
4
4
  "author": {
5
5
  "name": "HKdigital",
6
6
  "url": "https://hkdigital.nl"
@@ -41,13 +41,13 @@
41
41
  "cache:clear": "rm -rf node_modules/.cache/imagetools",
42
42
  "lint:prettier": "prettier --check .",
43
43
  "lint:eslint": "eslint .",
44
- "lint:imports": "node scripts/validate-imports.mjs",
44
+ "lint:imports": "node scripts/validate-imports.mjs --exclude src/lib/meta/templates",
45
45
  "test:unit": "vitest",
46
46
  "test:unit-run": "pnpm run test:unit -- --run",
47
47
  "prepack:sync": "svelte-kit sync",
48
48
  "prepack:build": "svelte-package",
49
49
  "prepack:lint": "publint",
50
- "prepack:imports": "node scripts/validate-imports.mjs",
50
+ "prepack:imports": "node scripts/validate-imports.mjs --exclude src/lib/meta/templates",
51
51
  "publish:npm:version": "npm version patch",
52
52
  "publish:npm:publish": "npm publish --access public",
53
53
  "upgrade:hk:update": "ncu --dep dev,optional,peer,prod '@hkdigital/*' -u",
@@ -9,6 +9,27 @@ const SRC_DIR = join(PROJECT_ROOT, 'src');
9
9
  const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
10
10
  const LIB_ROOT = dirname(SCRIPT_DIR);
11
11
 
12
+ /**
13
+ * Parse command line arguments for exclusion patterns
14
+ *
15
+ * @returns {string[]} Array of path patterns to exclude
16
+ */
17
+ function parseExclusionArgs() {
18
+ const args = process.argv.slice(2);
19
+ const exclusions = [];
20
+
21
+ for (let i = 0; i < args.length; i++) {
22
+ if (args[i] === '--exclude' && i + 1 < args.length) {
23
+ exclusions.push(args[i + 1]);
24
+ i++; // Skip next arg since we consumed it
25
+ }
26
+ }
27
+
28
+ return exclusions;
29
+ }
30
+
31
+ const EXCLUSION_PATTERNS = parseExclusionArgs();
32
+
12
33
  /**
13
34
  * Scopes to validate for barrel exports
14
35
  * Any package under these scopes will be checked
@@ -555,6 +576,25 @@ async function findAliasBarrelExport(importPath, targetName) {
555
576
  return null;
556
577
  }
557
578
 
579
+ /**
580
+ * Check if file path matches any exclusion pattern
581
+ *
582
+ * @param {string} filePath - Path to check
583
+ *
584
+ * @returns {boolean} True if file should be excluded
585
+ */
586
+ function isExcluded(filePath) {
587
+ const relativePath = relative(PROJECT_ROOT, filePath);
588
+
589
+ for (const pattern of EXCLUSION_PATTERNS) {
590
+ if (relativePath.includes(pattern)) {
591
+ return true;
592
+ }
593
+ }
594
+
595
+ return false;
596
+ }
597
+
558
598
  /**
559
599
  * Validate import paths in a file
560
600
  *
@@ -563,6 +603,11 @@ async function findAliasBarrelExport(importPath, targetName) {
563
603
  * @returns {Promise<string[]>} Array of error messages
564
604
  */
565
605
  async function validateFile(filePath) {
606
+ // Skip excluded files
607
+ if (isExcluded(filePath)) {
608
+ return [];
609
+ }
610
+
566
611
  const content = await readFile(filePath, 'utf-8');
567
612
  const errors = [];
568
613
  const relativePath = relative(PROJECT_ROOT, filePath);
@@ -1234,6 +1279,12 @@ async function main() {
1234
1279
  console.log(`Using script from @hkdigital/lib-core v${pkgJson.version}`);
1235
1280
  console.log(`Validating import paths...`);
1236
1281
 
1282
+ if (EXCLUSION_PATTERNS.length > 0) {
1283
+ console.log('Excluding patterns:');
1284
+ EXCLUSION_PATTERNS.forEach(pattern => console.log(` ${pattern}`));
1285
+ console.log();
1286
+ }
1287
+
1237
1288
  // Load project aliases from svelte.config.js
1238
1289
  PROJECT_ALIASES = await loadAliases();
1239
1290