@pixelated-tech/components 3.11.0 → 3.11.3

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.
Files changed (35) hide show
  1. package/README.md +17 -106
  2. package/dist/components/sitebuilder/form/formbuilder.js +2 -1
  3. package/dist/components/sitebuilder/form/formcomponents.js +28 -0
  4. package/dist/components/sitebuilder/form/formemailer.js +29 -1
  5. package/dist/components/sitebuilder/form/formengine.js +3 -0
  6. package/dist/components/sitebuilder/form/formextractor.js +2 -1
  7. package/dist/components/sitebuilder/form/formutils.js +1 -1
  8. package/dist/config/pixelated.config.json.enc +1 -1
  9. package/dist/scripts/config-vault.js +7 -5
  10. package/dist/scripts/config-vault.ts +7 -5
  11. package/dist/scripts/pixelated-eslint-plugin.js +190 -0
  12. package/dist/types/components/sitebuilder/form/formbuilder.d.ts.map +1 -1
  13. package/dist/types/components/sitebuilder/form/formcomponents.d.ts +11 -0
  14. package/dist/types/components/sitebuilder/form/formcomponents.d.ts.map +1 -1
  15. package/dist/types/components/sitebuilder/form/formemailer.d.ts.map +1 -1
  16. package/dist/types/components/sitebuilder/form/formextractor.d.ts.map +1 -1
  17. package/dist/types/components/sitebuilder/form/formutils.d.ts +0 -1
  18. package/dist/types/components/sitebuilder/form/formutils.d.ts.map +1 -1
  19. package/dist/types/scripts/pixelated-eslint-plugin.d.ts +76 -0
  20. package/dist/types/scripts/pixelated-eslint-plugin.d.ts.map +1 -1
  21. package/dist/types/stories/sitebuilder/form.honeypot.stories.d.ts +20 -0
  22. package/dist/types/stories/sitebuilder/form.honeypot.stories.d.ts.map +1 -0
  23. package/dist/types/tests/components/general/sitemap.test.d.ts.map +1 -0
  24. package/dist/types/tests/formemailer.honeypot.test.d.ts +2 -0
  25. package/dist/types/tests/formemailer.honeypot.test.d.ts.map +1 -0
  26. package/dist/types/tests/formengine.honeypot.integration.test.d.ts +2 -0
  27. package/dist/types/tests/formengine.honeypot.integration.test.d.ts.map +1 -0
  28. package/dist/types/tests/formengine.method.test.d.ts +2 -0
  29. package/dist/types/tests/formengine.method.test.d.ts.map +1 -0
  30. package/dist/types/tests/pixelated-eslint-plugin.exports.test.d.ts +2 -0
  31. package/dist/types/tests/pixelated-eslint-plugin.exports.test.d.ts.map +1 -0
  32. package/package.json +11 -11
  33. package/dist/components/general/sitemap.test.js +0 -19
  34. package/dist/types/components/general/sitemap.test.d.ts.map +0 -1
  35. /package/dist/types/{components → tests/components}/general/sitemap.test.d.ts +0 -0
package/README.md CHANGED
@@ -85,8 +85,8 @@ Pixelated Components is committed to creating inclusive web experiences. All com
85
85
  ## 📦 Installation & Setup
86
86
 
87
87
  ### Requirements
88
- - **React**: 18.0 or higher
89
- - **Next.js**: 13.0 or higher (recommended)
88
+ - **React**: 19.0 or higher
89
+ - **Next.js**: 16.0 or higher
90
90
  - **Node.js**: 18.0 or higher
91
91
  - **TypeScript**: 4.9 or higher (optional, but recommended)
92
92
 
@@ -105,10 +105,10 @@ pnpm add @pixelated-tech/components
105
105
 
106
106
  ### Peer Dependencies
107
107
 
108
- This library requires the following peer dependencies (install if not already present):
108
+ This library requires the following peer dependencies (install if not already present). Versions in examples match the package's peerDependency policy:
109
109
 
110
110
  ```bash
111
- npm install react react-dom prop-types
111
+ npm install react@^19 react-dom@^19 next@^16 prop-types
112
112
  ```
113
113
 
114
114
  ### TypeScript Support
@@ -162,86 +162,12 @@ npm run dev
162
162
 
163
163
  Visit `http://localhost:3006` to explore the admin interface and see components in action.
164
164
 
165
- ### General Components
166
- Reusable UI components for common patterns:
167
- - **Accordion** - Expandable content sections using native `<details>` elements
168
- - **Callout** - Flexible content highlight blocks with image support
169
- - **CSS** - Dynamic CSS utilities and styling helpers
170
- - **Image** - Advanced image component with lazy loading and optimization
171
- - **Loading** - Progress indicators and loading states
172
- - **MicroInteractions** - Subtle animations and interaction effects
173
- - **Modal** - Dialog overlays and popups
174
- - **Semantic** - Semantic HTML structure components
175
- - **SidePanel** - Slide-out panel component for additional content
176
- - **Table** - Data display and table components
177
-
178
- ### CMS Integration
179
- Headless CMS and content management components:
180
- - **WordPress** - Blog post integration and display with automatic Photon CDN URL processing
181
- - **Contentful** - Headless CMS components and utilities with delivery and management APIs
182
- - **PageBuilder** - Dynamic page construction from JSON
183
- - **PageEngine** - Advanced page rendering with Contentful integration
184
-
185
- ### UI Components
186
- User interface and interaction components:
187
- - **Carousel** - Image and content sliders (Hero, Reviews, Portfolio)
188
- - **Forms** - Form builder, validation, and emailer components
189
- - **FormBuilder** - Advanced form construction and configuration
190
- - **FormComponents** - Individual form field components and utilities
191
- - **FormEngine** - Form rendering and processing engine
192
- - **Menu** - Navigation components (Simple, Accordion, Expando)
193
- - **Tab** - Tabbed interface component for organizing content
194
- - **Tiles** - Image grid and tile layouts
195
- - **FontSelector** - Font selection and Google Fonts integration
196
- - **CompoundFontSelector** - Advanced font selection with multiple font families
197
-
198
- ### Development Tools
199
- Components for development, configuration, and site building:
200
- - **ComponentPropertiesForm** - Form for editing component properties
201
- - **ComponentSelector** - Component selection interface
202
- - **ComponentTree** - Visual component hierarchy display
203
- - **ConfigBuilder** - Interactive configuration builder for site settings, metadata, routes, and visual design tokens
204
- - **ConfigEngine** - Configuration processing and validation engine
205
- - **PageBuilderUI** - User interface for page building
206
- - **SaveLoadSection** - Save and load functionality for configurations
207
-
208
- ### SEO & Schema
209
- Search engine optimization and structured data:
210
- - **404** - Custom 404 error page component
211
- - **FAQAccordion** - Interactive FAQ component with schema.org markup and search
212
- - **GoogleAnalytics** - Google Analytics integration
213
- - **GoogleMap** - Interactive Google Maps component
214
- - **GoogleSearch** - Google Custom Search integration
215
- - **JSON-LD** - Structured data schemas (LocalBusiness, Recipe, BlogPosting, etc.)
216
- - **Manifest** - Web app manifest generation
217
- - **MetaTags** - Dynamic meta tag injection
218
- - **SchemaBlogPosting** - Blog post structured data
219
- - **SchemaLocalBusiness** - Local business structured data
220
- - **SchemaRecipe** - Recipe structured data
221
- - **SchemaServices** - Services structured data
222
- - **SchemaWebsite** - Website structured data
223
- - **Sitemap** - XML sitemap generation
224
- - **Social Cards** - Open Graph and Twitter card generation
225
- - **BuzzwordBingo** - Interactive buzzword bingo game
226
- - **Markdown** - Markdown rendering component
227
- - **Recipe** - Recipe display component
228
- - **Resume** - Resume/CV display component
229
- - **Timeline** - Timeline visualization component
230
-
231
- ### Third-Party Integrations
232
- External service integrations:
233
- - **Calendly** - Scheduling and appointment booking
234
- - **Cloudinary** - Image optimization and delivery
235
- - **GoogleReviews** - Google business reviews integration
236
- - **Gravatar** - User avatar integration
237
- - **HubSpot** - CRM and marketing automation
238
- - **Instagram** - Social media image integration
239
- - **Flickr** - Photo sharing integration
240
- - **PayPal** - Payment processing
241
- - **ShoppingCart** - E-commerce shopping cart functionality
242
- - **eBay** - Store listings and shopping cart
243
- - **NerdJokes** - Entertainment content integration
244
- - **Yelp** - Business reviews and ratings
165
+ ### Component index
166
+ The full component index and API reference live in `docs/components.md` (single source-of-truth). For interactive exploration, run Storybook: `npm run storybook`.
167
+
168
+ - Quick link: [Component API reference](docs/components.md)
169
+
170
+ If you want to browse individual components interactively, run Storybook: `npm run storybook`.
245
171
 
246
172
 
247
173
  ### Utilities
@@ -268,28 +194,6 @@ Comprehensive site health monitoring and analytics:
268
194
  - **SiteHealthDependencyVulnerabilities** - Dependency security scanning
269
195
 
270
196
 
271
- ## 🎨 Visual Design Configuration
272
-
273
- The ConfigBuilder now includes a **Visual Design** tab that allows users to configure visual design tokens such as colors, fonts, spacing, and other design system variables. These tokens are stored in the `routes.json` file under the `visualdesign` object and can be used throughout your application for consistent theming.
274
-
275
- ### Features:
276
- - **Color Management**: Primary, secondary, accent colors with color picker inputs
277
- - **Typography**: Font family and base font size settings
278
- - **Spacing & Layout**: Border radius, box shadows, transitions
279
- - **Form-Based Editing**: User-friendly form interface powered by FormEngine
280
- - **JSON Storage**: Design tokens stored as flattened key-value pairs in routes.json
281
-
282
- ### Usage:
283
- ```tsx
284
- import { ConfigBuilder } from '@pixelated-tech/components';
285
-
286
- function MyConfigPage() {
287
- return <ConfigBuilder />;
288
- }
289
- ```
290
-
291
- The visual design tokens can be accessed in your components via the config context or directly from the routes.json file.
292
-
293
197
 
294
198
  ## � Quick Start
295
199
 
@@ -336,6 +240,13 @@ See our detailed [Roadmap](docs/roadmap.md) for planned improvements and refacto
336
240
 
337
241
  See our comprehensive [Testing Documentation](docs/testing.md) for test coverage, setup, and strategies.
338
242
 
243
+ Quick conventions:
244
+ - Unit & integration tests → `src/tests` (filename: `*.test.{ts,tsx}`)
245
+ - Shared harnesses / fixtures → `src/test`
246
+ - Storybook stories & `play()` tests → `src/stories` (run with `npm run storybook`)
247
+
248
+ Following these locations keeps CI discovery and story-driven QA consistent across the monorepo.
249
+
339
250
 
340
251
  <!-- CONTRIBUTING -->
341
252
  ## Contributing
@@ -3,8 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { useState } from 'react';
4
4
  import PropTypes from 'prop-types';
5
5
  import * as FC from './formcomponents';
6
- import { mapTypeToComponent, generateTypeField, debug } from './formutils';
6
+ import { mapTypeToComponent, generateTypeField } from './formutils';
7
7
  import { FormEngine } from './formengine';
8
+ const debug = false;
8
9
  /* ===== FORM BUILDER =====
9
10
  Display all the components for a Form Builder -
10
11
  Element Buttons, Element Details, and the Form */
@@ -158,7 +158,10 @@ FormInput.propTypes = {
158
158
  maxLength: PropTypes.string,
159
159
  placeholder: PropTypes.string,
160
160
  autoComplete: PropTypes.string,
161
+ tabIndex: PropTypes.number,
162
+ style: PropTypes.object,
161
163
  "aria-label": PropTypes.string,
164
+ "aria-hidden": PropTypes.string,
162
165
  min: PropTypes.string,
163
166
  max: PropTypes.string,
164
167
  step: PropTypes.string,
@@ -466,5 +469,30 @@ FormFieldset.propTypes = {};
466
469
  export function FormFieldset(props) {
467
470
  return (_jsx(_Fragment, {}));
468
471
  }
472
+ /*
473
+ FormHoneypot — MVP
474
+ - id: "winnie" (canonical)
475
+ - default name: "website"
476
+ - inline off-screen styling: { position: 'absolute', top: '-9999px' }
477
+ - aria-hidden + tabIndex -1 + autocomplete="off"
478
+ - no label / no validation / no required
479
+ */
480
+ FormHoneypot.propTypes = {
481
+ id: PropTypes.string.isRequired,
482
+ name: PropTypes.string,
483
+ };
484
+ export function FormHoneypot({ id = "winnie", name }) {
485
+ const hpProps = {
486
+ type: 'text',
487
+ id: "winnie",
488
+ name: name || 'website',
489
+ defaultValue: null,
490
+ autoComplete: 'off',
491
+ 'aria-hidden': 'true',
492
+ tabIndex: -1,
493
+ style: { position: 'absolute', top: '-9999px' },
494
+ };
495
+ return (_jsx(FormInput, { ...hpProps }));
496
+ }
469
497
  // Re-export FontSelector for use in forms
470
498
  export { FontSelector, CompoundFontSelector };
@@ -7,16 +7,35 @@ subject: ""
7
7
  }
8
8
  */
9
9
  export async function emailFormData(e, callback) {
10
+ const debug = false;
10
11
  // const sendmail_api = "https://nlbqdrixmj.execute-api.us-east-2.amazonaws.com/default/sendmail";
11
12
  const sendmail_api = "https://sendmail.pixelated.tech/default/sendmail";
12
13
  const target = e.target;
13
14
  const myform = document.getElementById(target.id);
14
- e.preventDefault();
15
+ e.preventDefault?.();
15
16
  const myFormData = {};
16
17
  const formData = new FormData(myform);
17
18
  for (const [key, value] of formData.entries()) {
18
19
  myFormData[key] = value;
19
20
  }
21
+ const hpField = myform?.elements.namedItem('winnie');
22
+ const hpFieldVal = hpField?.value.toString();
23
+ // If either DOM or FormData indicate a filled honeypot, silently drop the submission.
24
+ if ((hpField && hpFieldVal.trim())) {
25
+ // Prevent native navigation where possible and mirror success path.
26
+ try {
27
+ e?.preventDefault?.();
28
+ }
29
+ catch (err) {
30
+ if (debug)
31
+ console.debug('preventDefault failed in honeypot guard', err);
32
+ }
33
+ if (debug)
34
+ console.info('honeypot triggered — dropping submit');
35
+ // Ensure callback is invoked so calling code shows the same UX as a normal submit
36
+ callback(e);
37
+ return;
38
+ }
20
39
  myFormData.Date = new Date().toLocaleDateString();
21
40
  myFormData.Status = "Submitted";
22
41
  await fetch(sendmail_api, {
@@ -34,6 +53,8 @@ export async function emailFormData(e, callback) {
34
53
  }
35
54
  return response.json();
36
55
  });
56
+ if (debug)
57
+ console.debug('emailFormData — submission data:', myFormData);
37
58
  callback(e);
38
59
  }
39
60
  export async function emailJSON(jsonData, callback) {
@@ -43,6 +64,13 @@ export async function emailJSON(jsonData, callback) {
43
64
  for (const [key, value] of Object.entries(jsonData)) {
44
65
  myJsonData[key] = value;
45
66
  }
67
+ // MVP honeypot guard: check both the canonical id/key 'winnie' and the
68
+ // FormHoneypot default name 'website' to cover both DOM- and JSON-based calls.
69
+ if (myJsonData['winnie'] || myJsonData['website']) {
70
+ if (callback)
71
+ callback();
72
+ return;
73
+ }
46
74
  myJsonData.Date = new Date().toLocaleDateString();
47
75
  myJsonData.Status = "Submitted";
48
76
  await fetch(sendmail_api, {
@@ -26,6 +26,9 @@ function FormEngineInner(props) {
26
26
  console.log("Generating Form Props");
27
27
  // Create a clean copy without non-serializable properties
28
28
  const { formData, onSubmitHandler, ...formProps } = props;
29
+ // Safety: default to POST to avoid accidental GET navigation (prevents query leakage)
30
+ if (!formProps.method)
31
+ formProps.method = 'post';
29
32
  return formProps;
30
33
  }
31
34
  generateNewFields.propTypes = {
@@ -3,8 +3,9 @@ import { useState, useEffect } from 'react';
3
3
  import PropTypes from 'prop-types';
4
4
  import * as FC from './formcomponents';
5
5
  import * as FVF from './formfieldvalidations';
6
- import { capitalize, attributeMap, debug } from './formutils';
6
+ import { capitalize, attributeMap } from './formutils';
7
7
  import { FormEngine } from './formengine';
8
+ const debug = false;
8
9
  /*
9
10
  ===== FORM EXTRACT =====
10
11
  Submit a page URL of a form to extract all form elements and
@@ -1,6 +1,6 @@
1
1
  // Shared utility functions for form components
2
2
  import { generateKey, capitalize, attributeMap } from '../../general/utilities';
3
- export const debug = false;
3
+ const debug = false;
4
4
  /**
5
5
  * Maps input type to form component name
6
6
  */
@@ -1 +1 @@
1
- pxl:v1:3f481a2cd7f5ad57638e8bee:855f0159f90b4111272402268a590c55:0bb71ae7ab631b7113b6af9bc361b176295904022f96cd6976d6d733472eef8c82e55e0b974e4baa74e82b93c695add88152fda55bf6273532b41acda35af8d326b2962ad5180a25d42486a2581597d85b2d530cf1248e43df471ba83f9d924ab279856d3db1060cc5e5d7b6b678f3f390d815fe3f3ab9ef90f57e1989d0986d4fd3a45bd44b24ced99f19f1a1c33a5e57446b94d991a65d498c2d9dc3e7f24ceb86ca890d24e951d74ff709460f4a9891568f2673e348653d6f4ed3d695456e25f19b2c86851b2b63d0b8e816a36cf0b72707352fd074a020fd0d38be126372980bc9bd3dba99bc69fb0bc7fd0ed8bb16f54cbbfcda01a424e7141d44874e372b826142e44a430f6ae63ad2d1898777a76ab249df5eb1f1f2b75a0980977d7b6e203d2957a654a56d73f3048a0c3335efee7406ac3957a14afc5da6880226a762c075b5d9bf022ad4dc76764259c562e3ec7f46ab1d30318e6798899390f0ae0c7c971af758360d38e07fdb431319a282fb6ac9db7bd5d61f794b667e25284324ce2f38ea6b6758f686883d7d357403dff548190206af30d042e43881e5db3e8922edf7f3404dc52113a752dc14b10c31bcf0830d22388c3a6348f15922dd78ef356c0719bcd0ace9feda62f4b903c7cdd03a6ac96f296bf2f29881696ea125cfe2da984aca88020f0a3c96f1b5d641fc32b0d7c3850657762eb2dd151d0a7f4e774e0e228cbd86f4691c44e3d205af4f659b66da5f63dc9593f7887b8606eb5438e1436124101304cedc19fdb8deb56a8da925ff89f43acb2a7fc1c01c14427048aee2e7e01a6722ccc0dc49c0b77feb5c7ed9f55df85118902caafa981bac1397b931a7e9ce1150a5c8278f9d1217297a08eda88fdc95c69f62f7f0ed5d54e944b924d88c2c9488f06b715a9f07f7cc673dc704b90c353c26afcf3728f8f4707d47b8ef883a00feface769fdba93988ac2a57579b5b26160f2d8a51437365554560c351d6d1620d5334b099761c3d7acf463016b765faa45ca19bd384de2612608a41969e5ad2384a22defae9c876111fd700b832682cdc12a57218f11057c6f87c226a1de74f9f163305a8fecf6d2f5a958727620a4bbee2738ae4fc4c975a3162d19e9afdfe2a3cf4d1922959a3f7006e123b212ef7f00cc71c73c44bffb8609f72351aee8e37ca67214408762983c4cc03e5c5ec958208f695c46199db6f10a4b96f5837eec22ca9ae2a68ce2b04c991b8ff91c9cf553a65d30030ffc795e24ead8982488abafa11b23ade4d2fcf72ffea2995f1e4634584ddefe6a7056f13312915d454f4a1a5580398cf1330346debe07c0770069b257e4ad42930fd9c0af406bd4e3a001f8a08cbc6bee058b0688d620f4dce2d2d26626f3c872965b6dece263a27a3407d701c0174c3577dcb914af8fbecdb8c7c6895d920df15f49b3f8d7494674912393e26c3842e5caec83a3c2537390a5f27db328af1c0f84c6fcd689c87ee1d415cc4abf9b778c2a74a41c2218fc983aa1b8ed73538ed5efe8fae9535776b4d0943a33a8a942ecb66b7b2beb9db037d1b0f25489316077718d38d3fa27666c25314f04763d5993efbf7112fd70f4ecdc254c6dc368a8bbef4724014edb3ee74f0cbc9f7ed2907cb8334ff9bebca990df0522b3af52d931b034adda04b333b8ef484b951b0796c2904852b8f90e74e9163179ef2c69727edb07ffa87e82176a12ed7a5e54cb88104e7fb0cd9abd9ad36ff505a43d649b2912d565c55d8c50a720c83a3c15871b7a20974416cdeb5fa66c233fba989c4892e6af28a678418340e4c056958ab23eac62b8cbeb02a54a557555bc6333df228fd65d19141e1d84c0838b050ee77ccc5c7ae7e20b8cf2797444051882d26a106491c5d617a9a4391aac36a8cd317cf8be339f91785441df7d5b39005ce862c5d8958199aec9fa8e483945b4eef9edc795ed5bb76c58d0767cadf35dc99b910a6b29783c610eeb13d23ba33cd2df2a435b41fceb2bb9d8fe181b7efdb219d94a6b8f5d62b1258200d82bec1dcc64ec10af2ca7598646e82cbf4297c98fdcba0e729db3ccd547d734696691b6d36c41894784d0309402e52cde4261029821a09ed0d084478faaa10bf4354c29289cd857b13576fbfeb8b1dd934c8d20eff3fa43b95174bf2e2b14e7b8429907e595d90cf9e7a770273d95cc0debe84471e2d4d84136186c9382c8d4ee637d0f251fe62364806c315983e2c6502d268a2e6a75f37150b3d851dc50ca02dfb0117154633a38a51f9247d5eea4163186b21fa19926a89f63755aeaf62f98ab840c15afde3b011e5ba08e7931afa38d4a48b932723de97e5c8ce8e19087dc818797aa01fa542de7e5edbd2bec792e59b29ff81377ac305a9b8182e70af480b49a45050f79db912297cfc94b94d78b520fd72ecdcac4cc24a79f902d71cccc7d69b9e97ca3db8e430f94b40deacff153230ecece173c25249d673ab1fb45e3b96c7610f51bf456007ff1762eacb0c3ddb9822a6bc322709a963230ac7a836e27dc9bd39bc77482dfb2f1816fab10f99edb0d8c2828e23ebc5eb63946c8af65d41ec66ff80f062b97ae98dd5500f36aeaeb04c3e920907b0004aa30a719c7e4c5958f971a1a21ad77a775cb34ecd31a0f6a42a17c66f4717cda306777aa60d3414e2121807aa3d1167c7bd37839fb5cc32a293b86f4fa49ce751d926cd93bcacf829dee86ebfc83f1d0f7482728446b01e61abbe6169c6132cb9aa0494286e8713f82e26de0f909abeab2b06c0c8ba9acc466b078f9e18ee99779ebcfa7bb3426eed70b8d1d1118bd71d5dbd65034ccb7eed28bbd3963b5e478a4e13abd5b652b324d44178968d2da2dade17656deff8c22e456368ab1b737a01de3393e9523fa59fbec9cde95a594a69940ff91f63cd657ae0855d07e364ce7036801a3c5646ea2e380096cda97045f2e7f180b428fdcb2bbf59dbee200a2711f6c26c3c4776fdafd90e3d29aedaee47552daac8e0abca599757b38579a787eef6deee54d6eb51b567b23dbb59e959dd016b1c9b2a505472d30f7d262273933ffb8494f8c05369cf09806c5682eea402f627b399a899c48e563b50e87da9af357cabfb3b08d6a594bb2d7961c4d0c3a39094af2048b813999ebe006c11f61afe95cea05b046191079325570245c6055351030f4168c2b26ad06fa9476272eec40621d4511ac615c83a704113d976dc7cf9752251f87628ae8a3d2b7eaea92fe492ac3f80ad5db06487514e89b3335b81799e4a8937c88ebef5901a2959b1f72ddeaa3bf350cdf1cd29715d0aa9fadd874f505070bb9eb3e3ecc42147ba51e7bd6f45c20ac5aafd1088115907a674c267208d08268c991677b365dab96235134e866e9ea8bcfc2a48b130b78fc2b39c412479b24bf91b7c3525f447e9d3cea3902fdfaacac45500d03971a7f7a056e976c1a101d6c0011f99dc23e0c1a215ecfd3cd146b2d4cbe49ba950dd1a5c2675a1ab4ef6f6191e12e3819a725fac94018a44e24c50e747ed198f112e291f4d3bc61f06655abbf1e533878cee855bcf9cb44c5ec18c384ad81026282345eec371aab5808f2063faea69d0971006455f3d7b10e14d808c7168534b0302efd787ae1ee073b6ce35c578b8c67835b733a6096f01190cb043cd6a3241923eeb36568163e7a53f75800077b2be6ba5dc2d7f79a38a2614b19a612443bfb48fde9fbe3b464b49a0f95dd27c73800f06e952e04defa86b76c4e26c9251832c0b4ce8e281f85f6d0fb702ec2fa4a8e919cc7cd81881f3e12c076fcc5b540f30f600e2a1f06f0a9e21841fdc8f4a53062239c8ad83a9c27802d8710d0e1e5156fdc05d4f0de08f5900cd58a51de26c0f3b887ba5011c9cc3faa244b971d573d3c220768425576b98cc637c823084fd72dade3ec8708d350e822bb738edf9c24ac8992ab2b61f41758ff64c6eba52a6bc6b46e9b112adf808d8f4f35e0c83298ff7100d832e574700ca0a4838a671ddf9b13f544781aa2106b116912df6c5975ab71593269597ac8d52bfc3259b6c00f4247f8468bc579990886ca867a2019687dbf33f3a323b3d2e55b795d6d8d4ec7e96c35c94534fac4ebfbbccada5187d21b4c192e86f999e8cc4dad4fceb9b35a07104e7433e1e9deb891533a57b0a97ec630ed8c0028ea511917fa5f49c71eb330cb9e7cb134e81ec09d30994dd87b4be8aa2b37933267a84ac2ae8b3a1ac45de61dec9c52061d7ebc8be55d9c59c47f883ca4d1176aa33be527c57eef7925850dfa55373c37a085c8b36564fbab9ead5b71e17a6c84e1e7671fbc78ec37333684a6a32f8ff212346178fa7d40cca347bf59aeb5342f373a05b8228efcdb7c4e155ce6f11793f33edab5c91f17072a4c8887c45669ffff60289710e544c95e7f7a9faabff8d2a80a3edbf238bc326384880cb0792f276fb065c9e906332d7fea0fff599f93b1ecba729ad25088d69a2c598bdf393ccba9c57fe975dc39eec2300d94fcdf4625ffeb025c5abf5d92c41022ec6baa2a856444fb5b652fc3828d886781275aab5fa67da55a4c4a07c84b3b07fe066f2f74f9407c51a4dcc0ac1b62e33dd478dc342efd89b3da289662e33392ec157d054666b1f8ea3ceb304e0d0fbfab2d25759ad1ee93cf85d0296a0884d4274f4ab318123fe694c1915f8fbd0a1953e5c09b4ea1da5503eff6628ed7b053d788766ddc02850fa5b00333e26a7fc221269e1b28fb1c65092a700369a681a61937b0016c6e65fa26c3991dcf68f899ae669fadef453f6a54168ab03e8918a88f208a8f45491bb7acd1ea38132f2dbdcd2f612bd1d6540d67c7c0b9bc391708c4344bb6a225136b2e60b00b71f53c9966fcf3e6434c998a8ecb565f47a28099b9e2291e66dfe53ee2f0f6ef6e3e214892bba0d0e8c8490391e29efdd10a93b36ed18f43c744553e82d89cf7e3bb1fa041aef7f76f4f1f1f3d695dca352dbd1b6814c0fa6023dced8caa314261869933b5241532425357787c4113a2c06c0715d7130fde3ec4b2dea5c818b563ef6c8ed82e2ff531239d81b175a366bc7787804734bb65a98e18128310ea7c7d5b08e67a157ad4eb56eaf65fa32b9ed2ecd04474b270f691f1dec4b3700ed771b59cf68a01ad1bc1fbd44d25290b2789fcbc904
1
+ pxl:v1:eb6d72dafab78c0eefe9d579:4138458b03a639bfb6a82644b3fd2e1d:eaa2c5ebc40c1939cc1532f810b308d2b32bcc06ea5ed0127a0da346f57f8e244d32648b2a08b3666f30c3bf6a475d5ab4c2c749772f77bd95a7bddc0884ec351ba4973c7a381cb0dbf97adc3c66fbeb7e14b239589f9e080dbe51b66158194d49023f903bd07f322be8bb4c667042b1c66c0d956c04c01fdd84200eaad64bdf626693e900ef5f849b029fe48875bbdad00e90ae804088a18eae59112206c9a7abe93e61cc180f5588ae6f2f33748f746d36e0f1ddd43d7146273a1af62cf68b210527a9bdbe4ec1524abc4a4d9bc4b5abfe3478ae58d74f94a13e7deea1d3e2cbe3ffc735ed82cbd243b44b4bb13c5a1f5830f9a0495e712d189e4edbeaccdd0a6d7cca095bd89f2a058f7d765bd56d678835bd736e083b0f3e455eb48baed144c62370d9e2d6e5460334712af4ae6dba0cb45d0f34fd862299118d05a41fc2b448ddc25198a5d22d49013572a8bf451828df02de3cf85e660fe5e33c4287407758cf815d0ae0549faa075769940c7571570235e134055444991edffb76a13740a7bd6617b1cb172679f2c52a2d31e8320c3d7ce91d8547165685fcd3269cda3f6913f98bacd9d547c440ea27fe5119fc5a2410c98665cb95b27ca4e8a59afd050d3e69cd6602ee2e45122692a8050707c3065e7051e81f650894d657db6f3f30eb1391b19632ae2c61145c4d151d92ac90e190ba99e243bd5e17e591252d9e6209f7063e451fd45dac5e74e50d035c2f2709192670aeaeae43a3b0eb1fa678a22a032b453abd773e581c82a8caf701be8e99a7ff9e69dcabc18bd074afb7faeced2c5f5a1fc7199ba5980ef54674aa70edfcaa82c3e1bc72b73fe30eb4dd7d45087aed84aec5aae9b64f482a369bcd63bb7d3b67511ac50907af175824bf4c38b3dfbfb335385f3b632cd45cca7b245bd4269e8fcf38e4c3f9215abc560ce31ab3ad602ca7d2c1c4bab91d2d7feac7f46fb7bf21d70a08929396d073e38ba3eba8ff9cd465982d8f097b7e7b773db65ca5310101856926f5f269396086c0a44112577f6502e80b076be27c57b23bd0e26abf0eabfabbaf03730bdb41f747e67625390a3598c6151a388c7071efa45368f56ea6a10f6714c4ad61b35316e3780200eb45a30eace17e01d388f31fc201b20bba22715b357a54eaf9be45eb15a8d79b97368de3083276d45a81a6998b29adc4580cf28fbfb35ef3bdd32518d16614211a8bd4faecaeadecce6c4bd0934c2fbc98f3c5b26dc1ce4c5b7fd0fd3631ec6623dd61219fadc4540020d8ac8fba9b56846247165635e6702277dc1085ff28db46af7e253333657837692196f729e739fb2af6e2b4a8ffb9107eda51146acacf40f51e20e36d63bb68b4de074221e5c48c9fab56e864e29d65231a7519de47e12e2400b3086d955e6a51ad602ad51610fd789d2928b705b23a489101dcaa528fa56b1a693ce764e401ee9527446a3ae0041b4039c89564cf1b56a0ef34a8d9c6daf2df951e57bcdfef0841aafb609d4d72366b0aea29cb7890e3f14e16e73f402319f25627e1461f39f573d40303609607d685dcf9bd31368c7b8e981fc471dc83fecf6884c0f87be924ecc401134fc00857f9dae345e4d2ff40a5a693318d05b3f6e5835a26f900c36a92bd41fd0ce7f81b1c37f45f882d8355562f85b6bd92c080366b76b83c653cbc913664576a2d8178968fd4a68ef598e3c5e435199931dd68ba414841912ebdeb28130740bfbf74d8bd2c5a7abfc3d6003702263499505ec47b213053cbf9e062764c6bc1b93279692c8857cfb542606ada1e8eac54f0b941e33e6fee04f2eba2a7da357620eea334dc52c661020b31fd42047744dde9245f637a6e87e694a65ecf13ce0582045145db1804061cc13226a30fe8a268cb28786d4ed7e1562cd217b34af307e1d4eb7079e9a15a78e493c7bccc98825795ba58d4ac821cd678763a85263b2b754c2da5d95245caade7565a228402bf01753740b95c14e60ea6b01314df5d15308fb5e2320c9d6fd98b9a230c33afc432b3785078f09e4732e4b1289ea9f630a61d14ff32168a739883a11d4f825342e3790ae8ea9297af874bcd432d818c4739a5d61a73607e14b1999dc43e161da4ea1c86906d96e6eaa62f921bfad0f5b2a7bd84dbaeba8f3c91b5999d33d7c5c478feb6b12c68de9bb7bf0c0fea7e891f3418aaac4496e73cc0c595801ab06a3a697aa3dab77cacf9b690c688d3727547b0f9c4f386f977aca556a67615ab7960765b7b58ab400b16d6b1f971d42c3b63ee273e0cb327c47a8675daf82340f34f6ed5723c4bbf7e12152acd1f19bbaef8487c9d289f5a7d9cd4d2349d7919fa1ddc57932a9e6f490d849e40ace7ccf6a7466333f0450f5db31cd2f34733613d0638ec66888b111b222739311e34ec9ab9ccea4d2c890dc3ec3a566f9b4adf01962e3486dc6d51c928b16937d6bceffe6cabb3a17444466829b5523f3b7497d8a1cf101b237c14a1522bde1bafd346596715cc47a792462aef35b4d4945e92c5791af72e571171caad124cd1732d0faf2066dbdc360437c52eccae79000e2a376b60997b00ec3e001b76ca894f25ab65996c9c9df5cc44a2be077bff590c9e597a105d58d38366aab9ea19627b9c8b50eb304f87f99db6ce973306b91f2a4033bbbe46b8c175ca525e26a841d40a76606e4607fbca40d6547a0b0ae94bccb7aeb74c0b2a62fad12c022d567b1eee35abe506fe046e87663e18da17fd37028c620e7652d1832203f8faaafdebc24c7247bf6e6a0fac189471fb42e146e962fe07302f4589b6a4edb1125b6870ee8c0650744989694ecd8dcfcd822c6018c0f21eb7f3bd60f33014302ee34822bed13bf9cfc471fdb660388a489bb305730f173a817607eb63df9f36f10665934be8d5c36521ceb2b4d3976746d2c23a520bc5b7d1b1ee38a031c3c91df5f02f4e992aa511e52fbe0d41bc6b55c361eb0542185cc911941cc088e2ef937fd855f99dbcf483dd00ece10433157abf53a3543f68dd8af2d79d474daf1115fbfb8fc1c130caf01d5c03a13b16cfdd4b35b750cc5655e68c6835aa9c59da99eb01e5f1ab49b31829de16824c86e57c27823a7ee9f1746d6ccfa733a0d670cbd7a8ab8dabcc3bab3efe319a89edd5afe48f2d59e6428ca91be477c85f3c80e3b1f1d6dbb4a1fca83d1fa8fce3875a4dca6bb299d6616e52796895253897330ffb0577b2db78de6d49c233bce6dc9151a3a9835ae4183515db2c6ceff19233fe5e838caaf1e6e2d6c3fcf1478db36516dabea111f91ba48d8ce771d87ae545526244add76dfa7eae914bea40b49abf7fc620e4ad892f941353bafb5155d71f17ec2f1203237ab3994fd82c998ab6d2ad62a4288fb24bd12ab90b34bd590edf2e7ac1feda516ef4e3cae4127a40d146416c54f2c7c5c5389d5f9b622e53bfa79e9b72d5d5e561e246e6ded3c30f7205926f76ce6fd41d9457e49997c5f3d2df9e6229b1b26913bf7f6017203950b38e2ba068a8cb4c47296f0da266f5f7bed3c400a18ec344b48475bd9b8aadca3c2d5bfcd62c4d7dcc2dcd02d59b6c11ab5d2e98dcec056a60b368efab9efe64fa67f518b48e2448ee0d5ec7a360dea54d11d85e606e2186d641aed98d74310caf9998500088d8b40e419d1e1f0fa3210416f962adcfa1126ca0f396fe3956f39a1ac2fb7b9b5f74eee81aac59a33d768fa5acf0e9d61fdeb32bc6eee488c78053d301b3b3705254a89f8f80ec3b527e2166272ce4847f2c9a867cf6a8f11ba7235d9ced0dac1ac524faf608ba973bbb3cbabc7c02e6be8b0f76bba4212bf94c042d61dfcde2d1fbea4ece31886c05c6a67e84a2b8864d874e8e7c3f10d02464b2f50b33029749a86be2d433f7d646a9fe79e71ac82658aa9102917307736d3c137c8e2b7a5ba6f7d29aa15c28200f20d71db8f26416f831b7ceaedc5cbc1e9b613eec6318b233f88e65b3ab18bade67d5d9a51e60a38ef0b021d8ac712f757022cd65884a8fa0d4eceff9f51d758f8e914ca7e5684b0c7d4a3bd5556a9cb87ae320197fb846fc73b6f0d1268a4ee141676fce515f114293bdbc1d6911e9c174c9e48f086fb9f07b3528529b3307de49d31b8c31ebab672e22f07e152edc0fa456a454a7d6f4f0a9c64fe4e4b4d7745fb9ade45658518bc8962e6446104d0108d12a0e648158b7cbc3388931ba3f623ec9767a04b23b030aec90f3d80678ef897026f1e3d51c9d31349f5732f5e4f1256f1a396a0d28d4619756b72cffff6302a543932289a690ac5bc9537dd97d7a0000a94afdb81b6ab14e462190397510861d776126f6e8609a25bee734ffe46d63e73187e0ff38c35837ae635f399a249e0310cbcf45b3d2d42337a99a98027c3721f4adbffe5852e4ea6695641129a51fadb30bcd6bb87fb0ab8a139e4b0d34b4197c81ac3fb8a07aa5183e89e06a45137cce9b586265ac1bfb8b80b863610c851fc40d371eff6d901db4c5ae7d888e705c61958a059e03d766f5402e14fb52636a0a67073a9fa13654d91ac2c96339b7806f12a5c48bb59c0032cbe6cb76f699010c8b908316e1f1a38de95b8ed7c21bbb4a938148d106905066604e13f140bfa61c658398fd81f6d41ec262350cd6ab7e53a7f0e45327fff179d7b34d0965154e041584e290c8feacd22d78889d41696982d702b5ce860edd17bfecaa9df1e7bbcd39cbd63e6b530035509ab2d4e4dba81a9877688baebd2e9eef7b16e1be4ddab2264b5707bd1ed755bd6c314f6875769fc010a6c13affee72fd4add31030612cc8fa75aa3d5a4393feedcb4a96790d18e62388ea28fe03619952645b3753a67f98c8e9b8105626acc3a200353fc87be6e7d1c67c6725ac46d9fc66860313921998ffbd8210c61edbf0daf149a59693132a38630a49df21bbef85a50df65bfd55177ea8d108de56649fd63a7c932f4bd415a7d124eeab1d1d125401ae94aa05a5ec31218dbaa30526e131b07572cfa9b0b93e82ef4478421da9b1780b3225bb47bbf3cb1360ab72abd9b781d957d7abdecdda6097ea5784fb709ad5ec0cdab2016deb326e079ba694b31461b6f5a465927ac72689daf787b4560fc6cfe0535663494c79bbfac815497b3c6a0c06a32dbe7da75b46ec4f7131c115673d7d38a3534e0d6a6d62d
@@ -77,8 +77,8 @@ if (command === 'encrypt' || command === 'decrypt') {
77
77
  * - Decrypt in-place and copy plaintext to .next/server/pixelated.config.json
78
78
  * - Validate JSON and emit a concise success message
79
79
  */
80
- function decryptPostBuild() {
81
- const DEBUG = process.env.PIXELATED_CONFIG_DEBUG === '1';
80
+ function decryptPostBuild(opts = {}) {
81
+ const debug = opts.debug ?? false;
82
82
  const candidates = [
83
83
  path.join(process.cwd(), 'src/app/config/pixelated.config.json.enc'),
84
84
  path.join(process.cwd(), 'src/config/pixelated.config.json.enc'),
@@ -92,7 +92,7 @@ function decryptPostBuild() {
92
92
  }
93
93
  }
94
94
  if (!foundEnc) {
95
- if (DEBUG)
95
+ if (debug)
96
96
  console.log('No encrypted config found; nothing to do.');
97
97
  process.exit(0);
98
98
  }
@@ -136,7 +136,7 @@ function decryptPostBuild() {
136
136
  // Validate JSON
137
137
  JSON.parse(decrypted);
138
138
  console.log('Config injected into .next/server/pixelated.config.json');
139
- if (DEBUG)
139
+ if (debug)
140
140
  console.log(`Decrypted ${path.basename(foundEnc)} -> ${injectPath}`);
141
141
  process.exit(0);
142
142
  }
@@ -177,7 +177,9 @@ try {
177
177
  console.log(`Successfully decrypted ${path.basename(targetPath)} -> ${path.basename(destPath)}`);
178
178
  }
179
179
  else if (command === 'postbuild' || command === 'post-build' || command === 'inject') {
180
- decryptPostBuild();
180
+ // CLI-only debug opt-in: explicit flag (do NOT use env vars for debug)
181
+ const cliDebug = process.argv.includes('--debug') || process.argv.some(a => a.startsWith('--debug='));
182
+ decryptPostBuild({ debug: cliDebug });
181
183
  }
182
184
  else {
183
185
  console.error(`Unknown command: ${command}`);
@@ -83,8 +83,8 @@ if (command === 'encrypt' || command === 'decrypt') {
83
83
  * - Decrypt in-place and copy plaintext to .next/server/pixelated.config.json
84
84
  * - Validate JSON and emit a concise success message
85
85
  */
86
- function decryptPostBuild(): void {
87
- const DEBUG = process.env.PIXELATED_CONFIG_DEBUG === '1';
86
+ function decryptPostBuild(opts: { debug?: boolean } = {}): void {
87
+ const debug = opts.debug ?? false;
88
88
  const candidates = [
89
89
  path.join(process.cwd(), 'src/app/config/pixelated.config.json.enc'),
90
90
  path.join(process.cwd(), 'src/config/pixelated.config.json.enc'),
@@ -100,7 +100,7 @@ function decryptPostBuild(): void {
100
100
  }
101
101
 
102
102
  if (!foundEnc) {
103
- if (DEBUG) console.log('No encrypted config found; nothing to do.');
103
+ if (debug) console.log('No encrypted config found; nothing to do.');
104
104
  process.exit(0);
105
105
  }
106
106
 
@@ -144,7 +144,7 @@ function decryptPostBuild(): void {
144
144
  // Validate JSON
145
145
  JSON.parse(decrypted);
146
146
  console.log('Config injected into .next/server/pixelated.config.json');
147
- if (DEBUG) console.log(`Decrypted ${path.basename(foundEnc)} -> ${injectPath}`);
147
+ if (debug) console.log(`Decrypted ${path.basename(foundEnc)} -> ${injectPath}`);
148
148
  process.exit(0);
149
149
  } catch (err: any) {
150
150
  console.error(`Post-build decrypt failed: ${err.message}`);
@@ -182,7 +182,9 @@ try {
182
182
  atomicWrite(destPath, decrypted);
183
183
  console.log(`Successfully decrypted ${path.basename(targetPath)} -> ${path.basename(destPath)}`);
184
184
  } else if (command === 'postbuild' || command === 'post-build' || command === 'inject') {
185
- decryptPostBuild();
185
+ // CLI-only debug opt-in: explicit flag (do NOT use env vars for debug)
186
+ const cliDebug = process.argv.includes('--debug') || process.argv.some(a => a.startsWith('--debug='));
187
+ decryptPostBuild({ debug: cliDebug });
186
188
  } else {
187
189
  console.error(`Unknown command: ${command}`);
188
190
  process.exit(1);
@@ -36,6 +36,16 @@ export const CLIENT_ONLY_PATTERNS = [
36
36
  /["']use client["']/ // Client directive
37
37
  ];
38
38
 
39
+ // Centralized, canonical allowlist for environment variables that are
40
+ // explicitly permitted in source (very narrow scope). Keep this list
41
+ // small and documented; reference it everywhere in this module.
42
+ export const ALLOWED_ENV_VARS = [
43
+ 'NEXTAUTH_URL',
44
+ 'NODE_ENV',
45
+ 'PIXELATED_CONFIG_KEY',
46
+ 'PUPPETEER_EXECUTABLE_PATH'
47
+ ];
48
+
39
49
  export function isClientComponent(fileContent) {
40
50
  return CLIENT_ONLY_PATTERNS.some(pattern => pattern.test(fileContent));
41
51
  }
@@ -419,6 +429,180 @@ const requireSectionIdsRule = {
419
429
  },
420
430
  };
421
431
 
432
+ /* ===== RULE: validate-test-locations ===== */
433
+ const validateTestLocationsRule = {
434
+ meta: {
435
+ type: 'problem',
436
+ docs: {
437
+ description: 'Enforce canonical test file locations (only `src/tests` or `src/stories`)',
438
+ category: 'Project Structure',
439
+ recommended: true,
440
+ },
441
+ messages: {
442
+ badLocation: 'Test spec files must live under `src/tests/` or `src/stories/` — move or add a migration note.',
443
+ },
444
+ schema: [],
445
+ },
446
+ create(context) {
447
+ const filename = context.getFilename();
448
+ if (!filename || filename === '<input>' || filename === '<text>') return {};
449
+
450
+ // identify test-like filenames
451
+ const isTestish = /\.(test|spec)\.(t|j)sx?$|\.honeypot\.test\.|\.stories?\./i.test(filename);
452
+ if (!isTestish) return {};
453
+
454
+ const normalized = filename.replaceAll('\\', '/');
455
+ const allowedRoots = ['/src/tests/', '/src/stories/'];
456
+ const ok = allowedRoots.some(r => normalized.includes(r));
457
+ if (ok) return {};
458
+
459
+ return {
460
+ Program(node) {
461
+ context.report({ node, messageId: 'badLocation' });
462
+ },
463
+ };
464
+ },
465
+ };
466
+
467
+ /* ===== RULE: no-process-env ===== */
468
+ const noProcessEnvRule = {
469
+ meta: {
470
+ type: 'problem',
471
+ docs: {
472
+ description: 'Disallow runtime environment-variable reads in source; use `pixelated.config.json` instead. Exception: PIXELATED_CONFIG_KEY',
473
+ category: 'Security',
474
+ recommended: true,
475
+ },
476
+ messages: {
477
+ forbiddenEnv: 'Direct access to environment variables is forbidden; use the config provider. Allowed exceptions: PIXELATED_CONFIG_KEY, PUPPETEER_EXECUTABLE_PATH.',
478
+ },
479
+ schema: [
480
+ {
481
+ type: 'object',
482
+ properties: { allowed: { type: 'array', items: { type: 'string' } } },
483
+ additionalProperties: false,
484
+ },
485
+ ],
486
+ },
487
+ create(context) {
488
+ const options = context.options[0] || {};
489
+ const allowed = new Set((options.allowed || ALLOWED_ENV_VARS).map(String));
490
+
491
+ function rootIsProcessEnv(node) {
492
+ let cur = node;
493
+ while (cur && cur.type === 'MemberExpression') {
494
+ if (cur.object && cur.object.type === 'Identifier' && cur.object.name === 'process') {
495
+ if (cur.property && ((cur.property.name === 'env') || (cur.property.value === 'env'))) return true;
496
+ }
497
+ cur = cur.object;
498
+ }
499
+ return false;
500
+ }
501
+
502
+ function reportIfForbidden(nameNode, node) {
503
+ const keyName = nameNode && (nameNode.name || nameNode.value);
504
+ if (!keyName) { context.report({ node, messageId: 'forbiddenEnv' }); return; }
505
+ if (!allowed.has(keyName)) context.report({ node, messageId: 'forbiddenEnv' });
506
+ }
507
+
508
+ return {
509
+ MemberExpression(node) {
510
+ // process.env.FOO or process['env'].FOO
511
+ if (node.object && node.object.type === 'MemberExpression') {
512
+ const obj = node.object;
513
+ if (obj.object && obj.object.type === 'Identifier' && obj.object.name === 'process' && (obj.property.name === 'env' || obj.property.value === 'env')) {
514
+ if (node.property.type === 'Identifier') reportIfForbidden(node.property, node);
515
+ else if (node.property.type === 'Literal') reportIfForbidden(node.property, node);
516
+ else context.report({ node, messageId: 'forbiddenEnv' });
517
+ }
518
+ }
519
+
520
+ // import.meta.env.X
521
+ if (node.object && node.object.type === 'MemberExpression' && node.object.object && node.object.object.type === 'MetaProperty') {
522
+ if (node.object.property && (node.object.property.name === 'env' || node.object.property.value === 'env')) {
523
+ if (node.property.type === 'Identifier') reportIfForbidden(node.property, node);
524
+ else context.report({ node, messageId: 'forbiddenEnv' });
525
+ }
526
+ }
527
+ },
528
+
529
+ VariableDeclarator(node) {
530
+ // const { X } = process.env
531
+ if (node.init && node.init.type === 'MemberExpression' && rootIsProcessEnv(node.init) && node.id.type === 'ObjectPattern') {
532
+ node.id.properties.forEach(p => { if (p.key) reportIfForbidden(p.key, p); else context.report({ node: p, messageId: 'forbiddenEnv' }); });
533
+ }
534
+ },
535
+
536
+ 'Program:exit'() {
537
+ const source = context.getSourceCode().text;
538
+ if (/\bprocess\s*\.\s*env\b/.test(source) && !(new RegExp('(?:' + ALLOWED_ENV_VARS.map(s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|') + ')').test(source)) ) {
539
+ context.report({ loc: { line: 1, column: 0 }, messageId: 'forbiddenEnv' });
540
+ }
541
+ },
542
+ };
543
+ },
544
+ };
545
+
546
+ /* ===== RULE: no-debug-true ===== */
547
+ const noDebugTrueRule = {
548
+ meta: {
549
+ type: 'suggestion',
550
+ docs: {
551
+ description: 'Warn when `debug` is set to `true` in source files — ensure debug is disabled before shipping.',
552
+ category: 'Best Practices',
553
+ recommended: true,
554
+ },
555
+ messages: {
556
+ debugOn: 'Found `debug = true` in source. Ensure debug is disabled or gated behind a dev-only flag before shipping.',
557
+ },
558
+ schema: [],
559
+ },
560
+ create(context) {
561
+ const filename = context.getFilename() || '';
562
+ // Allow debug=true in test/story files
563
+ if (filename.includes('/src/tests/') || filename.includes('/src/test/') || filename.includes('/src/stories/')) {
564
+ return {};
565
+ }
566
+
567
+ function isDebugName(n) {
568
+ return typeof n === 'string' && /^debug$/i.test(n);
569
+ }
570
+
571
+ return {
572
+ VariableDeclarator(node) {
573
+ // const debug = true
574
+ if (node.id && node.id.type === 'Identifier' && isDebugName(node.id.name) && node.init && node.init.type === 'Literal' && node.init.value === true) {
575
+ context.report({ node: node.id, messageId: 'debugOn' });
576
+ }
577
+
578
+ // const cfg = { debug: true }
579
+ if (node.init && node.init.type === 'ObjectExpression') {
580
+ node.init.properties.forEach(p => {
581
+ const key = p.key && (p.key.name || p.key.value);
582
+ if (isDebugName(key) && p.value && p.value.type === 'Literal' && p.value.value === true) {
583
+ context.report({ node: p, messageId: 'debugOn' });
584
+ }
585
+ });
586
+ }
587
+ },
588
+
589
+ AssignmentExpression(node) {
590
+ // debug = true OR obj.debug = true
591
+ if (node.left.type === 'Identifier' && isDebugName(node.left.name) && node.right.type === 'Literal' && node.right.value === true) {
592
+ context.report({ node: node.left, messageId: 'debugOn' });
593
+ }
594
+ if (node.left.type === 'MemberExpression') {
595
+ const prop = node.left.property;
596
+ const propName = prop && (prop.name || prop.value);
597
+ if (isDebugName(propName) && node.right.type === 'Literal' && node.right.value === true) {
598
+ context.report({ node: node.left, messageId: 'debugOn' });
599
+ }
600
+ }
601
+ },
602
+ };
603
+ },
604
+ };
605
+
422
606
  const requiredFaqRule = {
423
607
  meta: {
424
608
  type: 'suggestion',
@@ -521,6 +705,9 @@ export default {
521
705
  'no-raw-img': noRawImgRule,
522
706
  'require-section-ids': requireSectionIdsRule,
523
707
  'required-faq': requiredFaqRule,
708
+ 'validate-test-locations': validateTestLocationsRule,
709
+ 'no-process-env': noProcessEnvRule,
710
+ 'no-debug-true': noDebugTrueRule,
524
711
  },
525
712
  configs: {
526
713
  recommended: {
@@ -531,6 +718,9 @@ export default {
531
718
  'pixelated/no-raw-img': 'warn',
532
719
  'pixelated/require-section-ids': 'warn',
533
720
  'pixelated/required-faq': 'warn',
721
+ 'pixelated/validate-test-locations': 'error',
722
+ 'pixelated/no-process-env': ['error', { allowed: ALLOWED_ENV_VARS } ],
723
+ 'pixelated/no-debug-true': 'warn',
534
724
  },
535
725
  },
536
726
  },
@@ -1 +1 @@
1
- {"version":3,"file":"formbuilder.d.ts","sourceRoot":"","sources":["../../../../../src/components/sitebuilder/form/formbuilder.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAY,GAAG,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,SAAS,EAAE,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAUnD,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,SAAS,CAAC,CAAC;AACvE,wBAAgB,WAAW,IAAI,GAAG,CAAC,OAAO,CA4DzC;yBA5De,WAAW;;;AAyE3B,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,SAAS,CAAC,CAAC;AACnE,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,2CA0D7C;yBA1De,SAAS"}
1
+ {"version":3,"file":"formbuilder.d.ts","sourceRoot":"","sources":["../../../../../src/components/sitebuilder/form/formbuilder.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAY,GAAG,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,SAAS,EAAE,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAWnD,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,SAAS,CAAC,CAAC;AACvE,wBAAgB,WAAW,IAAI,GAAG,CAAC,OAAO,CA4DzC;yBA5De,WAAW;;;AAyE3B,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,SAAS,CAAC,CAAC;AACnE,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,2CA0D7C;yBA1De,SAAS"}
@@ -46,7 +46,10 @@ export declare namespace FormInput {
46
46
  maxLength: PropTypes.Requireable<string>;
47
47
  placeholder: PropTypes.Requireable<string>;
48
48
  autoComplete: PropTypes.Requireable<string>;
49
+ tabIndex: PropTypes.Requireable<number>;
50
+ style: PropTypes.Requireable<object>;
49
51
  "aria-label": PropTypes.Requireable<string>;
52
+ "aria-hidden": PropTypes.Requireable<string>;
50
53
  min: PropTypes.Requireable<string>;
51
54
  max: PropTypes.Requireable<string>;
52
55
  step: PropTypes.Requireable<string>;
@@ -220,5 +223,13 @@ export declare function FormFieldset(props: FormFieldsetType): import("react/jsx
220
223
  export declare namespace FormFieldset {
221
224
  var propTypes: {};
222
225
  }
226
+ export type FormHoneypotType = InferProps<typeof FormHoneypot.propTypes>;
227
+ export declare function FormHoneypot({ id, name }: FormHoneypotType): import("react/jsx-runtime").JSX.Element;
228
+ export declare namespace FormHoneypot {
229
+ var propTypes: {
230
+ id: PropTypes.Validator<string>;
231
+ name: PropTypes.Requireable<string>;
232
+ };
233
+ }
223
234
  export { FontSelector, CompoundFontSelector };
224
235
  //# sourceMappingURL=formcomponents.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"formcomponents.d.ts","sourceRoot":"","sources":["../../../../../src/components/sitebuilder/form/formcomponents.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"formcomponents.d.ts","sourceRoot":"","sources":["../../../../../src/components/sitebuilder/form/formcomponents.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"formemailer.d.ts","sourceRoot":"","sources":["../../../../../src/components/sitebuilder/form/formemailer.tsx"],"names":[],"mappings":"AASA,wBAAsB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,iBA6BzE;AAID,wBAAsB,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,iBAyBnE"}
1
+ {"version":3,"file":"formemailer.d.ts","sourceRoot":"","sources":["../../../../../src/components/sitebuilder/form/formemailer.tsx"],"names":[],"mappings":"AASA,wBAAsB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,iBAoDzE;AAID,wBAAsB,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI,iBA+BnE"}
@@ -1 +1 @@
1
- {"version":3,"file":"formextractor.d.ts","sourceRoot":"","sources":["../../../../../src/components/sitebuilder/form/formextractor.tsx"],"names":[],"mappings":"AACA,OAAO,SAAS,EAAE,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAgBnD,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,SAAS,CAAC,CAAC;AAC3E,wBAAgB,aAAa,CAAC,KAAK,EAAE,iBAAiB,2CAyCrD;yBAzCe,aAAa;;;;;;AA8C7B,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,SAAS,CAAC,CAAC;AAC3E,wBAAgB,aAAa,CAAC,KAAK,EAAE,iBAAiB,2CAmCrD;yBAnCe,aAAa;;;;;AA0C7B,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAC;AACnF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,2CAmL7D;yBAnLe,iBAAiB"}
1
+ {"version":3,"file":"formextractor.d.ts","sourceRoot":"","sources":["../../../../../src/components/sitebuilder/form/formextractor.tsx"],"names":[],"mappings":"AACA,OAAO,SAAS,EAAE,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAiBnD,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,SAAS,CAAC,CAAC;AAC3E,wBAAgB,aAAa,CAAC,KAAK,EAAE,iBAAiB,2CAyCrD;yBAzCe,aAAa;;;;;;AA8C7B,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,SAAS,CAAC,CAAC;AAC3E,wBAAgB,aAAa,CAAC,KAAK,EAAE,iBAAiB,2CAmCrD;yBAnCe,aAAa;;;;;AA0C7B,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAC;AACnF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,2CAmL7D;yBAnLe,iBAAiB"}
@@ -1,5 +1,4 @@
1
1
  import { generateKey, capitalize, attributeMap } from '../../general/utilities';
2
- export declare const debug = false;
3
2
  /**
4
3
  * Maps input type to form component name
5
4
  */
@@ -1 +1 @@
1
- {"version":3,"file":"formutils.d.ts","sourceRoot":"","sources":["../../../../../src/components/sitebuilder/form/formutils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEhF,eAAO,MAAM,KAAK,QAAQ,CAAC;AAE3B;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,CA+ItE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,GAAG,CAwBvC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI,CAgBpD;AAGD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"formutils.d.ts","sourceRoot":"","sources":["../../../../../src/components/sitebuilder/form/formutils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAIhF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,CA+ItE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,GAAG,CAwBvC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI,CAgBpD;AAGD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC"}
@@ -4,6 +4,7 @@ export function isClientComponent(fileContent: any): boolean;
4
4
  * Enforces workspace standards for SEO, performance, and project structure.
5
5
  */
6
6
  export const CLIENT_ONLY_PATTERNS: RegExp[];
7
+ export const ALLOWED_ENV_VARS: string[];
7
8
  declare namespace _default {
8
9
  let rules: {
9
10
  'prop-types-inferprops': {
@@ -122,6 +123,76 @@ declare namespace _default {
122
123
  'Program:exit'(): void;
123
124
  };
124
125
  };
126
+ 'validate-test-locations': {
127
+ meta: {
128
+ type: string;
129
+ docs: {
130
+ description: string;
131
+ category: string;
132
+ recommended: boolean;
133
+ };
134
+ messages: {
135
+ badLocation: string;
136
+ };
137
+ schema: never[];
138
+ };
139
+ create(context: any): {
140
+ Program?: undefined;
141
+ } | {
142
+ Program(node: any): void;
143
+ };
144
+ };
145
+ 'no-process-env': {
146
+ meta: {
147
+ type: string;
148
+ docs: {
149
+ description: string;
150
+ category: string;
151
+ recommended: boolean;
152
+ };
153
+ messages: {
154
+ forbiddenEnv: string;
155
+ };
156
+ schema: {
157
+ type: string;
158
+ properties: {
159
+ allowed: {
160
+ type: string;
161
+ items: {
162
+ type: string;
163
+ };
164
+ };
165
+ };
166
+ additionalProperties: boolean;
167
+ }[];
168
+ };
169
+ create(context: any): {
170
+ MemberExpression(node: any): void;
171
+ VariableDeclarator(node: any): void;
172
+ 'Program:exit'(): void;
173
+ };
174
+ };
175
+ 'no-debug-true': {
176
+ meta: {
177
+ type: string;
178
+ docs: {
179
+ description: string;
180
+ category: string;
181
+ recommended: boolean;
182
+ };
183
+ messages: {
184
+ debugOn: string;
185
+ };
186
+ schema: never[];
187
+ };
188
+ create(context: any): {
189
+ VariableDeclarator?: undefined;
190
+ AssignmentExpression?: undefined;
191
+ } | {
192
+ VariableDeclarator(node: any): void;
193
+ AssignmentExpression(node: any): void;
194
+ };
195
+ };
125
196
  };
126
197
  namespace configs {
127
198
  namespace recommended {
@@ -132,6 +203,11 @@ declare namespace _default {
132
203
  'pixelated/no-raw-img': string;
133
204
  'pixelated/require-section-ids': string;
134
205
  'pixelated/required-faq': string;
206
+ 'pixelated/validate-test-locations': string;
207
+ 'pixelated/no-process-env': (string | {
208
+ allowed: string[];
209
+ })[];
210
+ 'pixelated/no-debug-true': string;
135
211
  };
136
212
  export { rules_1 as rules };
137
213
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pixelated-eslint-plugin.d.ts","sourceRoot":"","sources":["../../../src/scripts/pixelated-eslint-plugin.js"],"names":[],"mappings":"AAsCA,6DAEC;AArCD;;;GAGG;AAIH,4CA0BE"}
1
+ {"version":3,"file":"pixelated-eslint-plugin.d.ts","sourceRoot":"","sources":["../../../src/scripts/pixelated-eslint-plugin.js"],"names":[],"mappings":"AAgDA,6DAEC;AA/CD;;;GAGG;AAIH,4CA0BE;AAKF,wCAKE"}
@@ -0,0 +1,20 @@
1
+ declare const _default: {
2
+ title: string;
3
+ parameters: {
4
+ layout: string;
5
+ docs: {
6
+ description: {
7
+ component: string;
8
+ };
9
+ };
10
+ };
11
+ };
12
+ export default _default;
13
+ export declare const HoneypotReject: {
14
+ (): import("react/jsx-runtime").JSX.Element;
15
+ storyName: string;
16
+ play(context: {
17
+ canvasElement: HTMLElement;
18
+ }): Promise<void>;
19
+ };
20
+ //# sourceMappingURL=form.honeypot.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.honeypot.stories.d.ts","sourceRoot":"","sources":["../../../../src/stories/sitebuilder/form.honeypot.stories.tsx"],"names":[],"mappings":";;;;;;;;;;;AAKA,wBAME;AAEF,eAAO,MAAM,cAAc;;;kBAmFW;QAAE,aAAa,EAAE,WAAW,CAAA;KAAE;CAJnE,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sitemap.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/components/general/sitemap.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=formemailer.honeypot.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formemailer.honeypot.test.d.ts","sourceRoot":"","sources":["../../../src/tests/formemailer.honeypot.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=formengine.honeypot.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formengine.honeypot.integration.test.d.ts","sourceRoot":"","sources":["../../../src/tests/formengine.honeypot.integration.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=formengine.method.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formengine.method.test.d.ts","sourceRoot":"","sources":["../../../src/tests/formengine.method.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pixelated-eslint-plugin.exports.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pixelated-eslint-plugin.exports.test.d.ts","sourceRoot":"","sources":["../../../src/tests/pixelated-eslint-plugin.exports.test.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixelated-tech/components",
3
- "version": "3.11.0",
3
+ "version": "3.11.3",
4
4
  "private": false,
5
5
  "author": {
6
6
  "name": "Pixelated Technologies",
@@ -103,12 +103,12 @@
103
103
  },
104
104
  "dependencies": {
105
105
  "date-fns": "^4.1.0",
106
- "globals": "^17.0.0",
106
+ "globals": "^17.1.0",
107
107
  "html-entities": "^2.6.0"
108
108
  },
109
109
  "devDependencies": {
110
- "@aws-sdk/client-amplify": "^3.972.0",
111
- "@aws-sdk/client-iam": "^3.972.0",
110
+ "@aws-sdk/client-amplify": "^3.975.0",
111
+ "@aws-sdk/client-iam": "^3.975.0",
112
112
  "@babel/cli": "^7.28.6",
113
113
  "@babel/core": "^7.28.6",
114
114
  "@babel/plugin-proposal-class-properties": "^7.18.6",
@@ -132,8 +132,8 @@
132
132
  "@typescript-eslint/eslint-plugin": "^8.53.1",
133
133
  "@typescript-eslint/parser": "^8.53.1",
134
134
  "@vitejs/plugin-react": "^5.1.2",
135
- "@vitest/coverage-v8": "^4.0.17",
136
- "@vitest/ui": "^4.0.17",
135
+ "@vitest/coverage-v8": "^4.0.18",
136
+ "@vitest/ui": "^4.0.18",
137
137
  "ajv": "^8.17.1",
138
138
  "ajv-keywords": "^5.1.0",
139
139
  "babel-loader": "^10.0.0",
@@ -149,7 +149,7 @@
149
149
  "eslint-plugin-react": "^7.37.4",
150
150
  "eslint-plugin-storybook": "^10.2.0",
151
151
  "file-loader": "^6.2.0",
152
- "happy-dom": "^20.3.4",
152
+ "happy-dom": "^20.3.7",
153
153
  "jsdom": "^27.4.0",
154
154
  "less-loader": "^12.3.0",
155
155
  "mini-css-extract-plugin": "^2.10.0",
@@ -168,7 +168,7 @@
168
168
  "ts-loader": "^9.5.4",
169
169
  "typescript": "^5.9.3",
170
170
  "url-loader": "^4.1.1",
171
- "vitest": "^4.0.17",
171
+ "vitest": "^4.0.18",
172
172
  "webpack": "^5.104.1",
173
173
  "webpack-cli": "^6.0.1",
174
174
  "webpack-dev-server": "^5.2.3",
@@ -180,11 +180,11 @@
180
180
  "react-dom": "^19.2.0"
181
181
  },
182
182
  "optionalDependencies": {
183
- "@aws-sdk/client-cloudwatch": "^3.972.0",
184
- "@aws-sdk/client-route-53": "^3.972.0",
183
+ "@aws-sdk/client-cloudwatch": "^3.975.0",
184
+ "@aws-sdk/client-route-53": "^3.975.0",
185
185
  "googleapis": "^170.1.0",
186
186
  "md5": "^2.3.0",
187
- "puppeteer": "^24.35.0",
187
+ "puppeteer": "^24.36.0",
188
188
  "react-redux": "*",
189
189
  "recharts": "^3.7.0",
190
190
  "redux": "*"
@@ -1,19 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { getRuntimeEnvFromHeaders } from './sitemap';
3
- describe('getRuntimeEnvFromHeaders', () => {
4
- it('returns "local" for localhost host header', () => {
5
- const hdrs = { get: (k) => (k === 'host' ? 'localhost:3000' : null) };
6
- expect(getRuntimeEnvFromHeaders(hdrs)).toBe('local');
7
- });
8
- it('returns "local" for 127.0.0.1 host header', () => {
9
- const hdrs = { get: (k) => (k === 'host' ? '127.0.0.1:3000' : null) };
10
- expect(getRuntimeEnvFromHeaders(hdrs)).toBe('local');
11
- });
12
- it('returns "prod" for production host', () => {
13
- const hdrs = { get: (k) => (k === 'host' ? 'example.com' : null) };
14
- expect(getRuntimeEnvFromHeaders(hdrs)).toBe('prod');
15
- });
16
- it('returns "auto" when headers not present', () => {
17
- expect(getRuntimeEnvFromHeaders(undefined)).toBe('auto');
18
- });
19
- });
@@ -1 +0,0 @@
1
- {"version":3,"file":"sitemap.test.d.ts","sourceRoot":"","sources":["../../../../src/components/general/sitemap.test.ts"],"names":[],"mappings":""}