@pixelated-tech/components 3.12.0 → 3.13.0
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/components/admin/componentusage/componentAnalysis.js +2 -0
- package/dist/components/admin/deploy/deployment.integration.js +8 -0
- package/dist/components/config/config.js +41 -2
- package/dist/components/general/metadata.functions.js +1 -1
- package/dist/components/general/well-known.js +137 -0
- package/dist/components/integrations/contentful.management.js +25 -25
- package/dist/components/sitebuilder/page/lib/pageStorageContentful.js +4 -4
- package/dist/config/pixelated.config.json.enc +1 -1
- package/dist/index.js +0 -1
- package/dist/index.server.js +3 -4
- package/dist/scripts/pixelated-eslint-plugin.js +49 -1
- package/dist/types/components/admin/componentusage/componentAnalysis.d.ts +2 -5
- package/dist/types/components/admin/componentusage/componentAnalysis.d.ts.map +1 -1
- package/dist/types/components/admin/deploy/deployment.integration.d.ts +1 -5
- package/dist/types/components/admin/deploy/deployment.integration.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-github.integration.d.ts +1 -11
- package/dist/types/components/admin/site-health/site-health-github.integration.d.ts.map +1 -1
- package/dist/types/components/admin/sites/sites.integration.d.ts +7 -1
- package/dist/types/components/admin/sites/sites.integration.d.ts.map +1 -1
- package/dist/types/components/config/config.d.ts.map +1 -1
- package/dist/types/components/config/config.types.d.ts +2 -2
- package/dist/types/components/config/config.types.d.ts.map +1 -1
- package/dist/types/components/general/well-known.d.ts +56 -0
- package/dist/types/components/general/well-known.d.ts.map +1 -0
- package/dist/types/components/integrations/contentful.management.d.ts +1 -5
- package/dist/types/components/integrations/contentful.management.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/ebay.functions.d.ts +2 -2
- package/dist/types/components/shoppingcart/ebay.functions.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/paypal.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts +20 -12
- package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/page/lib/pageStorageContentful.d.ts +1 -1
- package/dist/types/components/sitebuilder/page/lib/pageStorageContentful.d.ts.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.server.d.ts +3 -4
- package/dist/types/scripts/pixelated-eslint-plugin.d.ts +18 -0
- package/dist/types/tests/securitytxt.test.d.ts +2 -0
- package/dist/types/tests/securitytxt.test.d.ts.map +1 -0
- package/package.json +6 -6
- package/dist/components/config/config.utils.js +0 -52
- package/dist/components/general/humanstxt.js +0 -81
- package/dist/types/components/config/config.utils.d.ts +0 -6
- package/dist/types/components/config/config.utils.d.ts.map +0 -1
- package/dist/types/components/general/humanstxt.d.ts +0 -37
- package/dist/types/components/general/humanstxt.d.ts.map +0 -1
|
@@ -62,6 +62,8 @@ export async function getAllFiles(dirPath, extensions = []) {
|
|
|
62
62
|
*/
|
|
63
63
|
export async function checkComponentUsage(sitePath, componentName) {
|
|
64
64
|
try {
|
|
65
|
+
if (!sitePath)
|
|
66
|
+
return false; // nothing to scan
|
|
65
67
|
const files = await getAllFiles(sitePath, ['.tsx', '.ts', '.jsx', '.js']);
|
|
66
68
|
// Special case for semantic components that export multiple functions
|
|
67
69
|
if (componentName === 'general/semantic') {
|
|
@@ -22,6 +22,14 @@ export async function executeDeployment(request, siteConfig, isLocalExecution =
|
|
|
22
22
|
*/
|
|
23
23
|
async function executeScript(siteName, versionType, commitMessage, environments, localPath, remote) {
|
|
24
24
|
const sourceBranch = 'dev'; // Always deploy from dev branch
|
|
25
|
+
// Guard against missing localPath — callers may omit for non-local checks
|
|
26
|
+
if (!localPath) {
|
|
27
|
+
throw new Error('localPath is required for deployment execution');
|
|
28
|
+
}
|
|
29
|
+
// Guard against missing remote — required for git operations
|
|
30
|
+
if (!remote) {
|
|
31
|
+
throw new Error('remote is required for deployment execution');
|
|
32
|
+
}
|
|
25
33
|
try {
|
|
26
34
|
// Get current branch and ensure we're on dev
|
|
27
35
|
const { stdout: currentBranch } = await execAsync('git branch --show-current', { cwd: localPath });
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { SECRET_CONFIG_KEYS } from './config.types';
|
|
1
2
|
import { decrypt, isEncrypted } from './crypto';
|
|
2
|
-
import { getClientOnlyPixelatedConfig as stripSecrets } from './config.utils';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
|
5
|
+
// NOTE: getClientOnlyPixelatedConfig implementation moved here from
|
|
6
|
+
// src/components/config/config.utils.ts — this consolidates the public
|
|
7
|
+
// config API into one module.
|
|
5
8
|
const debug = false;
|
|
6
9
|
/**
|
|
7
10
|
* Read the full master config blob from local file.
|
|
@@ -108,5 +111,41 @@ export function getClientOnlyPixelatedConfig(full) {
|
|
|
108
111
|
const src = (full === undefined) ? getFullPixelatedConfig() : full;
|
|
109
112
|
if (src === null || typeof src !== 'object')
|
|
110
113
|
return (src || {});
|
|
111
|
-
|
|
114
|
+
// Inlined secret stripping logic (previously in config.utils)
|
|
115
|
+
const visited = new WeakSet();
|
|
116
|
+
function isSecretKey(key, serviceName) {
|
|
117
|
+
if (SECRET_CONFIG_KEYS.global.includes(key))
|
|
118
|
+
return true;
|
|
119
|
+
if (serviceName && SECRET_CONFIG_KEYS.services[serviceName]) {
|
|
120
|
+
const serviceSecrets = SECRET_CONFIG_KEYS.services[serviceName];
|
|
121
|
+
if (serviceSecrets.includes(key))
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
function strip(obj, serviceName) {
|
|
127
|
+
if (obj === null || typeof obj !== 'object')
|
|
128
|
+
return obj;
|
|
129
|
+
if (visited.has(obj))
|
|
130
|
+
return '[Circular]';
|
|
131
|
+
visited.add(obj);
|
|
132
|
+
if (Array.isArray(obj)) {
|
|
133
|
+
return obj.map((item) => strip(item, serviceName));
|
|
134
|
+
}
|
|
135
|
+
const out = {};
|
|
136
|
+
for (const k of Object.keys(obj)) {
|
|
137
|
+
const currentService = serviceName || k;
|
|
138
|
+
if (isSecretKey(k, serviceName))
|
|
139
|
+
continue;
|
|
140
|
+
out[k] = strip(obj[k], currentService);
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
return strip(src);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
console.error('Failed to strip secrets from config', err);
|
|
149
|
+
return {};
|
|
150
|
+
}
|
|
112
151
|
}
|
|
@@ -128,5 +128,5 @@ export function generateMetaTags(props) {
|
|
|
128
128
|
const image_height = prop_image_height || siteInfo?.image_height;
|
|
129
129
|
const image_width = prop_image_width || siteInfo?.image_width;
|
|
130
130
|
const favicon = prop_favicon || siteInfo?.favicon;
|
|
131
|
-
return (_jsxs(_Fragment, { children: [_jsx("title", { children: title }), _jsx("meta", { charSet: "UTF-8" }), _jsx("meta", { httpEquiv: "content-type", content: "text/html; charset=UTF-8" }), _jsx("meta", { httpEquiv: 'Expires', content: '0' }), _jsx("meta", { httpEquiv: 'Pragma', content: 'no-cache' }), _jsx("meta", { httpEquiv: 'Cache-Control', content: 'no-cache' }), _jsx("meta", { name: "application-name", content: site_name }), _jsx("meta", { name: "author", content: site_name + ", " + email }), _jsx("meta", { name: 'copyright', content: site_name }), _jsx("meta", { name: "creator", content: site_name }), _jsx("meta", { name: "description", content: description }), _jsx("meta", { name: "keywords", content: keywords }), _jsx("meta", { name: 'language', content: 'EN' }), _jsx("meta", { name: 'owner', content: site_name }), _jsx("meta", { name: "publisher", content: site_name }), _jsx("meta", { name: 'rating', content: 'General' }), _jsx("meta", { name: 'reply-to', content: email }), _jsx("meta", { name: "robots", content: "index, follow" }), _jsx("meta", { name: 'url', content: url }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0, shrink-to-fit=no" }), _jsx("meta", { property: "og:description", content: description }), _jsx("meta", { property: 'og:email', content: email }), _jsx("meta", { property: "og:image", content: image }), _jsx("meta", { property: "og:image:height", content: image_height != null ? String(image_height) : undefined }), _jsx("meta", { property: "og:image:width", content: image_width != null ? String(image_width) : undefined }), _jsx("meta", { property: "og:locale", content: "en_US" }), _jsx("meta", { property: "og:site_name", content: site_name }), _jsx("meta", { property: "og:title", content: title }), _jsx("meta", { property: "og:type", content: "website" }), _jsx("meta", { property: "og:url", content: url }), _jsx("meta", { itemProp: "name", content: site_name }), _jsx("meta", { itemProp: "url", content: url }), _jsx("meta", { itemProp: "description", content: description }), _jsx("meta", { itemProp: "thumbnailUrl", content: image }), _jsx("meta", { property: "twitter:domain", content: newOrigin }), _jsx("meta", { property: "twitter:url", content: url }), _jsx("meta", { name: "twitter:card", content: "summary_large_image" }), _jsx("meta", { name: "twitter:creator", content: site_name }), _jsx("meta", { name: "twitter:description", content: description }), _jsx("meta", { name: "twitter:image", content: image }), _jsx("meta", { name: "twitter:image:height", content: image_height != null ? String(image_height) : undefined }), _jsx("meta", { name: "twitter:image:width", content: image_width != null ? String(image_width) : undefined }), _jsx("meta", { name: "twitter:title", content: title }), _jsx("link", { rel: "author", href:
|
|
131
|
+
return (_jsxs(_Fragment, { children: [_jsx("title", { children: title }), _jsx("meta", { charSet: "UTF-8" }), _jsx("meta", { httpEquiv: "content-type", content: "text/html; charset=UTF-8" }), _jsx("meta", { httpEquiv: 'Expires', content: '0' }), _jsx("meta", { httpEquiv: 'Pragma', content: 'no-cache' }), _jsx("meta", { httpEquiv: 'Cache-Control', content: 'no-cache' }), _jsx("meta", { name: "application-name", content: site_name }), _jsx("meta", { name: "author", content: site_name + ", " + email }), _jsx("meta", { name: 'copyright', content: site_name }), _jsx("meta", { name: "creator", content: site_name }), _jsx("meta", { name: "description", content: description }), _jsx("meta", { name: "keywords", content: keywords }), _jsx("meta", { name: 'language', content: 'EN' }), _jsx("meta", { name: 'owner', content: site_name }), _jsx("meta", { name: "publisher", content: site_name }), _jsx("meta", { name: 'rating', content: 'General' }), _jsx("meta", { name: 'reply-to', content: email }), _jsx("meta", { name: "robots", content: "index, follow" }), _jsx("meta", { name: 'url', content: url }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0, shrink-to-fit=no" }), _jsx("meta", { property: "og:description", content: description }), _jsx("meta", { property: 'og:email', content: email }), _jsx("meta", { property: "og:image", content: image }), _jsx("meta", { property: "og:image:height", content: image_height != null ? String(image_height) : undefined }), _jsx("meta", { property: "og:image:width", content: image_width != null ? String(image_width) : undefined }), _jsx("meta", { property: "og:locale", content: "en_US" }), _jsx("meta", { property: "og:site_name", content: site_name }), _jsx("meta", { property: "og:title", content: title }), _jsx("meta", { property: "og:type", content: "website" }), _jsx("meta", { property: "og:url", content: url }), _jsx("meta", { itemProp: "name", content: site_name }), _jsx("meta", { itemProp: "url", content: url }), _jsx("meta", { itemProp: "description", content: description }), _jsx("meta", { itemProp: "thumbnailUrl", content: image }), _jsx("meta", { property: "twitter:domain", content: newOrigin }), _jsx("meta", { property: "twitter:url", content: url }), _jsx("meta", { name: "twitter:card", content: "summary_large_image" }), _jsx("meta", { name: "twitter:creator", content: site_name }), _jsx("meta", { name: "twitter:description", content: description }), _jsx("meta", { name: "twitter:image", content: image }), _jsx("meta", { name: "twitter:image:height", content: image_height != null ? String(image_height) : undefined }), _jsx("meta", { name: "twitter:image:width", content: image_width != null ? String(image_width) : undefined }), _jsx("meta", { name: "twitter:title", content: title }), _jsx("link", { rel: "author", href: "humans.txt" }), _jsx("link", { rel: "canonical", href: url }), _jsx("link", { rel: "icon", type: "image/x-icon", href: favicon }), _jsx("link", { rel: "shortcut icon", type: "image/x-icon", href: favicon }), _jsx("link", { rel: "manifest", href: "/manifest.webmanifest" }), _jsx("link", { rel: "preconnect", href: "https://images.ctfassets.net/" }), _jsx("link", { rel: "preconnect", href: "https://res.cloudinary.com/" }), _jsx("link", { rel: "preconnect", href: "https://farm2.static.flickr.com" }), _jsx("link", { rel: "preconnect", href: "https://farm6.static.flickr.com" }), _jsx("link", { rel: "preconnect", href: "https://farm8.static.flickr.com" }), _jsx("link", { rel: "preconnect", href: "https://farm66.static.flickr.com" })] }));
|
|
132
132
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import PropTypes from 'prop-types';
|
|
2
|
+
import { readFile } from 'fs/promises';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
import { NextResponse } from 'next/server';
|
|
5
|
+
import { flattenRoutes } from './sitemap';
|
|
6
|
+
/* ===== Shared helpers for .well-known files ===== */
|
|
7
|
+
/**
|
|
8
|
+
* Read JSON from disk safely — returns null on error. Exported for testing.
|
|
9
|
+
*/
|
|
10
|
+
export async function safeJSON(path) {
|
|
11
|
+
try {
|
|
12
|
+
const raw = await readFile(path, 'utf8');
|
|
13
|
+
return JSON.parse(raw);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Normalize a value into a single-line trimmed string (safe for humans.txt / security.txt).
|
|
21
|
+
* Exported for testing.
|
|
22
|
+
*/
|
|
23
|
+
export function sanitizeString(v) {
|
|
24
|
+
return v == null ? '' : String(v).replace(/\s+/g, ' ').trim();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build a plain-text response payload including ETag and standard headers.
|
|
28
|
+
* Exported for testing and reuse across .well-known generators.
|
|
29
|
+
*/
|
|
30
|
+
export function createTextResponsePayload(body) {
|
|
31
|
+
const etag = crypto.createHash('sha1').update(body).digest('hex');
|
|
32
|
+
const headers = {
|
|
33
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
34
|
+
'Cache-Control': 'public, max-age=60, stale-while-revalidate=3600',
|
|
35
|
+
ETag: etag,
|
|
36
|
+
};
|
|
37
|
+
return { body, etag, headers };
|
|
38
|
+
}
|
|
39
|
+
/* ========== HUMANS.TXT ========== */
|
|
40
|
+
generateHumansTxt.propTypes = {
|
|
41
|
+
/** base directory to read package.json / routes.json from (defaults to process.cwd()) */
|
|
42
|
+
cwd: PropTypes.string,
|
|
43
|
+
/** optional package.json object (if provided, fs is not used) */
|
|
44
|
+
pkg: PropTypes.object,
|
|
45
|
+
/** optional routes.json object (if provided, fs is not used) */
|
|
46
|
+
routesJson: PropTypes.object,
|
|
47
|
+
/** limit how many routes to include (default 50) */
|
|
48
|
+
maxRoutes: PropTypes.number,
|
|
49
|
+
};
|
|
50
|
+
export async function generateHumansTxt(opts = {}) {
|
|
51
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
52
|
+
const pkg = opts.pkg ?? (await safeJSON(cwd + '/package.json')) ?? {};
|
|
53
|
+
const data = opts.routesJson ?? (await safeJSON(cwd + '/src/app/data/routes.json')) ?? {};
|
|
54
|
+
const site = data.siteInfo ?? {};
|
|
55
|
+
const routes = Array.isArray(data.routes) ? data.routes : [];
|
|
56
|
+
const lines = [
|
|
57
|
+
'/* HUMAN-READABLE SITE INFORMATION - generated at runtime */',
|
|
58
|
+
'',
|
|
59
|
+
'/* AUTHOR */',
|
|
60
|
+
` Author Name: ${sanitizeString(site.author ?? '')}`,
|
|
61
|
+
` Author Address: ${sanitizeString(site.address
|
|
62
|
+
? [
|
|
63
|
+
site.address.streetAddress,
|
|
64
|
+
site.address.addressLocality,
|
|
65
|
+
site.address.addressRegion,
|
|
66
|
+
site.address.postalCode,
|
|
67
|
+
site.address.addressCountry,
|
|
68
|
+
]
|
|
69
|
+
.filter(Boolean)
|
|
70
|
+
.join(' ')
|
|
71
|
+
: '')}`,
|
|
72
|
+
` Author Email: ${sanitizeString(site.email ?? '')}`,
|
|
73
|
+
` Author Telephone: ${sanitizeString(site.telephone ?? '')}`,
|
|
74
|
+
'',
|
|
75
|
+
'/* DEVELOPER */',
|
|
76
|
+
` Developer Name: Brian Whaley`,
|
|
77
|
+
` Developer Company: Pixelated Technologies LLC`,
|
|
78
|
+
` Developer Address: 10 Jade Circle, Denville NJ 07834 USA`,
|
|
79
|
+
` Developer Email: brian@pixelated.tech`,
|
|
80
|
+
` Developer Website: https://www.pixelated.tech`,
|
|
81
|
+
` Developer Telephone: +1 (973) 722-2601`,
|
|
82
|
+
'',
|
|
83
|
+
'/* SITE */',
|
|
84
|
+
` Site Name: ${sanitizeString(site.name ?? '')}`,
|
|
85
|
+
` Site Package Name: ${sanitizeString(pkg.name ?? '')}`,
|
|
86
|
+
` Site Package Version: ${sanitizeString(pkg.version ?? '')}`,
|
|
87
|
+
` Site URL: ${sanitizeString(site.url ?? '')}`,
|
|
88
|
+
` Site Languages: React, Node, NextJS, JavaScript, HTML5, CSS3, SASS `,
|
|
89
|
+
` Site Tools: VSCode, GitHub, AWS, Contently, Cloudinary, Wordpress, Google Analytics, Google Search Console`,
|
|
90
|
+
` Site Pages: (${routes.length})`,
|
|
91
|
+
];
|
|
92
|
+
const limit = typeof opts.maxRoutes === 'number' ? opts.maxRoutes : 50;
|
|
93
|
+
for (const r of flattenRoutes(routes).slice(0, limit)) {
|
|
94
|
+
lines.push(` - ${sanitizeString(r.path ?? r.pathname ?? r.url ?? '')} - ${sanitizeString(r.title ?? '')}`);
|
|
95
|
+
}
|
|
96
|
+
const body = lines.join('\n');
|
|
97
|
+
return createTextResponsePayload(body);
|
|
98
|
+
}
|
|
99
|
+
/* ========== SECURITY.TXT ========== */
|
|
100
|
+
generateSecurityTxt.propTypes = {
|
|
101
|
+
routesJson: PropTypes.object,
|
|
102
|
+
};
|
|
103
|
+
export async function generateSecurityTxt(props = {}) {
|
|
104
|
+
const data = props.routesJson ?? (await safeJSON(process.cwd() + '/src/app/data/routes.json')) ?? {};
|
|
105
|
+
const siteInfo = data.siteInfo ?? {};
|
|
106
|
+
const lines = [
|
|
107
|
+
'# Contact methods for security researchers',
|
|
108
|
+
`Contact: mailto:${sanitizeString(siteInfo.email ?? '')}`,
|
|
109
|
+
'',
|
|
110
|
+
"# Link to your vulnerability disclosure policy",
|
|
111
|
+
'Policy: ',
|
|
112
|
+
'',
|
|
113
|
+
"# Link to your PGP public key for encrypted communication",
|
|
114
|
+
'Encryption: ',
|
|
115
|
+
'',
|
|
116
|
+
"# Languages supported",
|
|
117
|
+
'Preferred-Languages: en',
|
|
118
|
+
'',
|
|
119
|
+
"# Date and time the file should be considered stale",
|
|
120
|
+
`Expires: ${new Date(new Date().getFullYear(), 11, 31).toISOString()}`,
|
|
121
|
+
];
|
|
122
|
+
const body = lines.join('\n');
|
|
123
|
+
return createTextResponsePayload(body);
|
|
124
|
+
}
|
|
125
|
+
/* ========== Convenience helper ========== */
|
|
126
|
+
/**
|
|
127
|
+
* Create a response for a well-known resource.
|
|
128
|
+
* @param {'humans'|'security'} type - Which resource to generate ('humans' | 'security').
|
|
129
|
+
*/
|
|
130
|
+
export async function createWellKnownResponse(type, req, opts = {}) {
|
|
131
|
+
const payload = (type === 'humans') ? await generateHumansTxt(opts) : await generateSecurityTxt(opts);
|
|
132
|
+
const { body, etag, headers } = payload;
|
|
133
|
+
if (req?.headers?.get && req.headers.get('if-none-match') === etag) {
|
|
134
|
+
return new NextResponse(null, { status: 304, headers });
|
|
135
|
+
}
|
|
136
|
+
return new NextResponse(body, { status: 200, headers });
|
|
137
|
+
}
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* List all entries of a specific content type
|
|
8
8
|
*/
|
|
9
9
|
export async function listEntries(contentType, config) {
|
|
10
|
-
const {
|
|
10
|
+
const { space_id, delivery_access_token, environment = 'master' } = config;
|
|
11
11
|
try {
|
|
12
|
-
const response = await fetch(`https://api.contentful.com/spaces/${
|
|
12
|
+
const response = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries?content_type=${contentType}`, {
|
|
13
13
|
headers: {
|
|
14
|
-
'Authorization': `Bearer ${
|
|
14
|
+
'Authorization': `Bearer ${delivery_access_token}`,
|
|
15
15
|
'Content-Type': 'application/json',
|
|
16
16
|
},
|
|
17
17
|
});
|
|
@@ -37,11 +37,11 @@ export async function listEntries(contentType, config) {
|
|
|
37
37
|
* Get a single entry by ID
|
|
38
38
|
*/
|
|
39
39
|
export async function getEntryById(entryId, config) {
|
|
40
|
-
const {
|
|
40
|
+
const { space_id, delivery_access_token, environment = 'master' } = config;
|
|
41
41
|
try {
|
|
42
|
-
const response = await fetch(`https://api.contentful.com/spaces/${
|
|
42
|
+
const response = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${entryId}`, {
|
|
43
43
|
headers: {
|
|
44
|
-
'Authorization': `Bearer ${
|
|
44
|
+
'Authorization': `Bearer ${delivery_access_token}`,
|
|
45
45
|
'Content-Type': 'application/json',
|
|
46
46
|
},
|
|
47
47
|
});
|
|
@@ -71,11 +71,11 @@ export async function getEntryById(entryId, config) {
|
|
|
71
71
|
* Search for entries by field value
|
|
72
72
|
*/
|
|
73
73
|
export async function searchEntriesByField(contentType, fieldName, fieldValue, config) {
|
|
74
|
-
const {
|
|
74
|
+
const { space_id, delivery_access_token, environment = 'master' } = config;
|
|
75
75
|
try {
|
|
76
|
-
const response = await fetch(`https://api.contentful.com/spaces/${
|
|
76
|
+
const response = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries?content_type=${contentType}&fields.${fieldName}=${encodeURIComponent(fieldValue)}`, {
|
|
77
77
|
headers: {
|
|
78
|
-
'Authorization': `Bearer ${
|
|
78
|
+
'Authorization': `Bearer ${delivery_access_token}`,
|
|
79
79
|
'Content-Type': 'application/json',
|
|
80
80
|
},
|
|
81
81
|
});
|
|
@@ -101,17 +101,17 @@ export async function searchEntriesByField(contentType, fieldName, fieldValue, c
|
|
|
101
101
|
* Create a new entry
|
|
102
102
|
*/
|
|
103
103
|
export async function createEntry(contentType, fields, config, autoPublish = true) {
|
|
104
|
-
const {
|
|
104
|
+
const { space_id, delivery_access_token, environment = 'master' } = config;
|
|
105
105
|
try {
|
|
106
106
|
// Convert fields to Contentful format (with 'en-US' locale)
|
|
107
107
|
const contentfulFields = {};
|
|
108
108
|
for (const [key, value] of Object.entries(fields)) {
|
|
109
109
|
contentfulFields[key] = { 'en-US': value };
|
|
110
110
|
}
|
|
111
|
-
const createResponse = await fetch(`https://api.contentful.com/spaces/${
|
|
111
|
+
const createResponse = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries`, {
|
|
112
112
|
method: 'POST',
|
|
113
113
|
headers: {
|
|
114
|
-
'Authorization': `Bearer ${
|
|
114
|
+
'Authorization': `Bearer ${delivery_access_token}`,
|
|
115
115
|
'Content-Type': 'application/vnd.contentful.management.v1+json',
|
|
116
116
|
'X-Contentful-Content-Type': contentType,
|
|
117
117
|
},
|
|
@@ -126,10 +126,10 @@ export async function createEntry(contentType, fields, config, autoPublish = tru
|
|
|
126
126
|
const newEntry = await createResponse.json();
|
|
127
127
|
// Publish if requested
|
|
128
128
|
if (autoPublish) {
|
|
129
|
-
await fetch(`https://api.contentful.com/spaces/${
|
|
129
|
+
await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${newEntry.sys.id}/published`, {
|
|
130
130
|
method: 'PUT',
|
|
131
131
|
headers: {
|
|
132
|
-
'Authorization': `Bearer ${
|
|
132
|
+
'Authorization': `Bearer ${delivery_access_token}`,
|
|
133
133
|
'X-Contentful-Version': newEntry.sys.version.toString(),
|
|
134
134
|
},
|
|
135
135
|
});
|
|
@@ -151,7 +151,7 @@ export async function createEntry(contentType, fields, config, autoPublish = tru
|
|
|
151
151
|
* Update an existing entry
|
|
152
152
|
*/
|
|
153
153
|
export async function updateEntry(entryId, fields, config, autoPublish = true) {
|
|
154
|
-
const {
|
|
154
|
+
const { space_id, delivery_access_token, environment = 'master' } = config;
|
|
155
155
|
try {
|
|
156
156
|
// Get current entry to get version
|
|
157
157
|
const getResponse = await getEntryById(entryId, config);
|
|
@@ -167,10 +167,10 @@ export async function updateEntry(entryId, fields, config, autoPublish = true) {
|
|
|
167
167
|
for (const [key, value] of Object.entries(fields)) {
|
|
168
168
|
contentfulFields[key] = { 'en-US': value };
|
|
169
169
|
}
|
|
170
|
-
const updateResponse = await fetch(`https://api.contentful.com/spaces/${
|
|
170
|
+
const updateResponse = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${entryId}`, {
|
|
171
171
|
method: 'PUT',
|
|
172
172
|
headers: {
|
|
173
|
-
'Authorization': `Bearer ${
|
|
173
|
+
'Authorization': `Bearer ${delivery_access_token}`,
|
|
174
174
|
'Content-Type': 'application/vnd.contentful.management.v1+json',
|
|
175
175
|
'X-Contentful-Version': currentEntry.sys.version.toString(),
|
|
176
176
|
},
|
|
@@ -185,10 +185,10 @@ export async function updateEntry(entryId, fields, config, autoPublish = true) {
|
|
|
185
185
|
const updatedEntry = await updateResponse.json();
|
|
186
186
|
// Publish if requested
|
|
187
187
|
if (autoPublish) {
|
|
188
|
-
await fetch(`https://api.contentful.com/spaces/${
|
|
188
|
+
await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${entryId}/published`, {
|
|
189
189
|
method: 'PUT',
|
|
190
190
|
headers: {
|
|
191
|
-
'Authorization': `Bearer ${
|
|
191
|
+
'Authorization': `Bearer ${delivery_access_token}`,
|
|
192
192
|
'X-Contentful-Version': updatedEntry.sys.version.toString(),
|
|
193
193
|
},
|
|
194
194
|
});
|
|
@@ -210,7 +210,7 @@ export async function updateEntry(entryId, fields, config, autoPublish = true) {
|
|
|
210
210
|
* Delete an entry (unpublish first, then delete)
|
|
211
211
|
*/
|
|
212
212
|
export async function deleteEntry(entryId, config) {
|
|
213
|
-
const {
|
|
213
|
+
const { space_id, delivery_access_token, environment = 'master' } = config;
|
|
214
214
|
try {
|
|
215
215
|
// Get current entry to get version
|
|
216
216
|
const getResponse = await getEntryById(entryId, config);
|
|
@@ -222,18 +222,18 @@ export async function deleteEntry(entryId, config) {
|
|
|
222
222
|
}
|
|
223
223
|
const entry = getResponse.entry;
|
|
224
224
|
// Unpublish first
|
|
225
|
-
await fetch(`https://api.contentful.com/spaces/${
|
|
226
|
-
method: '
|
|
225
|
+
await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${entry.sys.id}/published`, {
|
|
226
|
+
method: 'PUT',
|
|
227
227
|
headers: {
|
|
228
|
-
'Authorization': `Bearer ${
|
|
228
|
+
'Authorization': `Bearer ${delivery_access_token}`,
|
|
229
229
|
'X-Contentful-Version': entry.sys.version.toString(),
|
|
230
230
|
},
|
|
231
231
|
});
|
|
232
232
|
// Delete the entry
|
|
233
|
-
const deleteResponse = await fetch(`https://api.contentful.com/spaces/${
|
|
233
|
+
const deleteResponse = await fetch(`https://api.contentful.com/spaces/${space_id}/environments/${environment}/entries/${entryId}`, {
|
|
234
234
|
method: 'DELETE',
|
|
235
235
|
headers: {
|
|
236
|
-
'Authorization': `Bearer ${
|
|
236
|
+
'Authorization': `Bearer ${delivery_access_token}`,
|
|
237
237
|
'X-Contentful-Version': (entry.sys.version + 1).toString(),
|
|
238
238
|
},
|
|
239
239
|
});
|
|
@@ -19,9 +19,9 @@ export async function listContentfulPages(config) {
|
|
|
19
19
|
// Map management-style config to delivery apiProps for the CDN-based read helper
|
|
20
20
|
const apiProps = {
|
|
21
21
|
base_url: 'https://cdn.contentful.com',
|
|
22
|
-
space_id: config.
|
|
22
|
+
space_id: config.space_id,
|
|
23
23
|
environment: config.environment || 'master',
|
|
24
|
-
delivery_access_token: config.
|
|
24
|
+
delivery_access_token: config.delivery_access_token,
|
|
25
25
|
};
|
|
26
26
|
const result = await getContentfulEntriesByType({ apiProps, contentType: CONTENT_TYPE });
|
|
27
27
|
if (!result || !Array.isArray(result.items)) {
|
|
@@ -46,9 +46,9 @@ export async function loadContentfulPage(name, config) {
|
|
|
46
46
|
// Use delivery API for reads
|
|
47
47
|
const apiProps = {
|
|
48
48
|
base_url: 'https://cdn.contentful.com',
|
|
49
|
-
space_id: config.
|
|
49
|
+
space_id: config.space_id,
|
|
50
50
|
environment: config.environment || 'master',
|
|
51
|
-
delivery_access_token: config.
|
|
51
|
+
delivery_access_token: config.delivery_access_token,
|
|
52
52
|
};
|
|
53
53
|
const result = await getContentfulEntriesByType({ apiProps, contentType: CONTENT_TYPE });
|
|
54
54
|
if (!result || !Array.isArray(result.items) || result.items.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
pxl:v1:
|
|
1
|
+
pxl:v1:cb4a6489e69c34388bf9b3e4:6f420b0316cbc2f7b8ff526175372cca:ab175029a0c5d9aeb1c7c69ac67db745304191463e5338ea9f711f8c93aad8c1549369a06eb6c1bd972e3a3bfb3ccfb851f2cce837b48542a51dd2e1a23303dabf2db0734caa0fc3006d6f1e51b1c5bbd203e74c1861ef350c4dd8a266ea38f723cac9d964ae8abf34d296af9327284a8dd3eab3f8821920d5995e465067f4c5052c14165a9d9fb316f5a9b8f4a55abc618974df1ad98569bcd5e4d64430a9513287d56a1c0fbc455d7d2ce13bccc99554814268edb61a29923d305690707d7f91c6de1caa1ad72409b3aba95fa82744293c3e5c28c2baffa2a0441c0bf0ffae8cc6dd0678cedb9cd67dc11c582c37714d6cdfaa4a0e80c0e61d5040d678cd4d9332b65fc20074406f44f99ca82c23ecdd64b07f681d0fcd1fc0fd1992250e2245bd0c8df616053e6c0d9f076576a1d30c1ac426f7c00848aa657239e54e87ba4f34a8579b005d9f3ab3d326aaaed98d3f510b32514a2b0ce155ba611286521bb726a45377fadd2d27fdbff5a905f0b213805a5a04a1d09dd1ec46dd5a633e5e522add289a6ce1a68bed32226d74a43adaa5972b93021e2f90a92231c2438012277081bed2df304070ae44776807b09a5ff650a285429504c52fa60f2b02ebd0c421cc06f27694d49aad5423fe496cb2b4d3d69330ca095931e1bdc45d27d4e1f97ec887eb4303f782ab051490c3f820ff94c65464b9718747aaa2bdc5d71c21ada02f3934e5843b63f6f47ad39b61a8a260d2b2278f14ac9b891b6fb0cc9b24d0d635358459d40674e74f1c3f1fdd68566930606eb59e870691d67b334a96e3e5672a111d6f393475f14c805cc154f6c744322c417dee4e3457cea509ab2871257bd5f115ddf1cdf266795374267ef415e1da35708bf897a56d87d89596bee19d244900ba0a1a3c216f3ebb1055efe1319f0fd806afe6332f9700bdbf4585dd1ff1729d46804cc7942e98ea2cbc3cedbe9c3f79130099ca87b78caa248a1a4a71f9f8d198b54073e5a34d028be15ee4a0dd2d10d4ac2e82cf3a2cbe4019aeaa382a167b738ca4293c4d61d479b11f05216e378a064afe8a2bd9292bba48d684fa83a5d910a24b9e8f5ff2fb2fcc1a6024dba4d16565ec403cba779f6cbba00ac582b197af0c2493d3eeb02303e86321832eaaf9ed109f093a7c685c0e12030b3b06ae90c7387106d41ca45b606c1f6c20982b892f24dd541d5beca2e492d18c7cb3643e0629040db750e6c85997ba11ce677fdce6cee16d065d2390cdb22cce45f5e1f9c187604febe71057af13f3cd820da97c1712e0c58cb02c5a111cfc5f5ff0adbc44f9bef8ac9cab94b76239c2e4c15dbf02ee336e3970fb39b7e9389e184a518e3f0e18cfc1dbc571935f6aa1cf3d7e7440902aa6a8a3a7be8faa589ff2c905146b240937385c0a9f69ad7d11419a28c170ccc31b2fda851e82af5f782c1f51b37a1262d67fd8a68d3afdc3331b6b2581e779ad1a6072332d44d7350693fedec4f4a072e55c79175eff6a7c3fee115736a36f26b0999aa38570c91f71c7290fb82d4b5f19eba1e0a6bcf37b62d831629603cb47e618abd01ac6fb3bbecfffc263d946fc388b295300944b064d67b27f50d0544dca746973b6427b85527ed72ba846f3149788deaa04ff66812adfbb594f994af0b227081b6e8d9f303370a88d3907d50acb0c38980095d76c27df3259adf0055d7cb0d774cc78d4a4f684338f2135ed2098be70f386dccda9bc1b5d6be28e586763f9540f199db3509d18ce04a53ba7e3da77f82d197f8e2a11430d65c3a4498b01abe86e6aac3c159a3c6cdf3ede1be2875372e9cc6bb8f1ee787de1193fc28e5c68a3ae9133cab2d8b34bbffb2dc3cb3e02ecc68153c6039b3e64601fb70180a1ee4358c46ff379c832bcb47a8e17a5751c6fa7e39f21d23d74eb55d46004d978594dc63f01ebd4033df4fb2a525c80acedaff402cce7691e396d508d265068cd1e55f057432e7710f0b220c1cd249a670fc84962adac60c94f3670f021f060fb5518afca7ed52717cb90029dbe4c491f2f1c05a8d7d07c3589ba8faf3f2e9f170be1572db5e3001d90441ac4b486cdf9cee8d5f827b563d5f3bdf428fe6fa45d71985af27957065e91f440fa03fd0bef44bf87d825ca995e492391c60a8bb7168cb591330aefd1abb4ce2ea1007223fd4f5135c11fe1d5d26fba5944ff9daf852358cd8ef2a2360d2069b4e80f421c75122d9165cf22ddabfe5b2e31c1aa7bea8b8c9ee94e3f7cca3c9cc915700a789f88abf3c6929c0773f51d38e39224652bf8bdca0cc2744c1c8bd052ca619a80a11ecb93faf3cc8cf1ce83c0c88d0d4566fa689329c22c8551fea8961bdd86363aee3f85170ddc6db28b22c41cb00cf87b03441474e2b988118582c0b9d4578fbcb66b44a905e7c25e66ae3de085e6ff5a1149d4808f077ca5481c3d3d257442cd7ff0b7664d820a416c8728d01819f5cdbd3f26ca7d9456920b9000951e16b2e211929cd9e98e41e7c48161deac3cce9cacdf43a04351b25678724ab1029e66c64218131266c7791431939083ee5b125f5ef6d4fef0cfcfdfd812441ea15beff8c93abe1521beec86378c91818a29225045a4af5dc5167b9cdf0e20df4f2dd600355b906716177a8320edf4789d495b60ecc69ca73866973c68200c26d37d47752a0fba3c06e178bfda2cf2824c93d25aa19aa72ec75d7d8787963378ba4212549e5710a366407be73e9671383e37bba45deea3959a38ab6d7c1e0b45ac4be484b873916b19eff8b50b909ce74e1e5eececfe9041b4d33bbdbfd221f5ae301165dbf890084d3ca36f2f91da7dbea85b05134a0db5c2f782b12d7bd3817cd392817d6e893d34c03b4551dd282c949cea5e7ac00b9b70a5a80925bba1bc3f514b1c43d2f82e97a523d6eaddb0d12168472866b11f2a9025d2facb0eabeba21018c8dd8794f4ecf3a1126dbc75a060bb029ea1b4f398d9690de76c723faa7d8e71050cdafb17a94c769dbcb8bd21a880bba7c863df765ce59089d357d356ac8ecc942dadece79d71b8dba7a7f18f93e96eee1ca05e6b3ea04af947cd0ad21d28438d1ed50bdc0573b20b73f2429d7bfac52edbc9d8b898ec28fdd80d7f23b67391d3b715a445bbeb86336abb27054169c4fed409262fcf737a113df680e6fb1d60d1cfd679584b90f1b302dca6d84c2f62074a70542467263cfbac4379e2795f7c3b08fa44adf998d90a6be1859153b364f5d5743b7febd8cff1918f44877cad7f76954b4145e7cb03ad3b16c338ab9535435a4a86bbbe36a11bfda3190fa4b561ba50b2691a0b6a60b42553bcefa48914238f8fa08f32184e279c5e94bf37e82f5ac0066f89bc17bab8d4221a0d9dac7a640ce3958d65c3d5e5f896de66e70800017b61308b62c9ebd4ddd3cffdc3a74e208c0b5bfb05ad93309704a2f5c143b9d9ba957e920c15954d4347f6cc0caccd45e911aaebb5c2e64711d18b58854faf5d2ffe3612f77ea82d5c672c67007968e37d52f24c7efe36d800614cfb6fa128fd211683884d5487c624370201a0619e29689cf944fb7af6b03cf242aefc34eb92ead068689e1877040ae89b2cd90ceb1da5319c610024376545058e493fe8e38a79ba6b6a2a3d594b07fda088ae436a601f89a379fac5af5bf77e892a4e937867a6bfd424cd01d0a75918e21ddb0bacc6db0d1863ec7c57375ee2bca147327a616294fed2fff515be532adbb78ede2e5147115028278baf9d9ff64cacfad454ddc581fc5c85c8738c3b1243db430e5a8a492f95fc8fec33d8f050784edc8848e9001a33680a3e5ea88bb457f9caca3ac8693084c13c593480a8a93810c7cb34c6c9558ec3c186a8f754058d33d627574718cd50eab6040b575ad214ddbf2f332de8326ea46f2b6a081c3c61882f97ba9d726aab97101506253b3c8b4c922cba9fca9a8c4bcf744f327bdd615d4d38cfc7d0d2c8178bb735459bdc40c879ab05b3301eb9c27aaae044e7b65c68fa21b304beeb71731de29a271437948e04d70b86c4a8f518b0c3ea29d209ca5e90fa0a562b5b22318e1712ee0082200969ff5a2d91389206537295aef15d0a6830e8e5e34d7101a85b50b5101cabc3db885369cabdb993349145bfaf841dd9ddbfc82baa620eb1d9b905db1cc2b1bde20f636212fb40a473315879d7cc2088389de7bfad757f717b677e9c17c8772f784d7f0c93893629641d7e6942fdade396adead18fe3e3b8e0c81e4ac178fa7cfc01c85390b597ad31eb375805e0e4175a7d7703bd6c10b6f7a2c013546e88cfa9b8f4935c109c7a4e8bf31d4a586202801aed8be490e0ba9a0d93d8d709f1760f20d07802c0d2ff36bddd4d470791614984d0838e91bad3d3f6a3b7a5d91ab0b6ad6ed1c1a66cd3f98eff7188cda2e7912270b547d577d0a31f1e94b6c4fa8bced14543e98d91fc10d4d18dabed1d47749eb4601f5bd7466bb5cfb07f810c1119839126d8e249fba398b52a2c92d08e9f0e26c0ca4402d5ad019598e2e737d76435fe22b53cab4b5f8c75df8f747393b9b53114203a3cd8fe0aa5486652b1c43cefc16c5cd04171ad43cae61d4c3ef2da3d2f3ebdf95408b504efcb34900d6f806d4802deecba1fbfd56083caf24d14759be2d1cb7c9ac7d1747ac989a3c46f0c2a61350cc260186895c5aa88798b9aae78674c0c74332d8b4c5d6b62f478775e3b4caec1b846d8e74c384ffbb1db92bc14d1bcc0277786d3d66132241edc0fbf561e14047b1e61c27ca871feab562f1f47c689d595724240971ce2bdda571317cda4ffaca9a78d16f6f36b4efa49b129afcbbf054b9e61704fb344ecd7b089f31d10d774cdf526d00c30ff008225f276c26c4a4ada20752614d5463167fe319b20acc9fd625121d83314d212f0b0e3ea5ab1a61e4d0237df5f185aebe49d88a09bd3294944acb20377e475d2e04a5b68c34e192910df2a83aba2cd6e0eccbda77d47dde51a11a1cb166012953be980e97a6ee9c16e81f7b9d721126320f5c3478779fe7134e94fd91a76f00166a2d6248263c950e93e071f094c912a15427019f1eaf9aeff3ee9a8020af4d78c9088e5e5c2e4c29f7b263347217a669e1868161965d0813854a7a3e0415826964248539c8fd47c6bb43a58d73635a8b3a81486d6bc26f1a8179d85
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// sorted alphabetically and grouped by folder for easier reading
|
|
2
2
|
export * from './components/config/config.client';
|
|
3
3
|
export * from './components/config/config.types';
|
|
4
|
-
export * from './components/config/config.utils';
|
|
5
4
|
export * from './components/config/config.validators';
|
|
6
5
|
export * from './components/general/404';
|
|
7
6
|
export * from './components/general/accordion';
|
package/dist/index.server.js
CHANGED
|
@@ -6,11 +6,10 @@ export * from './components/admin/sites/sites.integration';
|
|
|
6
6
|
export * from './components/config/config';
|
|
7
7
|
export * from './components/config/config.server';
|
|
8
8
|
export * from './components/config/config.types';
|
|
9
|
-
export * from './components/config/config.utils';
|
|
10
9
|
export * from './components/config/config.validators';
|
|
11
10
|
export * from './components/config/crypto';
|
|
12
|
-
export * from './components/general/manifest';
|
|
13
11
|
export * from './components/general/hero';
|
|
12
|
+
export * from './components/general/manifest';
|
|
14
13
|
export * from './components/general/metadata.functions';
|
|
15
14
|
export * from './components/general/proxy-handler';
|
|
16
15
|
export * from './components/general/resume';
|
|
@@ -22,9 +21,9 @@ export * from './components/general/schema-recipe';
|
|
|
22
21
|
export * from './components/general/schema-services';
|
|
23
22
|
export * from './components/general/schema-website';
|
|
24
23
|
export * from './components/general/sitemap';
|
|
25
|
-
export * from './components/general/humanstxt';
|
|
26
|
-
export * from './components/general/utilities';
|
|
27
24
|
export * from './components/general/skeleton';
|
|
25
|
+
export * from './components/general/well-known';
|
|
26
|
+
export * from './components/general/utilities';
|
|
28
27
|
export * from './components/integrations/contentful.delivery';
|
|
29
28
|
export * from './components/integrations/contentful.management';
|
|
30
29
|
export * from './components/integrations/flickr';
|
|
@@ -348,6 +348,52 @@ const propTypesJsdocRule = {
|
|
|
348
348
|
},
|
|
349
349
|
};
|
|
350
350
|
|
|
351
|
+
// ===== RULE: class-name-kebab-case =====
|
|
352
|
+
const classNameKebabCaseRule = {
|
|
353
|
+
meta: {
|
|
354
|
+
type: 'suggestion',
|
|
355
|
+
docs: {
|
|
356
|
+
description: 'Enforce kebab-case for JSX className values',
|
|
357
|
+
category: 'Stylistic',
|
|
358
|
+
recommended: true,
|
|
359
|
+
},
|
|
360
|
+
messages: {
|
|
361
|
+
invalidClass: 'Class name "{{className}}" should be kebab-case (e.g. "callout-title-text").',
|
|
362
|
+
},
|
|
363
|
+
schema: [],
|
|
364
|
+
},
|
|
365
|
+
create(context) {
|
|
366
|
+
const kebabRe = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
367
|
+
return {
|
|
368
|
+
JSXAttribute(node) {
|
|
369
|
+
if (!node.name) return;
|
|
370
|
+
const name = node.name.name;
|
|
371
|
+
if (name !== 'className' && name !== 'class') return;
|
|
372
|
+
|
|
373
|
+
const value = node.value;
|
|
374
|
+
if (!value) return;
|
|
375
|
+
|
|
376
|
+
let text = null;
|
|
377
|
+
if (value.type === 'Literal') text = value.value;
|
|
378
|
+
else if (value.type === 'JSXExpressionContainer') {
|
|
379
|
+
if (value.expression && value.expression.type === 'Literal') text = value.expression.value;
|
|
380
|
+
else if (value.expression && value.expression.type === 'TemplateLiteral') {
|
|
381
|
+
text = value.expression.quasis.map(q => q.value.cooked).join(' ');
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (typeof text !== 'string') return; // skip dynamic expressions
|
|
385
|
+
|
|
386
|
+
const parts = text.split(/\s+/).filter(Boolean);
|
|
387
|
+
for (const part of parts) {
|
|
388
|
+
if (!kebabRe.test(part)) {
|
|
389
|
+
context.report({ node, messageId: 'invalidClass', data: { className: part } });
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
};
|
|
394
|
+
},
|
|
395
|
+
};
|
|
396
|
+
|
|
351
397
|
const requiredFilesRule = {
|
|
352
398
|
meta: {
|
|
353
399
|
type: 'suggestion',
|
|
@@ -871,6 +917,7 @@ export default {
|
|
|
871
917
|
'required-proptypes-jsdoc': propTypesJsdocRule,
|
|
872
918
|
'file-name-kebab-case': fileNameKebabCaseRule,
|
|
873
919
|
'no-duplicate-export-names': noDuplicateExportNamesRule,
|
|
920
|
+
'class-name-kebab-case': classNameKebabCaseRule,
|
|
874
921
|
},
|
|
875
922
|
configs: {
|
|
876
923
|
recommended: {
|
|
@@ -886,7 +933,8 @@ export default {
|
|
|
886
933
|
'pixelated/no-debug-true': 'warn',
|
|
887
934
|
'pixelated/file-name-kebab-case': 'off',
|
|
888
935
|
'pixelated/required-proptypes-jsdoc': 'warn',
|
|
889
|
-
'pixelated/no-duplicate-export-names': '
|
|
936
|
+
'pixelated/no-duplicate-export-names': 'error',
|
|
937
|
+
'pixelated/class-name-kebab-case': 'warn',
|
|
890
938
|
},
|
|
891
939
|
},
|
|
892
940
|
},
|
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
* Component Usage Analysis Services
|
|
3
3
|
* Server-side utilities for analyzing component usage across sites
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
name: string;
|
|
7
|
-
localPath: string;
|
|
8
|
-
}
|
|
5
|
+
import type { SiteConfig } from '../sites/sites.integration';
|
|
9
6
|
export interface ComponentUsageResult {
|
|
10
7
|
components: string[];
|
|
11
8
|
siteList: SiteConfig[];
|
|
@@ -27,7 +24,7 @@ export declare function getAllFiles(dirPath: string, extensions?: string[]): Pro
|
|
|
27
24
|
/**
|
|
28
25
|
* Check if a component is used in a site
|
|
29
26
|
*/
|
|
30
|
-
export declare function checkComponentUsage(sitePath: string, componentName: string): Promise<boolean>;
|
|
27
|
+
export declare function checkComponentUsage(sitePath: string | undefined, componentName: string): Promise<boolean>;
|
|
31
28
|
/**
|
|
32
29
|
* Analyze component usage across all sites
|
|
33
30
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"componentAnalysis.d.ts","sourceRoot":"","sources":["../../../../../src/components/admin/componentusage/componentAnalysis.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"componentAnalysis.d.ts","sourceRoot":"","sources":["../../../../../src/components/admin/componentusage/componentAnalysis.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE7D,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,WAAW,EAAE;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG;YAAE,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC;CACnE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAezE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoC/F;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAwD/G;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAC1C,UAAU,EAAE,MAAM,EAAE,EACpB,KAAK,EAAE,UAAU,EAAE,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAyC/B"}
|
|
@@ -2,11 +2,7 @@
|
|
|
2
2
|
* Deployment Integration Services
|
|
3
3
|
* Server-side utilities for site deployment operations
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
name: string;
|
|
7
|
-
localPath: string;
|
|
8
|
-
remote: string;
|
|
9
|
-
}
|
|
5
|
+
import type { SiteConfig } from '../sites/sites.integration';
|
|
10
6
|
export interface DeploymentRequest {
|
|
11
7
|
site: string;
|
|
12
8
|
environments: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployment.integration.d.ts","sourceRoot":"","sources":["../../../../../src/components/admin/deploy/deployment.integration.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"deployment.integration.d.ts","sourceRoot":"","sources":["../../../../../src/components/admin/deploy/deployment.integration.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAI7D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACzC;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACtC,OAAO,EAAE,iBAAiB,EAC1B,UAAU,EAAE,UAAU,EACtB,gBAAgB,GAAE,OAAe,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAU3B"}
|
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
import type { GitCommit } from './site-health-types';
|
|
2
|
+
import type { SiteConfig } from '../sites/sites.integration';
|
|
2
3
|
export interface GitHealthResult {
|
|
3
4
|
commits: GitCommit[];
|
|
4
5
|
timestamp: string;
|
|
5
6
|
status: 'success' | 'error';
|
|
6
7
|
error?: string;
|
|
7
8
|
}
|
|
8
|
-
export interface SiteConfig {
|
|
9
|
-
name: string;
|
|
10
|
-
/** Optional: explicit repository identifier (e.g., "owner/repo" or just "repo") */
|
|
11
|
-
repo?: string;
|
|
12
|
-
/** Optional: remote name (legacy) */
|
|
13
|
-
remote?: string;
|
|
14
|
-
/** Optional explicit repo owner */
|
|
15
|
-
owner?: string;
|
|
16
|
-
/** Optional local path used to derive repo name if needed */
|
|
17
|
-
localPath?: string;
|
|
18
|
-
}
|
|
19
9
|
/**
|
|
20
10
|
* Analyze git repository health for a site using the GitHub REST API.
|
|
21
11
|
* Expects a GitHub token to be present in the master config under `github.token`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"site-health-github.integration.d.ts","sourceRoot":"","sources":["../../../../../src/components/admin/site-health/site-health-github.integration.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"site-health-github.integration.d.ts","sourceRoot":"","sources":["../../../../../src/components/admin/site-health/site-health-github.integration.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAM7D,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,CAgHnM"}
|