@pixelated-tech/components 3.9.7 → 3.9.10

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 (161) hide show
  1. package/README.md +2 -0
  2. package/dist/components/admin/site-health/site-health-axe-core.js +2 -1
  3. package/dist/components/admin/site-health/site-health-uptime.integration.js +21 -2
  4. package/dist/components/config/config.js +3 -0
  5. package/dist/components/general/sitemap.js +2 -2
  6. package/dist/components/general/smartimage.js +1 -1
  7. package/dist/components/{utilities/functions.js → general/utilities.js} +3 -8
  8. package/dist/components/{general → integrations}/contentful.items.components.js +1 -1
  9. package/dist/components/{general → integrations}/flickr.js +1 -1
  10. package/dist/components/{general → integrations}/google.reviews.components.js +1 -1
  11. package/dist/components/{general → integrations}/instagram.components.js +2 -2
  12. package/dist/components/{general → integrations}/socialcard.js +2 -2
  13. package/dist/components/{general → integrations}/wordpress.components.js +3 -3
  14. package/dist/components/shoppingcart/ebay.components.js +1 -1
  15. package/dist/components/shoppingcart/ebay.functions.js +1 -1
  16. package/dist/components/shoppingcart/shoppingcart.functions.js +1 -1
  17. package/dist/components/sitebuilder/config/ConfigBuilder.js +1 -1
  18. package/dist/components/sitebuilder/form/formutils.js +1 -1
  19. package/dist/components/sitebuilder/page/components/PageEngine.js +1 -1
  20. package/dist/components/sitebuilder/page/lib/pageStorageContentful.js +2 -2
  21. package/dist/config/pixelated.config.json.enc +1 -0
  22. package/dist/index.adminserver.js +1 -1
  23. package/dist/index.js +21 -22
  24. package/dist/index.server.js +10 -18
  25. package/dist/scripts/build.sh +86 -0
  26. package/dist/scripts/config-vault.js +24 -9
  27. package/dist/scripts/config-vault.ts +24 -9
  28. package/dist/scripts/release.sh +232 -85
  29. package/dist/scripts/validate-exports.cjs +1 -1
  30. package/dist/scripts/validate-exports.js +1 -1
  31. package/dist/types/components/admin/site-health/site-health-uptime.integration.d.ts.map +1 -1
  32. package/dist/types/components/config/config.d.ts.map +1 -1
  33. package/dist/types/components/general/schema-blogposting.functions.d.ts +1 -1
  34. package/dist/types/components/general/schema-blogposting.functions.d.ts.map +1 -1
  35. package/dist/types/components/general/sitemap.d.ts.map +1 -1
  36. package/dist/types/components/{utilities/functions.d.ts → general/utilities.d.ts} +1 -2
  37. package/dist/types/components/general/utilities.d.ts.map +1 -0
  38. package/dist/types/components/integrations/calendly.d.ts.map +1 -0
  39. package/dist/types/components/integrations/cloudinary.d.ts.map +1 -0
  40. package/dist/types/components/integrations/contentful.delivery.d.ts.map +1 -0
  41. package/dist/types/components/integrations/contentful.items.components.d.ts.map +1 -0
  42. package/dist/types/components/integrations/contentful.management.d.ts.map +1 -0
  43. package/dist/types/components/{general → integrations}/flickr.d.ts +1 -1
  44. package/dist/types/components/integrations/flickr.d.ts.map +1 -0
  45. package/dist/types/components/integrations/gemini-api.client.d.ts.map +1 -0
  46. package/dist/types/components/integrations/gemini-api.server.d.ts.map +1 -0
  47. package/dist/types/components/integrations/google.reviews.components.d.ts.map +1 -0
  48. package/dist/types/components/integrations/google.reviews.functions.d.ts.map +1 -0
  49. package/dist/types/components/integrations/googleanalytics.d.ts.map +1 -0
  50. package/dist/types/components/integrations/googlemap.d.ts.map +1 -0
  51. package/dist/types/components/integrations/googlesearch.d.ts.map +1 -0
  52. package/dist/types/components/integrations/gravatar.components.d.ts.map +1 -0
  53. package/dist/types/components/integrations/gravatar.functions.d.ts.map +1 -0
  54. package/dist/types/components/integrations/hubspot.components.d.ts.map +1 -0
  55. package/dist/types/components/integrations/instagram.components.d.ts.map +1 -0
  56. package/dist/types/components/{general → integrations}/instagram.functions.d.ts +1 -1
  57. package/dist/types/components/integrations/instagram.functions.d.ts.map +1 -0
  58. package/dist/types/components/integrations/socialcard.d.ts.map +1 -0
  59. package/dist/types/components/integrations/wordpress.components.d.ts.map +1 -0
  60. package/dist/types/components/integrations/wordpress.functions.d.ts.map +1 -0
  61. package/dist/types/components/integrations/yelp.d.ts.map +1 -0
  62. package/dist/types/components/sitebuilder/form/formutils.d.ts +1 -1
  63. package/dist/types/components/sitebuilder/form/formutils.d.ts.map +1 -1
  64. package/dist/types/components/sitebuilder/page/lib/pageStorageContentful.d.ts +1 -1
  65. package/dist/types/components/sitebuilder/page/lib/pageStorageContentful.d.ts.map +1 -1
  66. package/dist/types/index.adminserver.d.ts +1 -1
  67. package/dist/types/index.d.ts +21 -22
  68. package/dist/types/index.server.d.ts +10 -10
  69. package/dist/types/stories/general/contentful.item.stories.d.ts +1 -1
  70. package/dist/types/stories/general/contentful.item.stories.d.ts.map +1 -1
  71. package/dist/types/stories/general/contentful.items.stories.d.ts +1 -1
  72. package/dist/types/stories/general/contentful.items.stories.d.ts.map +1 -1
  73. package/dist/types/stories/general/google.reviews.stories.d.ts +1 -1
  74. package/dist/types/stories/general/google.reviews.stories.d.ts.map +1 -1
  75. package/dist/types/stories/general/googleanalytics.stories.d.ts +1 -1
  76. package/dist/types/stories/general/googleanalytics.stories.d.ts.map +1 -1
  77. package/dist/types/stories/general/googlesearch.stories.d.ts +1 -1
  78. package/dist/types/stories/general/googlesearch.stories.d.ts.map +1 -1
  79. package/dist/types/stories/general/gravatar.stories.d.ts +1 -1
  80. package/dist/types/stories/general/gravatar.stories.d.ts.map +1 -1
  81. package/dist/types/stories/general/instagram.stories.d.ts +1 -1
  82. package/dist/types/stories/general/instagram.stories.d.ts.map +1 -1
  83. package/dist/types/stories/general/socialcard.stories.d.ts +1 -1
  84. package/dist/types/stories/general/socialcard.stories.d.ts.map +1 -1
  85. package/dist/types/stories/general/wordpress.stories.d.ts +1 -1
  86. package/dist/types/stories/general/wordpress.stories.d.ts.map +1 -1
  87. package/dist/types/tests/utilities.test.d.ts +2 -0
  88. package/dist/types/tests/utilities.test.d.ts.map +1 -0
  89. package/package.json +14 -11
  90. package/dist/config/pixelated.config.json +0 -85
  91. package/dist/test/config.mock.js +0 -13
  92. package/dist/test/run-analyzeGitHealth.js +0 -50
  93. package/dist/test/setup.js +0 -46
  94. package/dist/test/test-utils.js +0 -23
  95. package/dist/types/components/general/calendly.d.ts.map +0 -1
  96. package/dist/types/components/general/cloudinary.d.ts.map +0 -1
  97. package/dist/types/components/general/contentful.delivery.d.ts.map +0 -1
  98. package/dist/types/components/general/contentful.items.components.d.ts.map +0 -1
  99. package/dist/types/components/general/contentful.management.d.ts.map +0 -1
  100. package/dist/types/components/general/flickr.d.ts.map +0 -1
  101. package/dist/types/components/general/google.reviews.components.d.ts.map +0 -1
  102. package/dist/types/components/general/google.reviews.functions.d.ts.map +0 -1
  103. package/dist/types/components/general/googleanalytics.d.ts.map +0 -1
  104. package/dist/types/components/general/googlemap.d.ts.map +0 -1
  105. package/dist/types/components/general/googlesearch.d.ts.map +0 -1
  106. package/dist/types/components/general/gravatar.components.d.ts.map +0 -1
  107. package/dist/types/components/general/gravatar.functions.d.ts.map +0 -1
  108. package/dist/types/components/general/hubspot.components.d.ts.map +0 -1
  109. package/dist/types/components/general/instagram.components.d.ts.map +0 -1
  110. package/dist/types/components/general/instagram.functions.d.ts.map +0 -1
  111. package/dist/types/components/general/socialcard.d.ts.map +0 -1
  112. package/dist/types/components/general/wordpress.components.d.ts.map +0 -1
  113. package/dist/types/components/general/wordpress.functions.d.ts.map +0 -1
  114. package/dist/types/components/general/yelp.d.ts.map +0 -1
  115. package/dist/types/components/utilities/functions.d.ts.map +0 -1
  116. package/dist/types/components/utilities/gemini-api.client.d.ts.map +0 -1
  117. package/dist/types/components/utilities/gemini-api.server.d.ts.map +0 -1
  118. package/dist/types/tests/functions.test.d.ts +0 -2
  119. package/dist/types/tests/functions.test.d.ts.map +0 -1
  120. /package/dist/components/{general → integrations}/calendly.js +0 -0
  121. /package/dist/components/{general → integrations}/cloudinary.js +0 -0
  122. /package/dist/components/{general → integrations}/contentful.delivery.js +0 -0
  123. /package/dist/components/{general → integrations}/contentful.items.css +0 -0
  124. /package/dist/components/{general → integrations}/contentful.management.js +0 -0
  125. /package/dist/components/{utilities → integrations}/gemini-api.client.js +0 -0
  126. /package/dist/components/{utilities → integrations}/gemini-api.server.js +0 -0
  127. /package/dist/components/{general → integrations}/google.reviews.css +0 -0
  128. /package/dist/components/{general → integrations}/google.reviews.functions.js +0 -0
  129. /package/dist/components/{general → integrations}/googleanalytics.js +0 -0
  130. /package/dist/components/{general → integrations}/googlemap.js +0 -0
  131. /package/dist/components/{general → integrations}/googlesearch.css +0 -0
  132. /package/dist/components/{general → integrations}/googlesearch.js +0 -0
  133. /package/dist/components/{general → integrations}/gravatar.components.js +0 -0
  134. /package/dist/components/{general → integrations}/gravatar.css +0 -0
  135. /package/dist/components/{general → integrations}/gravatar.functions.js +0 -0
  136. /package/dist/components/{general → integrations}/hubspot.components.js +0 -0
  137. /package/dist/components/{general → integrations}/instagram.functions.js +0 -0
  138. /package/dist/components/{general → integrations}/socialcard.css +0 -0
  139. /package/dist/components/{general → integrations}/wordpress.css +0 -0
  140. /package/dist/components/{general → integrations}/wordpress.functions.js +0 -0
  141. /package/dist/components/{general → integrations}/yelp.js +0 -0
  142. /package/dist/types/components/{general → integrations}/calendly.d.ts +0 -0
  143. /package/dist/types/components/{general → integrations}/cloudinary.d.ts +0 -0
  144. /package/dist/types/components/{general → integrations}/contentful.delivery.d.ts +0 -0
  145. /package/dist/types/components/{general → integrations}/contentful.items.components.d.ts +0 -0
  146. /package/dist/types/components/{general → integrations}/contentful.management.d.ts +0 -0
  147. /package/dist/types/components/{utilities → integrations}/gemini-api.client.d.ts +0 -0
  148. /package/dist/types/components/{utilities → integrations}/gemini-api.server.d.ts +0 -0
  149. /package/dist/types/components/{general → integrations}/google.reviews.components.d.ts +0 -0
  150. /package/dist/types/components/{general → integrations}/google.reviews.functions.d.ts +0 -0
  151. /package/dist/types/components/{general → integrations}/googleanalytics.d.ts +0 -0
  152. /package/dist/types/components/{general → integrations}/googlemap.d.ts +0 -0
  153. /package/dist/types/components/{general → integrations}/googlesearch.d.ts +0 -0
  154. /package/dist/types/components/{general → integrations}/gravatar.components.d.ts +0 -0
  155. /package/dist/types/components/{general → integrations}/gravatar.functions.d.ts +0 -0
  156. /package/dist/types/components/{general → integrations}/hubspot.components.d.ts +0 -0
  157. /package/dist/types/components/{general → integrations}/instagram.components.d.ts +0 -0
  158. /package/dist/types/components/{general → integrations}/socialcard.d.ts +0 -0
  159. /package/dist/types/components/{general → integrations}/wordpress.components.d.ts +0 -0
  160. /package/dist/types/components/{general → integrations}/wordpress.functions.d.ts +0 -0
  161. /package/dist/types/components/{general → integrations}/yelp.d.ts +0 -0
package/README.md CHANGED
@@ -138,6 +138,8 @@ The release script will:
138
138
 
139
139
  **Important**: Always run releases from the `dev` branch. The script ensures both `dev` and `main` branches stay synchronized.
140
140
 
141
+ **Config policy**: To avoid shipping secrets, keep `pixelated.config.json` encrypted on disk as `pixelated.config.json.enc` and never commit the plaintext `pixelated.config.json`. The release script will remove any plaintext `pixelated.config.json` from `dist` post-build and will fail if the `.enc` file is not present.
142
+
141
143
  **Universal Usage**: This script is designed to work with any Pixelated project and automatically detects project settings.
142
144
 
143
145
  ### Reference Implementation
@@ -25,7 +25,8 @@ export function SiteHealthAxeCore({ siteName }) {
25
25
  const script = document.createElement('script');
26
26
  script.src = src;
27
27
  script.async = false; // preserve execution order
28
- script.onload = () => console.info('axe-core loaded from', src);
28
+ script.onload = () => { if (debug)
29
+ console.info('axe-core loaded from', src); };
29
30
  script.onerror = async () => {
30
31
  console.warn('Failed to load axe-core from', src);
31
32
  if (src !== apiFallback) {
@@ -1,8 +1,27 @@
1
1
  import { Route53Client, GetHealthCheckStatusCommand } from '@aws-sdk/client-route-53';
2
+ import { getFullPixelatedConfig } from '../../config/config';
3
+ const debug = true;
2
4
  export async function checkUptimeHealth(healthCheckId) {
3
5
  try {
4
- // Simple Route 53 call (global service, no region needed)
5
- const client = new Route53Client({});
6
+ // Simple Route 53 call (global service). Prefer credentials from pixelated.config.json when present
7
+ const fullCfg = getFullPixelatedConfig();
8
+ const awsCfg = fullCfg?.aws;
9
+ if (debug) {
10
+ if (awsCfg?.access_key_id && awsCfg?.secret_access_key) {
11
+ console.log('Uptime check: using AWS credentials from pixelated.config.json (aws block).');
12
+ }
13
+ else {
14
+ console.log('Uptime check: no explicit AWS credentials in pixelated.config.json; using default credential provider chain.');
15
+ }
16
+ }
17
+ const client = new Route53Client({
18
+ region: awsCfg?.region || 'us-east-1',
19
+ credentials: (awsCfg?.access_key_id && awsCfg?.secret_access_key) ? {
20
+ accessKeyId: awsCfg.access_key_id,
21
+ secretAccessKey: awsCfg.secret_access_key,
22
+ sessionToken: awsCfg.session_token
23
+ } : undefined
24
+ });
6
25
  const response = await client.send(new GetHealthCheckStatusCommand({
7
26
  HealthCheckId: healthCheckId,
8
27
  }));
@@ -18,6 +18,9 @@ export function getFullPixelatedConfig() {
18
18
  path.join(process.cwd(), 'src/config', filename),
19
19
  path.join(process.cwd(), filename),
20
20
  path.join(process.cwd(), '.next/server', filename), // Sometimes moved here in build
21
+ path.join(process.cwd(), 'dist', 'config', filename), // Support dist when project outputs a dist/config
22
+ // If this library is installed as a package, check its dist/config as a fallback
23
+ path.join(process.cwd(), 'node_modules', '@pixelated-tech', 'components', 'dist', 'config', filename),
21
24
  ];
22
25
  for (const configPath of paths) {
23
26
  if (fs.existsSync(configPath)) {
@@ -1,7 +1,7 @@
1
1
  import PropTypes from "prop-types";
2
2
  import { getAllRoutes } from "./metadata.functions";
3
- import { getWordPressItems, getWordPressItemImages } from "../general/wordpress.functions";
4
- import { getContentfulFieldValues, getContentfulAssetURLs } from "../general/contentful.delivery";
3
+ import { getWordPressItems, getWordPressItemImages } from "../integrations/wordpress.functions";
4
+ import { getContentfulFieldValues, getContentfulAssetURLs } from "../integrations/contentful.delivery";
5
5
  import { getEbayAppToken, getEbayItemsSearch } from "../shoppingcart/ebay.functions";
6
6
  import { getFullPixelatedConfig } from '../config/config';
7
7
  import { CacheManager } from '../general/cache-manager';
@@ -3,7 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import React, { useState } from 'react';
4
4
  import PropTypes from 'prop-types';
5
5
  import Image from 'next/image';
6
- import { buildCloudinaryUrl } from '../general/cloudinary';
6
+ import { buildCloudinaryUrl } from '../integrations/cloudinary';
7
7
  import { usePixelatedConfig } from '../config/config.client';
8
8
  const CLOUDINARY_DOMAIN = 'https://res.cloudinary.com/';
9
9
  const CLOUDINARY_TRANSFORMS = 'f_auto,c_limit,q_auto,dpr_auto';
@@ -28,11 +28,6 @@ export function mergeDeep(a, b) {
28
28
  }
29
29
  return extended;
30
30
  }
31
- export function pushNewValueToStateArray(that, oldState, newValue) {
32
- const myNewArray = that.state[oldState];
33
- myNewArray.push(newValue);
34
- that.setState({ [oldState]: myNewArray });
35
- }
36
31
  export function randomBetween(min, max) {
37
32
  /* ===== RANDOM NUM BETWEEN MIN AND MAX ===== */
38
33
  if (min < 0) {
@@ -206,7 +201,7 @@ export const SERVER_ONLY_PATTERNS = [
206
201
  /\bimport.*path\b|\brequire.*path\b/, // Actual import of path module
207
202
  /\bprocess\.cwd\(\)/,
208
203
  /\brequire\.resolve\b/,
209
- /\butil\b/,
210
- /\bNextRequest\b/,
211
- /\bNextResponse\b/
204
+ /\butil\b/
205
+ // /\bNextRequest\b/,
206
+ // /\bNextResponse\b/
212
207
  ];
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect } from "react";
4
4
  import PropTypes from "prop-types";
5
- import { Carousel } from './carousel';
5
+ import { Carousel } from '../general/carousel';
6
6
  import { getContentfulEntriesByType, getContentfulEntryByEntryID } from "./contentful.delivery";
7
7
  import { usePixelatedConfig } from '../config/config.client';
8
8
  import { addToShoppingCart } from "../shoppingcart/shoppingcart.functions";
@@ -1,5 +1,5 @@
1
1
  import PropTypes from 'prop-types';
2
- import { mergeDeep } from '../utilities/functions';
2
+ import { mergeDeep } from '../general/utilities';
3
3
  const defaultFlickr = {
4
4
  flickr: {
5
5
  baseURL: 'https://api.flickr.com/services/rest/?',
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect } from 'react';
4
4
  import PropTypes from 'prop-types';
5
- import { SmartImage } from './smartimage';
5
+ import { SmartImage } from '../general/smartimage';
6
6
  import { getGoogleReviewsByPlaceId } from './google.reviews.functions';
7
7
  import { usePixelatedConfig } from '../config/config.client';
8
8
  import './google.reviews.css';
@@ -2,9 +2,9 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect } from 'react';
4
4
  import PropTypes from 'prop-types';
5
- import { getInstagramTiles } from '../general/instagram.functions';
5
+ import { getInstagramTiles } from './instagram.functions';
6
6
  import { usePixelatedConfig } from "../config/config.client";
7
- import { Tiles } from './tiles';
7
+ import { Tiles } from '../general/tiles';
8
8
  InstagramTiles.propTypes = {
9
9
  accessToken: PropTypes.string,
10
10
  userId: PropTypes.string,
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useEffect } from 'react';
3
3
  import PropTypes from "prop-types";
4
- import { mergeDeep } from '../utilities/functions';
5
- import { SmartImage } from './smartimage';
4
+ import { mergeDeep } from '../general/utilities';
5
+ import { SmartImage } from '../general/smartimage';
6
6
  import { usePixelatedConfig } from '../config/config.client';
7
7
  import './socialcard.css';
8
8
  /* ========== NOTES ==========
@@ -3,10 +3,10 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
3
3
  import { useEffect, useState } from 'react';
4
4
  import PropTypes from 'prop-types';
5
5
  import { usePixelatedConfig } from "../config/config.client";
6
- import { SmartImage } from './smartimage';
7
- import { PageGridItem } from './semantic';
6
+ import { SmartImage } from '../general/smartimage';
7
+ import { PageGridItem } from '../general/semantic';
8
8
  import { getWordPressItems } from './wordpress.functions';
9
- import { Loading, ToggleLoading } from './loading';
9
+ import { Loading, ToggleLoading } from '../general/loading';
10
10
  import "./wordpress.css";
11
11
  // https://microformats.org/wiki/h-entry
12
12
  function decodeString(str) {
@@ -7,7 +7,7 @@ import { SmartImage } from "../general/smartimage";
7
7
  import { getEbayItems, getEbayItem, getShoppingCartItem, getEbayRateLimits, getEbayAppToken } from "./ebay.functions";
8
8
  import { addToShoppingCart } from "./shoppingcart.functions";
9
9
  import { AddToCartButton, /* GoToCartButton */ ViewItemDetails } from "./shoppingcart.components";
10
- import { getCloudinaryRemoteFetchURL as getImg } from "../general/cloudinary";
10
+ import { getCloudinaryRemoteFetchURL as getImg } from "../integrations/cloudinary";
11
11
  import { ToggleLoading } from "../general/loading";
12
12
  import { usePixelatedConfig } from "../config/config.client";
13
13
  import "../../css/pixelated.grid.scss";
@@ -1,5 +1,5 @@
1
1
  import PropTypes from "prop-types";
2
- import { getCloudinaryRemoteFetchURL as getImg } from "../general/cloudinary";
2
+ import { getCloudinaryRemoteFetchURL as getImg } from "../integrations/cloudinary";
3
3
  import { CacheManager } from "../general/cache-manager";
4
4
  const debug = false;
5
5
  // Initialize eBay Cache (Session storage, 1 hour TTL)
@@ -1,4 +1,4 @@
1
- import { getContentfulDiscountCodes } from "../general/contentful.delivery";
1
+ import { getContentfulDiscountCodes } from "../integrations/contentful.delivery";
2
2
  const debug = false;
3
3
  /* ========== LOCALSTORAGE KEYS ========== */
4
4
  export const shoppingCartKey = "pixelvividCart";
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
5
5
  import { Modal } from '../../general/modal';
6
6
  import { Tab } from '../../general/tab';
7
7
  import { Accordion } from '../../general/accordion';
8
- import { createGeminiApiService } from '../../utilities/gemini-api.client';
8
+ import { createGeminiApiService } from '../../integrations/gemini-api.client';
9
9
  import { FormEngine } from '../form/formengine';
10
10
  import { FormValidationProvider } from '../form/formvalidator';
11
11
  import * as FC from '../form/formcomponents';
@@ -1,5 +1,5 @@
1
1
  // Shared utility functions for form components
2
- import { generateKey, capitalize, attributeMap } from '../../utilities/functions';
2
+ import { generateKey, capitalize, attributeMap } from '../../general/utilities';
3
3
  export const debug = false;
4
4
  /**
5
5
  * Maps input type to form component name
@@ -1,7 +1,7 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import PropTypes from 'prop-types';
4
- import { generateKey } from '../../../utilities/functions';
4
+ import { generateKey } from '../../../general/utilities';
5
5
  import { componentMap, layoutComponents } from '../lib/componentMap';
6
6
  import './pagebuilder.scss';
7
7
  /**
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Uses generic Contentful management functions with PageBuilder-specific logic
5
5
  */
6
- import { createEntry, updateEntry, deleteEntry, searchEntriesByField } from '../../../general/contentful.management';
7
- import { getContentfulEntriesByType } from '../../../general/contentful.delivery';
6
+ import { createEntry, updateEntry, deleteEntry, searchEntriesByField } from '../../../integrations/contentful.management';
7
+ import { getContentfulEntriesByType } from '../../../integrations/contentful.delivery';
8
8
  const CONTENT_TYPE = 'page';
9
9
  /**
10
10
  * Validate page name format
@@ -0,0 +1 @@
1
+ pxl:v1:af6a05433e212e25084de327:ca5a4b076bcea79187f5c9d4a5542791:18cd569c7c2131985f05d76d6e7d95ed11ccc22aa648f644bc61c28ca0c7a9fb4b8ac669dc6c0107d3469d118a776db4caa1cc10a0c4be73496995393843138edff705bb7902e8048bf7d229e99e7b8c1cbd83aaed6007ff2cda66c8afdee1822fa4bc7c3a601b3460e4af68f86ce5324507289abd3a91cee163953bd6d894eca9f121f41582602e04c4f20803b1dcb39fd8e7253fcd345faa16ab763e66e00743e6ca36e33cad0890d4030bbb04b3173ebb7e10d75bac41c582bf3c547860382c9fa27a01aab5a1be730fc4deef206fc51bc5880cd346159b0ab032775a37d6f46170e9a49930eab89d0b90d7f918cc3d13a363b79c2e688a3b1520e5848d9c3bb16894aba37f9cdacc228a23749429c6901e43ba40dd185115a3add46a45339ca398a0c794bdbb7ff58e0f6b4b8a34a17a3bbf45dc9736c7423c889036a0a3465c0b2e500f42ec2370bf0b448904d8a0e66b44981d1a10c7083f001bf71372eea21c95c4f591ce0e74e3ce2b8e33d02f13a13c45aa5c076b54b9258dc071c478fb0388882206a3d091151232d162675e0dca09dea04d9eba0585bbfb0ab6ba9be903982500ac4ae055fcd58b55b0023f5af5be67b8e2fb1de6aaa7c12bc0655f6c5030b9e01d03a4db89bdac8991fefcb50339bb22bd4055bb8f145893a872e76b779464234e2ad6236ca35f823f3016cced3acd1e903d8832f204ddecdfe07dbe0429405f27724d49d84d76bf01ff3235317f7ee3b8afe18f3531499d192a622374ebedfd4e10f27d75dcee843191104984b53d11cdf39ba3b44aed901f9f10965843e1731d413285309641d34078e4209e13c9af208deb4515e5fdfb990ad732157082fc9112b3a706d6a378b53e5ccfe26ee95d06a4fa47540b08a4e6a6333fb7c2c3983c6880074dbd1e5b3b563fe5e68f337e3e0ab50cef6bf948633884c9641a648c404cbe5f95c9a814c48bf6d7d058d04cd9f4523e0c9ff116d5b9a5ddd1a2f0fc44eafe98cef0007bc771735e4b32f6cb90afff75ac7888e0f8c072da789278cd23384bd8f8d4a585de486d8b7ca516ad4ebff1ff5e4cb6111da97127b84a423c86b0102ff38f4f063a7ce127d7d0b05c3c03607169ded0930fbe90d09e947028cc034db999dcdbc789f9fc01e08f74d93ca924f12c343d952310209d0358dd8ff6e8495a507e5b7eec7fcea8f7328bf865f16d9630da195e2e5395304f75cfe0754ea75801deecf04f5a6788d8202b87c87023367ee9c85b2ebc413b9f8a6132be686951b57f706ef315a0ec4ee43711038751db59c455db335a98209f2f555cf70f70b4fb83c8c15a22b1e3182867e8eccb6205a7b1b3e6a8b47dfdb2d1725a476cad278010aaab1a1de4562bdc48adff56d74fe1350bc3bd432a32be4559f96b941a775f06a63dc968b4d1a895365ade2a6162e29bc29e0134483d9d0f0b3e5e350c168df1adbb26a3cd8d7920a5a57332c8427b71ea2a6c6a2203bfd3eeff69d7b414b707419f501d33a69a0237ec713991f18e974a05ffe4d76d7eb0326de4f3d08a1927726c8d395b288f8d326ff3aa20c376d95be1020ebbdc9cb554135a537364dcd3ac9995c3e0bb64d0d05b707f501c731a669fb37c27244dc5dee47ec7b0ed1e36ac5582e287def893744382306136409656a82c73e987b0c68a06357970aff4aaba88f388d35399aeacb672ddce25bc4a79dd1a5f91f58cbd95d977b3979cd8efcdfe2ec19242a3f0af2c4276b57ef344531b9d4ae329003b8edeff1a53097bb36fea25db170429a2f11a7b6d00c105cf45c6e582633644250eabe6591b35b3be92f2f152dff86bd11e153b8fb2166e32d541850a9ad504d4db32aa80418a773e318991b44bb68d259ae2be6419e7f89c37e7c71d4972bd5862ac8f5486008a09c170fcf7c208ca1c55b991170a47376c89c1fc2272a2a2e7e4572b644dc909e16a712ade1e64f9cebc8df9abf0937f6fe3b7fc20d05201a63e048e75def45ea825404022c2457b58f0994ae29943b0cc25e159c71166c9e782e11e3db6157048599840cc791705dd46f8738b3ea190ffa5ce71ce946870947b5ec4e0bab5f5db4a912f2e869da2be6d4acb30673dc23beec3f0b15872579b744ccb00074f11089aa3c868d7063fe9a4b76603cf7ff2dc46ebd2db06f98eae7fbcabfe8ec29f0e39e29b21447f280834995c46f293c206cb73e8d3b774a6ae9d939c86876a74f739eb08153fac68e45ca8a95951b934e917453dee80a3ac5d8c350772eeaefbe536462f9563268cedef229f451b5c529e03b941ad15d8b7b3c2515ad7104e92df3afc9d8ee9564469490ec9480ea98753ffaf6a16468f324ba25b236279b060c8bbb9ada73b5f148f03bac44b47f4a4b7677df9451f528b4b6b8c8dee2a066d93e9129ff70285258da3b1d3b566ec89bedff0fb1a1d600ea5514ba82afb72d9855b7d8405ded7d3103b084af6e3a3eb6de599b2c1904aed52b74e6f67df103ea38fae9ce52819398bffc42c876673f8d3c019772b3b0288b3c8d3a91ce51cb30252de8bc207225f1c28c114f248ff3f13f1d778b856b8554e8ccc619eb8d78a570095fcc250990003ff83a65db83f280f79bd241982a69863416897e3a4008032bb04341d77533b4168440fedfe9152ca987dfc7b9ba0d5d314405d596112194eaba32e1d0f864ad1d7646f796e7f40132ab1749164be3a0017a336a480afa7c8ef92104e01aecfd0efa159392145bb7fa97b098c11d62b7e6354b55f8998f3bebe1b5ad679f139831cd38543fd7006957c5f3601e08606d507eaed3ed542f9a48e20d26c1249baedfd4bde59fe77477b6f11358013363ed742a37b73df342f8ad6c91804c737b04da7f58c0ecdfa8e798ea57c3db17e91a38b3b275698a65336f5be35704f5b86651d3a0ee8145ff8ebcf61a559b659ea5374955f59e7f64a2908090d107b95e9586b15311f4fe780b76c26c89760f31a35227c5d675f9412df26c58bbfcf520d1e4967690fb5c837cb36ef1ceab614124b7e47f9f6e9a831ee67aa0c85b9e11d70245e88e7dd3fae6ab5c3960d2f0bc6199f818801aa9ae70ba7d430378c59831ccfff9ce3210daa3af7db80a94b4d484d7b19e50adc306b0faffaea086546e1b59253614638147b8fad7f104e8df6da04803a4a8e1ed791ee1b628ee53b29a84f1ce41feda312bdd78efd83c3ba8c3bb6e94f717d0f3bf504759a27ed33d28a1f92b3fa92369a783e4fd3072a41cf120d59f854ac35b530c80b10b80f7cb8638ea1be62e7284c270e3eef48c051a7194af4264dbb0970cb6c7768cd326bc4e7342d7f8e9b833f4bfba966807c375e6a5345bab2a804816d34d771bc04d2c6368a2ef5f0fe5498fa11e2a37adc120bbc88258a95bcb0697b724ac3b109e9df9361e83dc50a262a39fc0010d18442f0ab6d41653a3b41ffa800836558a08d30bb7c9885e9180c779e1769c0139cdbbe47d7a830696dba9b148fcaa966e9fc1bc8ad8be681a929f66a6197c8ea537253a43e3bfec32640b29ea4886b7eca7afd912b82ec29d409af8830a6de409d9f6f756343f220c544aa212cbc254dbef46d93417c23bb024c270e50d33340ef71f9cacb78210d9d6339b0cf036eca2b627a88e28138be0ee2c11b54df30d55d2f6ccea8546b14a3319b953b1b47160bd4eac524d93982b62534952cc91a6073bc5160ac699a6d135b4587669d69c4c99d48f721519c1acaf0eea41e606708436e1ffaa68b76154b9b0b7daeb1f43a0130813c7f3b4f1b211f85ed1d1d55e4fa12d3be265181daa51f001a12195da658141794d566a9a285cfffc1007cc05938f109b97fa51b7fa2e810c63c0f2f50837b9be96d70f2c511e8109d2b8363a09fec93c0b9a08a2b158fd7197d033027f2fc67fa264f21204a460fad2d0281c0fe5de71700469356ccc3fa23cc6c756f64dd4b5834a7e78f009ff97669b7cb82879775630188398b087debac04259162eea5da6f39aabae18157dfa10b4fc30ab9bcfa66539ea7b5c2c73a08789827590e9926b27df1708e71ec728f8539e0ac604ce9f0d2fef6240f7b78da1e3582a38268ab311cea267c7d13699f74b1b9ba2e1b9a6992e449ea17fca20f0afff5ab5dad23a50bc5de1d8665c23afd57298c9c430836d0c1eb564d8406da3f0d8a403d72f363dd1b0b0292d7a3464ed27cf20a826e87f0d2be3c073967adc7dc9c166d9869a8b1fb4f536a5b736c35dc3fc589609cf8c4e05bf2a2df29c288a7849cae8c02a39951a8a48f3a2c5e1eef3b984668d6f673632f36a8fbcb7fc774a93a0e2d272930920c865a2075ae970461c9dc02d89793fb288284447996ba303ff8422725cb1ada7f4d219ffce9436d838bea913d032e49489346344249efcec3a1179c2c706c707b8fbff873e5a36637d1650ab14bea75949545da0cf5ced42dca8c97c6436d6f2679b8193443ac68bbcc65791178823b0bf5fbcb3bb3e187f598115cfa572a09ca0b54bb4fcacd7476722cde9fde66d24b3b623524f8b8df2b82fa1346fe6e4a067ac0fde4eed910f376cb68de5f7fc5914aa3165886b25078aaec25c6e41e43e848ead9bbd8688fea7eea75367c2f3ec714321c4133e803faaccf992f845293519a03cbcf2b247545549c6f35a9f41bb58c75c30db6d3b75fba2a02561d98f69c054751b32f5c5c1f7d91753be11e1f83ec5972bb81fb0d99a12db97fae7004d354735ac074c70780c872daf88d0e8ce5250fb50d28b50e73ebf2720fe5cb099209a74c6246b97fe429877422e309ae9d1a3cb29fc61c489adba0a8e523a8db4578be2c4a57675c86b23d30433865a66a448d27de551c0ebfaf2f88c9f0b8508271f889db15d62d3f0e2881d961caa98610914218a0a3026700a5c932421e571be857b125cee360b92478ed080ff6363603aa6454392e522274afbda16a514c27f81dc6b26b275e1bf7e797a8a88f1e90246f3cdf891e0579bcf3c458dbb6ca728fcf3386520cf9ba932f0dd186187eb3b17fd64c301b8d656633571f48bc4261d2dd9a41887594239215e03552c47f523e3f77324424a0f7eeb315f9fceeb885f4938ad286375374a687ebe16ecdef6a5afa648ef2c33f82fb420edd5006bab13ffb429bf4040a8c060e58e04f9494c68d0e54530cd4
@@ -18,4 +18,4 @@ export * from './components/admin/site-health/site-health-types';
18
18
  export * from './components/admin/site-health/site-health-uptime.integration';
19
19
  export * from './components/admin/site-health/site-health-utils';
20
20
  export * from './components/admin/sites/sites.integration';
21
- export * from './components/general/contentful.management';
21
+ export * from './components/integrations/contentful.management';
package/dist/index.js CHANGED
@@ -7,28 +7,12 @@ export * from './components/general/404';
7
7
  export * from './components/general/accordion';
8
8
  export * from './components/general/buzzwordbingo';
9
9
  export * from './components/general/cache-manager';
10
- export * from './components/general/calendly';
11
10
  export * from './components/general/callout';
12
11
  export * from './components/general/carousel';
13
12
  export * from './components/general/carousel.drag';
14
- export * from './components/general/cloudinary';
15
- export * from './components/general/contentful.delivery';
16
- export * from './components/general/contentful.items.components';
17
- export * from './components/general/contentful.management';
18
13
  export * from './components/general/css';
19
14
  export * from './components/general/faq-accordion';
20
- export * from './components/general/flickr';
21
- export * from './components/general/google.reviews.components';
22
- export * from './components/general/google.reviews.functions';
23
- export * from './components/general/googleanalytics';
24
- export * from './components/general/googlemap';
25
- export * from './components/general/googlesearch';
26
- export * from './components/general/gravatar.components';
27
- export * from './components/general/gravatar.functions';
28
- export * from './components/general/hubspot.components';
29
15
  export * from './components/general/image';
30
- export * from './components/general/instagram.components';
31
- export * from './components/general/instagram.functions';
32
16
  export * from './components/general/intersection-observer';
33
17
  export * from './components/general/loading';
34
18
  export * from './components/general/splitscroll';
@@ -56,14 +40,31 @@ export * from './components/general/semantic';
56
40
  export * from './components/general/sidepanel';
57
41
  export * from './components/general/sitemap';
58
42
  export * from './components/general/smartimage';
59
- export * from './components/general/socialcard';
60
43
  export * from './components/general/tab';
61
44
  export * from './components/general/table';
62
45
  export * from './components/general/tiles';
63
46
  export * from './components/general/timeline';
64
- export * from './components/general/wordpress.components';
65
- export * from './components/general/wordpress.functions';
66
- export * from './components/general/yelp';
47
+ export * from './components/integrations/calendly';
48
+ export * from './components/integrations/cloudinary';
49
+ export * from './components/integrations/contentful.delivery';
50
+ export * from './components/integrations/contentful.items.components';
51
+ export * from './components/integrations/contentful.management';
52
+ export * from './components/integrations/flickr';
53
+ export * from './components/integrations/google.reviews.components';
54
+ export * from './components/integrations/google.reviews.functions';
55
+ export * from './components/integrations/googleanalytics';
56
+ export * from './components/integrations/googlemap';
57
+ export * from './components/integrations/googlesearch';
58
+ export * from './components/integrations/gravatar.components';
59
+ export * from './components/integrations/gravatar.functions';
60
+ export * from './components/integrations/hubspot.components';
61
+ export * from './components/integrations/instagram.components';
62
+ export * from './components/integrations/instagram.functions';
63
+ export * from './components/integrations/socialcard';
64
+ export * from './components/integrations/gemini-api.client';
65
+ export * from './components/integrations/wordpress.components';
66
+ export * from './components/integrations/wordpress.functions';
67
+ export * from './components/integrations/yelp';
67
68
  export * from './components/shoppingcart/ebay.components';
68
69
  export * from './components/shoppingcart/ebay.functions';
69
70
  export * from './components/shoppingcart/paypal';
@@ -98,5 +99,3 @@ export * from './components/sitebuilder/page/lib/pageStorageTypes';
98
99
  export * from './components/sitebuilder/page/lib/propTypeIntrospection';
99
100
  export * from './components/sitebuilder/page/lib/types';
100
101
  export * from './components/sitebuilder/page/lib/usePageBuilder';
101
- export * from './components/utilities/functions';
102
- export * from './components/utilities/gemini-api.client';
@@ -2,23 +2,13 @@
2
2
  // Use this entry point for Next.js server components, API routes, and build-time code
3
3
  // Note: Client components (with JSX, CSS imports, browser APIs) are NOT exported here.
4
4
  // Import those from the main package entry point: @pixelated-tech/components
5
- // Admin
6
5
  export * from './components/admin/sites/sites.integration';
7
- // Config
8
6
  export * from './components/config/config';
9
7
  export * from './components/config/config.server';
10
8
  export * from './components/config/config.types';
11
9
  export * from './components/config/config.utils';
12
10
  export * from './components/config/config.validators';
13
11
  export * from './components/config/crypto';
14
- // SEO
15
- export * from './components/general/contentful.delivery';
16
- export * from './components/general/contentful.management';
17
- export * from './components/general/flickr';
18
- export * from './components/general/googlemap';
19
- export * from './components/general/google.reviews.functions';
20
- export * from './components/general/gravatar.functions';
21
- export * from './components/general/instagram.functions';
22
12
  export * from './components/general/manifest';
23
13
  export * from './components/general/metadata.functions';
24
14
  export * from './components/general/proxy-handler';
@@ -31,17 +21,22 @@ export * from './components/general/schema-recipe';
31
21
  export * from './components/general/schema-services';
32
22
  export * from './components/general/schema-website';
33
23
  export * from './components/general/sitemap';
34
- export * from './components/general/wordpress.functions';
35
- // Shopping Cart
24
+ export * from './components/general/utilities';
25
+ export * from './components/integrations/contentful.delivery';
26
+ export * from './components/integrations/contentful.management';
27
+ export * from './components/integrations/flickr';
28
+ export * from './components/integrations/gemini-api.server';
29
+ export * from './components/integrations/googlemap';
30
+ export * from './components/integrations/google.reviews.functions';
31
+ export * from './components/integrations/gravatar.functions';
32
+ export * from './components/integrations/instagram.functions';
33
+ export * from './components/integrations/wordpress.functions';
36
34
  export * from './components/shoppingcart/ebay.functions';
37
- // Sitebuilder - Config
38
35
  export * from './components/sitebuilder/config/ConfigEngine';
39
36
  export * from './components/sitebuilder/config/fonts';
40
37
  export * from './components/sitebuilder/config/google-fonts';
41
- // Sitebuilder - Form
42
38
  export * from './components/sitebuilder/form/formtypes';
43
39
  export * from './components/sitebuilder/form/formutils';
44
- // Sitebuilder - Page
45
40
  export * from './components/sitebuilder/page/lib/componentGeneration';
46
41
  export * from './components/sitebuilder/page/lib/componentMap';
47
42
  export * from './components/sitebuilder/page/lib/componentMetadata';
@@ -50,6 +45,3 @@ export * from './components/sitebuilder/page/lib/pageStorageLocal'; // used for
50
45
  export * from './components/sitebuilder/page/lib/pageStorageTypes';
51
46
  export * from './components/sitebuilder/page/lib/propTypeIntrospection';
52
47
  export * from './components/sitebuilder/page/lib/types';
53
- // Utilities
54
- export * from './components/utilities/functions';
55
- export * from './components/utilities/gemini-api.server';
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Centralized build script for pixelated-components
5
+ # Replaces the inline build command in package.json
6
+
7
+ echo ""
8
+ echo "================================================="
9
+ echo "🔨 Starting centralized build process"
10
+ echo "================================================="
11
+ echo ""
12
+
13
+ step=1
14
+
15
+ echo ""
16
+ echo "Step $((step++)): Validate Exports"
17
+ echo "================================================="
18
+ # directly run the validate script instead of npm wrapper
19
+ npx tsx src/scripts/validate-exports.js
20
+
21
+ echo ""
22
+ echo "Step $((step++)): Clean previous build"
23
+ echo "================================================="
24
+ rm -rf dist
25
+ echo "✅ Removed previous dist/ directory"
26
+
27
+ echo ""
28
+ echo "Step $((step++)): TypeScript build"
29
+ echo "================================================="
30
+ npx tsc --project tsconfig.json
31
+ echo "✅ TypeScript compilation completed"
32
+
33
+ echo ""
34
+ echo "Step $((step++)): Copy assets (rsync equivalent)"
35
+ echo "================================================="
36
+ # Copy CSS/SCSS/JSON and scripts from src into dist preserving structure
37
+ (cd src && tar -cf - $(find . -name "*.css" -o -name "*.scss" -o -name "*.json") scripts/) | tar -C dist -xf - || true
38
+ echo "✅ Copied assets to dist/ completed"
39
+
40
+ echo ""
41
+ echo "Step $((step++)): Prune unnecessary tsc output"
42
+ echo "================================================="
43
+ rm -rf dist/{images,stories,test,tests} || true
44
+ echo "✅ Pruned unnecessary files from dist/"
45
+
46
+ # Ensure encrypted config is present in dist (if available in src)
47
+ # This moves the responsibility of placing pixelated.config.json.enc into the build step
48
+ echo ""
49
+ echo "Step $((step++)): Ensure encrypted config is in dist (if available)"
50
+ echo "================================================="
51
+ DIST_DIR="dist"
52
+ ENC_DEST="$DIST_DIR/config/pixelated.config.json.enc"
53
+ PLAIN_DIST_CFG="$DIST_DIR/config/pixelated.config.json"
54
+
55
+ config_paths=("src/app/config/pixelated.config.json" "src/config/pixelated.config.json" "src/pixelated.config.json")
56
+ found_enc=false
57
+ for src in "${config_paths[@]}"; do
58
+ if [ -f "${src}.enc" ]; then
59
+ mkdir -p "$(dirname "${ENC_DEST}")"
60
+ cp "${src}.enc" "$ENC_DEST"
61
+ echo "✅ Copied ${src}.enc -> $ENC_DEST"
62
+ found_enc=true
63
+ break
64
+ fi
65
+ done
66
+
67
+ # Remove plaintext config from dist if present (avoid shipping plaintext)
68
+ if [ -f "$PLAIN_DIST_CFG" ]; then
69
+ echo "⚠️ Found plaintext config in dist at $PLAIN_DIST_CFG — removing it to avoid accidental publish."
70
+ rm -f "$PLAIN_DIST_CFG"
71
+ echo "✅ Removed $PLAIN_DIST_CFG"
72
+ else
73
+ echo "ℹ️ No plaintext config found in dist."
74
+ fi
75
+
76
+ if [ "$found_enc" = false ]; then
77
+ echo "ℹ️ No source .enc found in src; build did not place encrypted config. If you expect an encoded config, run 'npm run config:encrypt' and re-run build."
78
+ else
79
+ echo "✅ Encrypted config ensured in dist"
80
+ fi
81
+
82
+ echo ""
83
+ echo "================================================="
84
+ echo "✅ Build finished"
85
+ echo "================================================="
86
+ echo ""
@@ -7,6 +7,10 @@ import { encrypt, decrypt, isEncrypted } from '../components/config/crypto';
7
7
  * Usage:
8
8
  * npx tsx src/scripts/config-vault.js encrypt <filePath> <key>
9
9
  * npx tsx src/scripts/config-vault.js decrypt <filePath> <key>
10
+ *
11
+ * Behavior changes:
12
+ * - `encrypt` writes to `<file>.enc` (does not overwrite the plain file)
13
+ * - `decrypt` writes atomically to the plain filename (when given a `.enc` file it writes to the base name)
10
14
  */
11
15
  const [, , command, targetPath, argKey] = process.argv;
12
16
  let key = argKey || process.env.PIXELATED_CONFIG_KEY;
@@ -23,8 +27,8 @@ if (!key) {
23
27
  }
24
28
  if (!command || !targetPath || !key) {
25
29
  console.log('Usage:');
26
- console.log(' encrypt <filePath> [key] - Encrypts the file in place');
27
- console.log(' decrypt <filePath> [key] - Decrypts the file in place');
30
+ console.log(' encrypt <filePath> [key] - Encrypts the file and writes `<filePath>.enc`');
31
+ console.log(' decrypt <filePath> [key] - Decrypts the file and writes the plaintext file (atomic write)');
28
32
  console.log('\nNote: Key can be passed as argument or via PIXELATED_CONFIG_KEY env var.');
29
33
  process.exit(1);
30
34
  }
@@ -33,25 +37,36 @@ if (!fs.existsSync(fullPath)) {
33
37
  console.error(`File not found: ${fullPath}`);
34
38
  process.exit(1);
35
39
  }
36
- const content = fs.readFileSync(fullPath, 'utf8');
40
+ const atomicWrite = (destPath, data) => {
41
+ const dir = path.dirname(destPath);
42
+ const base = path.basename(destPath);
43
+ const tmp = path.join(dir, `.${base}.tmp`);
44
+ fs.writeFileSync(tmp, data, 'utf8');
45
+ fs.renameSync(tmp, destPath);
46
+ };
37
47
  try {
38
48
  if (command === 'encrypt') {
49
+ const content = fs.readFileSync(fullPath, 'utf8');
39
50
  if (isEncrypted(content)) {
40
- console.log('File is already encrypted.');
51
+ console.log('File is already encrypted. No action taken.');
41
52
  process.exit(0);
42
53
  }
43
54
  const encrypted = encrypt(content, key);
44
- fs.writeFileSync(fullPath, encrypted, 'utf8');
45
- console.log(`Successfully encrypted ${targetPath}`);
55
+ const encPath = fullPath.endsWith('.enc') ? fullPath : `${fullPath}.enc`;
56
+ atomicWrite(encPath, encrypted);
57
+ console.log(`Successfully encrypted ${targetPath} -> ${path.basename(encPath)}`);
46
58
  }
47
59
  else if (command === 'decrypt') {
60
+ const content = fs.readFileSync(fullPath, 'utf8');
48
61
  if (!isEncrypted(content)) {
49
- console.log('File is not encrypted.');
62
+ console.log('File is not encrypted. No action taken.');
50
63
  process.exit(0);
51
64
  }
52
65
  const decrypted = decrypt(content, key);
53
- fs.writeFileSync(fullPath, decrypted, 'utf8');
54
- console.log(`Successfully decrypted ${targetPath}`);
66
+ // Destination: if input ends with .enc, strip it; otherwise overwrite the provided path
67
+ const destPath = fullPath.endsWith('.enc') ? fullPath.slice(0, -4) : fullPath;
68
+ atomicWrite(destPath, decrypted);
69
+ console.log(`Successfully decrypted ${path.basename(fullPath)} -> ${path.basename(destPath)}`);
55
70
  }
56
71
  else {
57
72
  console.error(`Unknown command: ${command}`);
@@ -8,6 +8,10 @@ import { encrypt, decrypt, isEncrypted } from '../components/config/crypto';
8
8
  * Usage:
9
9
  * npx tsx src/scripts/config-vault.js encrypt <filePath> <key>
10
10
  * npx tsx src/scripts/config-vault.js decrypt <filePath> <key>
11
+ *
12
+ * Behavior changes:
13
+ * - `encrypt` writes to `<file>.enc` (does not overwrite the plain file)
14
+ * - `decrypt` writes atomically to the plain filename (when given a `.enc` file it writes to the base name)
11
15
  */
12
16
 
13
17
  const [,, command, targetPath, argKey] = process.argv;
@@ -27,8 +31,8 @@ if (!key) {
27
31
 
28
32
  if (!command || !targetPath || !key) {
29
33
  console.log('Usage:');
30
- console.log(' encrypt <filePath> [key] - Encrypts the file in place');
31
- console.log(' decrypt <filePath> [key] - Decrypts the file in place');
34
+ console.log(' encrypt <filePath> [key] - Encrypts the file and writes `<filePath>.enc`');
35
+ console.log(' decrypt <filePath> [key] - Decrypts the file and writes the plaintext file (atomic write)');
32
36
  console.log('\nNote: Key can be passed as argument or via PIXELATED_CONFIG_KEY env var.');
33
37
  process.exit(1);
34
38
  }
@@ -40,25 +44,36 @@ if (!fs.existsSync(fullPath)) {
40
44
  process.exit(1);
41
45
  }
42
46
 
43
- const content = fs.readFileSync(fullPath, 'utf8');
47
+ const atomicWrite = (destPath: string, data: string) => {
48
+ const dir = path.dirname(destPath);
49
+ const base = path.basename(destPath);
50
+ const tmp = path.join(dir, `.${base}.tmp`);
51
+ fs.writeFileSync(tmp, data, 'utf8');
52
+ fs.renameSync(tmp, destPath);
53
+ };
44
54
 
45
55
  try {
46
56
  if (command === 'encrypt') {
57
+ const content = fs.readFileSync(fullPath, 'utf8');
47
58
  if (isEncrypted(content)) {
48
- console.log('File is already encrypted.');
59
+ console.log('File is already encrypted. No action taken.');
49
60
  process.exit(0);
50
61
  }
51
62
  const encrypted = encrypt(content, key);
52
- fs.writeFileSync(fullPath, encrypted, 'utf8');
53
- console.log(`Successfully encrypted ${targetPath}`);
63
+ const encPath = fullPath.endsWith('.enc') ? fullPath : `${fullPath}.enc`;
64
+ atomicWrite(encPath, encrypted);
65
+ console.log(`Successfully encrypted ${targetPath} -> ${path.basename(encPath)}`);
54
66
  } else if (command === 'decrypt') {
67
+ const content = fs.readFileSync(fullPath, 'utf8');
55
68
  if (!isEncrypted(content)) {
56
- console.log('File is not encrypted.');
69
+ console.log('File is not encrypted. No action taken.');
57
70
  process.exit(0);
58
71
  }
59
72
  const decrypted = decrypt(content, key);
60
- fs.writeFileSync(fullPath, decrypted, 'utf8');
61
- console.log(`Successfully decrypted ${targetPath}`);
73
+ // Destination: if input ends with .enc, strip it; otherwise overwrite the provided path
74
+ const destPath = fullPath.endsWith('.enc') ? fullPath.slice(0, -4) : fullPath;
75
+ atomicWrite(destPath, decrypted);
76
+ console.log(`Successfully decrypted ${path.basename(fullPath)} -> ${path.basename(destPath)}`);
62
77
  } else {
63
78
  console.error(`Unknown command: ${command}`);
64
79
  process.exit(1);