@pixelated-tech/components 3.9.15 → 3.9.17

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.
@@ -22,6 +22,7 @@ export function getFullPixelatedConfig() {
22
22
  // If this library is installed as a package, check its dist/config as a fallback
23
23
  path.join(process.cwd(), 'node_modules', '@pixelated-tech', 'components', 'dist', 'config', filename),
24
24
  ];
25
+ // First, look for plaintext config files
25
26
  for (const configPath of paths) {
26
27
  if (fs.existsSync(configPath)) {
27
28
  try {
@@ -34,13 +35,46 @@ export function getFullPixelatedConfig() {
34
35
  }
35
36
  }
36
37
  }
38
+ // If not found, look for encrypted variants in the same locations (e.g., pixelated.config.json.enc)
39
+ const doIt = false;
40
+ if (!raw && doIt) {
41
+ for (const configPath of paths) {
42
+ const encPath = `${configPath}.enc`;
43
+ if (fs.existsSync(encPath)) {
44
+ try {
45
+ raw = fs.readFileSync(encPath, 'utf8');
46
+ source = encPath;
47
+ break;
48
+ }
49
+ catch (err) {
50
+ console.error(`Failed to read encrypted config file at ${encPath}`, err);
51
+ }
52
+ }
53
+ }
54
+ }
37
55
  if (!raw) {
38
56
  console.error('pixelated.config.json not found. Searched in src/app/config/, src/config/, and root.');
39
57
  return {};
40
58
  }
41
59
  // Handle decryption if the content is encrypted
42
60
  if (isEncrypted(raw)) {
43
- const key = process.env.PIXELATED_CONFIG_KEY;
61
+ // Allow key to come from env or a local .env.local fallback (useful for local/CI debugging)
62
+ let key = process.env.PIXELATED_CONFIG_KEY;
63
+ if (!key) {
64
+ const envPath = path.join(process.cwd(), '.env.local');
65
+ if (fs.existsSync(envPath)) {
66
+ try {
67
+ const envContent = fs.readFileSync(envPath, 'utf8');
68
+ const match = envContent.match(/^PIXELATED_CONFIG_KEY=(.*)$/m);
69
+ if (match && match[1]) {
70
+ key = match[1].trim();
71
+ }
72
+ }
73
+ catch (e) {
74
+ // ignore
75
+ }
76
+ }
77
+ }
44
78
  if (!key) {
45
79
  console.error('PIXELATED_CONFIG is encrypted but PIXELATED_CONFIG_KEY is not set in the environment.');
46
80
  return {};
@@ -19,6 +19,10 @@
19
19
  margin: 10px;
20
20
  }
21
21
 
22
+ .tile-image.clickable {
23
+ cursor: pointer;
24
+ }
25
+
22
26
  .tile-image img {
23
27
  width: 100%;
24
28
  height: 100% !important;
@@ -44,6 +48,12 @@
44
48
  }
45
49
  }
46
50
 
51
+ .tile-image-overlay,
52
+ .tile-image-overlay * {
53
+ pointer-events: none;
54
+ cursor: pointer;
55
+ }
56
+
47
57
  .tile-image:hover .tile-image-overlay {
48
58
  visibility: visible;
49
59
  width: 100% !important;
@@ -67,7 +77,7 @@
67
77
  transition-delay: 0.25s;
68
78
  }
69
79
 
70
- .tile-image-overlay-title{
80
+ .tile-image-overlay-title {
71
81
  margin-bottom: 10px;
72
82
  }
73
83
 
@@ -9,11 +9,12 @@ import "./tiles.css";
9
9
  Tiles.propTypes = {
10
10
  cards: PropTypes.array.isRequired,
11
11
  rowCount: PropTypes.number,
12
+ imgClick: PropTypes.func,
12
13
  };
13
14
  export function Tiles(props) {
14
15
  const rowCount = props.rowCount ?? 2;
15
16
  if (props.cards && props.cards.length > 0) {
16
- return (_jsx("div", { className: "tiles-container", children: _jsx("div", { className: `tile-container row-${rowCount}col`, children: props.cards.map((card, i) => (_jsx("div", { className: "gridItem", children: _jsx(Tile, { index: i, cardLength: props.cards.length, link: card.link, image: card.image, imageAlt: card.imageAlt, bodyText: card.bodyText }) }, i))) }) }));
17
+ return (_jsx("div", { className: "tiles-container", children: _jsx("div", { className: `tile-container row-${rowCount}col`, children: props.cards.map((card, i) => (_jsx("div", { className: "gridItem", children: _jsx(Tile, { index: i, cardLength: props.cards.length, link: card.link, image: card.image, imageAlt: card.imageAlt, bodyText: card.bodyText, imgClick: props.imgClick }) }, i))) }) }));
17
18
  }
18
19
  else {
19
20
  return (_jsx(Loading, {}));
@@ -27,10 +28,12 @@ Tile.propTypes = {
27
28
  image: PropTypes.string.isRequired,
28
29
  imageAlt: PropTypes.string,
29
30
  bodyText: PropTypes.string,
31
+ imgClick: PropTypes.func,
30
32
  };
31
33
  function Tile(props) {
32
34
  const config = usePixelatedConfig();
33
- const tileBody = _jsxs("div", { className: "tile-image", children: [_jsx(SmartImage, { src: props.image, title: props?.imageAlt ?? undefined, alt: props?.imageAlt ?? "", cloudinaryEnv: config?.cloudinary?.product_env ?? undefined }), _jsx("div", { className: "tile-image-overlay", children: _jsxs("div", { className: "tile-image-overlay-text", children: [_jsx("div", { className: "tile-image-overlay-title", children: props.imageAlt }), _jsx("div", { className: "tile-image-overlay-body", children: props.bodyText })] }) })] });
35
+ const imgClick = props.imgClick;
36
+ const tileBody = _jsxs("div", { className: "tile-image" + (imgClick ? " clickable" : ""), children: [_jsx(SmartImage, { src: props.image, title: props?.imageAlt ?? undefined, alt: props?.imageAlt ?? "", onClick: imgClick ? (event) => imgClick(event, props.image) : undefined, cloudinaryEnv: config?.cloudinary?.product_env ?? undefined }), _jsx("div", { className: "tile-image-overlay", children: _jsxs("div", { className: "tile-image-overlay-text", children: [_jsx("div", { className: "tile-image-overlay-title", children: props.imageAlt }), _jsx("div", { className: "tile-image-overlay-body", children: props.bodyText })] }) })] });
34
37
  return (_jsx("div", { className: "tile", id: 'tile-' + props.index, children: props.link ?
35
38
  _jsx("a", { href: props.link, className: "tileLink", children: tileBody })
36
39
  :
@@ -151,14 +151,6 @@ export const CLIENT_ONLY_PATTERNS = [
151
151
  /\bwindow\./,
152
152
  /["']use client["']/ // Client directive
153
153
  ];
154
- /**
155
- * Determines if a component file contains client-only code that requires browser execution
156
- * @param fileContent - The source code content of the file
157
- * @returns true if the file contains client-only patterns
158
- */
159
- export function isClientComponent(fileContent) {
160
- return CLIENT_ONLY_PATTERNS.some(pattern => pattern.test(fileContent));
161
- }
162
154
  /* ===== COMPONENT FILE DETECTION ===== */
163
155
  /**
164
156
  * Glob patterns for finding component files
@@ -1 +1 @@
1
- pxl:v1:3c2978eff23a9287d0ff83c6:d8979937576542bc09916f751f5fc1cf:a697ad370ce67491a655a119f4b00e82a990b19db110d33c0118399b87e902f0f3f22d693132977385119aeb39c22a65f15d5cb6a966d8f6ee92cdcc284a8b4e06ea10b3d50c43e88dccf4f912bdf4d7bdf7198ff77e4bd331fa4bf4e4b2ee88db2efbef089f2dab2c1257a27789d37aca1157f94debfe726a8b24ad25b56c8221f0dee67db15c5866879ad25c5895e80e95d1475e2f18f1342892176e2be3f64fdeffc53104ec915442b870bc25084f57572c2fd17ce3684fa0e3d4e75899af91328331f6f22cbd3b28395e8b4abca6367b8113956389e79f6f7c37f44edabc3b747b1522158402c79bc0e823021f1f6a29bcc3c260af89c72924e25e7bda860959eb9541268c541950cf53bf576f122ccb8fada3f0140ebe317a259c0616475098e4716748e8a8c7847ddd604d99624ec62dcf5bf41c5bd8e3c588308397cedf4c823f2cb287a4c6f90579e74ae19e93cf9f1e6117a9f2b755d3b17b15a2f5c16aa16edb9b190093ceebfc1c2f5059e09e95a221a73793b135e97e5b36fe0c1084d79552d262eb5a22373cdb7ae9c37d48fb65bcba26620c486dd7728f73e834cc1241e25f563a9067dda412b7fc79d1bd8b1a1d35beaca4386c4ae94303bcde5ffd840e5e8d3f12b9e842c1176ea117d0628fb17c3b518c0c07eb38f42a92ceefa909f8761f040a99c1fc9589b91fca5d8b2b4170367f321b5b6cd9396766a2b4e3fc659f4b89d867fc56046dc4c37b0bbeb6544d02d68c3acace0b691dff76c6c93c7f849b0c75ef96346438f40f904192a62300f8888fae6bc2e95324c6f24fbb85c114144d6c0dcfea1600c65044ce05cff2375834d6466b5fe39cf4835e3e4b1bc4610e755a0cc645d7ec3dd52c634e1e95ff8cb0adb0a90b0f37906dd23fc5df7ecb07013e256c1dd952c214e5a84e871ce4d7f65f0907efa620c209eb878bb733d207be48fd0c7b5a7ffd116f878f5e7c696226645573077252ede2724b9cf336e3c98684d79949fdce90df29c78818ddda01f7d6ad850f39e4a965f09da3b09504747ebb64c4516c4adf85b10d2e236a91894829cb793bc9d308b21362c3aa20605ab2ef1c2085c2a60ffce480d147380343c4b048fe31a545c9cd780255deade8481910ac448bf8205f25529c5f7697afaa3257c675b4dc35bdc0150c27ee013ade2404ec52ccf8110d332823c1fafec097807568bb1eda8fd31873c07bc8eab64045d8fd9116f9dda31c892b7a3d7edb56d90eb4778cb44e874f4890aa621b649d1c22c50e07d7b7bdf58fd6d20af33fc4e54db0a90e982c43b2242173d8630da571b8afdcbfe192db14c7e17b79598ed620f4dabe8aa68aa293fc8fa3a30b21c0cd960f81fe13a6b58c9ee88cb47169324daf3532b4c360d038737569c59efc3e6d4b7d5713fe1d7f6b2627e4d0389ce3ef8f42e642a776e916db6e9ef564edff69df0253da312ff3d8f2a4439d91b83d873cbc76fcdb623814fb271911c60e2aa694210902071b99f5b16c3c1e8f072f8aece36973499628dbd0a246d3e8de6d7b742b463bf62be46cb69ab63e3008794bd7a54132a9158104a6ed5a3348990c367da439eeec9f686f14302084c742a20451186714d323b9e64b7444388e069c7871525349eca42aa33696a6db4cca742971e17ff9ebc38e905131a619e63bcdc40190256de09a6fc64f1adbc26626553de33001bb9d76e5eb7e0f70a4dbf434b059b687a4f4c4aa99262060e0a66be48d9740b0e938ff8e88ce9f2b4c768f9010e2dc22c3d43a4b405465cb6690721e983baf161e2e0fc1066526ffb98f9fdcc600b29da4ce2f50f5921a077f005b5b9e941efebe4b7427390863ff08217fedf4c0c9c71ac006c52419f2f5840d203f09f0f0f47bde9983362c91e8dc8ce3ed8c01e893aeaa16b82319a92c23bd53a1dec899187043104e3bde9f4b80e84c65f71dbc71ffbe97d10747268433b4076c60031c37770db87630a40ffb9883e02026fb97c7acd37655df0d7410ae3a126d12b01948e6e6faed6710f06de47bd5ce98bf46cb7a43e81fed5d2d314806437e7adfc2d84fb49499642526ea86f6cb6b4dd257a3d0744bc359129c76828e62f967963171525a2500eaaaa5a26a792b06d0d0abf3200cdc4daa3b6414abb58e535eaa8133f631b9681f6bdd0950b5a0e938a29f8e3efce355727fe19e5b05d3141ef0562030610869fae2633bd62d1b9acc55369dea01fcf1ee407fb13c26e5a3c954ffcc9d532d8389feef545005db4521e02da5ce51c5e10b54b5e46ded85f7fe5d243cb393ae2c820a066af0e89ab9903b863f6237de82ed4a08159b3750b004a55e647d5002e9d32085906a275a8be60b2b1ad4daa1ca9076da23a1ff05aaa7f808c138a18f5c914b99c44fc99db2e65efc470aceed0753767d787532e7eaf797eeabb2841f1269b425739235fdc3a011215670c6ce05b104fc5540d95cb1de21a1e564c2c311dfdad176e01743d7dadef3819c09e70f93c6ba9d6e50e8170fd9383db0037d15c485497357fb5a2d3502c418df21c5816c8a933eb719c160984843e76bc0107ac8ba6d25e8c06a8e84cb9fa9b7ded05a97571e2e7c39c557d1617951ef0539d53000be04e7e2bbe1552f406ee2e7ea4dec012cd9ec2e1a061e6e266ced742209890e99ad6a5db825116acec9694f89733e662e6a2039dbd334dd96557184ff3cdd245e73fae6b5feb7b7263a1afa0e280d38e1d436051e8761cfbc3e332f9b1e4602243ade135e737919f22fbe3e3ff38d9ecc877836d9ea7ac9934f452e7de0fae0ac327aae98d25b825654798b4ff235c894292b25335eb15db9eeddf6b1cfa85d2ced9a0cf69756fe3141619c60ef146a98775e11a1a026f5a93865141a0a99b17bb22d7835d1cf1437008efd1b78f39b53245cc174bf46fbcb3a46d11455e702285e64fbbb3eb567d9d3bd5c3d5552eb0c2f8a2b075f6ef649105e01ffbef71deac2057306282cdde4bcca44a1653d3d9d275b3abbe14d6cddc3cd1ca368a47b125abc53547a50f929d061f06a498ea4e22f6fcf4134004b8662edeccce35491a4a2d6c4f3acb7ec84ff9285ccf2a1a3024fedd87af45e9a64eb9f0117f3bdd74059b9f652681c8dec6820dabc87232d2fad38c24ce89ceffef4f5917cc5c1432f10bfe1318226363c8e58a8c5034912917d4b55d7727c73e23655efc32963833a543584e305ef11eef68fb1b133b1b10ae72910e03a7b2da5c67aba73ffb44c9817aadda7e560ba554f56bad2204231a26e3d27297d46edf0634061e6da68d8bf48b8e1f98add482877511cba25652bdab1641500eac3ab4e23e9f14f7944fbe4e85f4bddb5afff3bb1d31ab42affba5d6cec5ef1a57a7125c0dca1074ae8ce8de8a5b73038e31d3b2ff44a8950921ec84e3e0262169d087950c7bb6262540c52de92814a655e2d9a50cba5ecd2d70cf1783b4fed0756ab1db17159f27caac342cee1f17016bbcd85c21ea9fec39be67df93c786e36aae2895412bd310e755e19c2a613bd69ce9c7ee5714f02aa2770b87d2b843db1439a5c5ef1caa67888f4711fc82752f97c710fc179c93283b295081a5e3bb49bd78b9e972b7b8ecf128a2ff2410da8ab8fbc2132192a9282483cd6a3f6645b0b795c1545e2ed063ceeded3678d3584f6c6ee2d63490ae01e1f33e7683ca1e6270aef5b2b5db983217ba37188df150e4232fd90a63328abb03acb595704449f90b463e43a253c687cbab26fa0e35a12daf8398ce24ab3048fb859972260a12dfb74f81fc93c01560489e1a38cae1146afa5633c1bc18e0b055a9ba0a3ee779403ed2982a5dbc222f31366446931a2792ef830495e782a8d9ba4d436bf4c38be32a01b1ebb0c3ad5bdbb7db897b009dee820d891dcb63644084e647bfd52c39ddf779924d313552eba352715aa15b7675001a5c6ff2524133e8e6300b15ba1db7225807e8265c22d88db98864fd594a0a59a086d375431a4be52a94d4a6bf09cbc38c4e28565d0dc91aed0e0ff8eeeea34e8e4bf71e45e6ab9bcce3d237228183220b615d4cacb25ac11ebede86b5a38f049888c4acecd7415d40f31e682a1de18c4b33e04b64dee3f443a6cc64bbbe194cf24b2481be7b69277d14e07e0e88a7053f6eea78cd1b704476ec812492e44068a15ae1c65b7623d333625f87bf08e877678e805dd255d82451f43b4ffab975c3612a11f1c9a65f93ffb4d0ad49e2f9df53a13f3ee2b8800f2eab0923b5ed7293129c27db0ca52e04ac3fdfd845ec97f3f9de18fd490a7c407529f90d3fb8f38b31cc75860621527b7dbe0d5b8d61b7e63eab059183861f3360364762448917f81d7eb86c8dbcab3cbd7e1a683fcad0c44106ef96e0bad49b73fdb94bcbe14a33100ee19de4a79b770e3a2b71634a9d05a74dfefc9da35a750b77b73604b03b56899d2ca337266323d4638a1f646294e2814bea3a0f9b3050c4ae6714abe427d355cb056e8efda7fa6a9f312f2ac38c598ae0aea208ec4cbc98d660427fe3a1537a5c247a06692ef974e43869645d25a09d6f682f08cf164aa772dd907bec24dc4bf6a27c8548db89ad0ca04c6f758ba3e9efac744bb8fd6e74274685aceef53d973e8e86a05701d61ef382025263f110ee601ba049dab1c6f1b9c28c663143ddef8b185dfbbf97dd1f6ead7350c22aedec0c0429ccf86a5afbf81f140185a318955d6c3f6dfbb4bc4ff015e0a644b321e226b53427aecc8821ee1525c9a1f2fd9d753b77621b948f0ff16ce1b86e764bd83d2fd91b5e97409f5cb236f400006adcbd91a04283603f14278f4726e328868eab3c0f723e9a02e098eff12d65a07adf4d87a9ab962236ee587c096c2145cd890051a3558ec4bb5a97f4f93a55897f2bc570d46361d4774ece4f01567f368f208cb193cf116e33b9350342209f79336ca837cc79135be3be28785ee7fc4040161a9235975dee2eb795c6f256c01d8f4c0d7aa505e954608f95ee5810761f775c57cd7ede22dcb53beadd30330475301f029a2b4e431f93d296ce5d9fe33e1665d45370ba87dfda992a76612a4128c8a766d912c75ea3e65232cfd006bd4e4a23692426a544abce95f19d21369230377a65c56799deabcac14684a46e677c80e5c4806409e7879a3defcd32b078c2b3743e02d4d
1
+ pxl:v1:c70cbe09dc837373c6f97231:63d645cc86fe3d8ab9ed584e12567337:de5401e0f619e7bc50e6333ad1dce44aa01813cf21d55ad9a607b7492a46295e65915a988c3809c1cef0048c3a6a08d6ac73e35b951bfd442a4d8a0db29f0e004d244f7a01dfce7e92fc3b099f5d9f16cb1783ce383d9b4e20b4ec1dfe28761ccc1dde660d0e53be13c7adc4421b9ba775be16ad44368d4f45f821e9b03823c41a49434823e33a0b61e2886b85fa68f73bf2f1789e8096796d32438a116051d99e121795aae13365f27a68ea07f4261bb63ba5e3ce52033efc2a64d2681962bbe5ae76e5f0b1c265815ef651557727ec362c9fd0f92eeda070c1468578e0b30c23d764dd9ca0be56ffc28d61834702aa601dfb5df093d25f71e4255c9f34cae0f8a09512220468642249e477d53bfa1cd22b2c5b83fc5f995812bdf5f18056e87551e6f29f72a8c37fe119f3cf895cd88f4eda02c509a1ee469c48043a00f01e69320454262165aeb499c981cf765ecebc40a5a0b99d9dbd991e11fbc1a1c4140e1fa21652edeaaa569e064bfe063e72521b4bb43d6603be1f1ead52536a52beeac985d91ab3b6e20b1d0e0bfefbe1a56340801736cf3a82fe6dc7b663d9cd70d68669894cc79ff0b992809a0910f7f2d42abfb86b64e4cf2e126a4ebab8976308ff61ea414cc33153c5feaf40f68cb7b61952f048761d75878cb57aeaf3a4ef04e754c560e268192749c6dc07b4488caafd5e1dcd09ac94523f7e9a0242a4ae85de3d045d98ba5a96af9d5068a8054728cd99f37cda73ccf8b46a5cb3978444e1e7d2a5b9a2ba90bb855c7e0ab9f13d78e9b234777109061565185775d369037c84505ab5bd224e91eea59ad32b64fd56d5451c9ac490c6cc479f4e6d76a02484a1aa9735979134a3b8b966817cd518e1d930d668f0f7fdfdda39e577bdb9a8332fd9dc1c60de418e51842965ab88d48469e6122c96e46a4302916a59cfae10957c91a7ac45f059fdb9429b993ac1705ab1a6fc43218f46c1b968fd00e41e11e7e2e4b7b69df78156cad91d30e7ab0d332fd99d1a6883d6a83d0cd713fa39cac6483ffef4f8603b8f9522d4f06968dd04eda944b152e056b173bed76609d1a9894bf6e35c1368f17e76ecc794792ed4b4444b924b6867599da45b208fe50ef540f99ac1fbe22b8ac4ceaee2ad069e96726c4740bb15fd12d50b9718cfed9a6eefc5db4bf86c78ab847d00043033f9991dc978ca5c5f1555e77ef04ff00d83da505bc8141ae1539b0e1dd3f42730fee6ba5d6fc02788df8a0489ba4f1b2542f6fd87b76c2bbb93330c165230d7c767bd51387ec8730bae8d435187da55cfb1deb10be60a80be7d29aa27772b2ecbb4340c0901574c8fee44d2c23b4c9d5f012671a260ad62dde2f1f95d6d6892c90a5fd57b20f3c36e10ad28083981685aea41774f828f5b379a0ae5041ea0d29aebf09e62f0ffaa789b3e6616270a3f6e74a5edd7ed18716f157af8af96c959021ba8553be53db638e3663c21a40d4932702163dbfd5834fb4a7f113bdc4d29346b7238e4461324ed2b614ee4a6e434d1207a824864aea955b24090f8e82320b395dc724defa313b3711ca8dedb1ede348367c8879a5c46aaa90bb57581b7643012fa19ca0c6d8956d4c8b8b50b1a077d4c3e3f5ee802084939b5c7a0c9113bcc06d787411d0c3e4a9f8177f0ec89bba4d0d7ff0a30751daadf6e762ac910f0298e4d3ca0d278f27dfaf16ec0d13533aeab259aa3f896f5018b4fd6b7a8b8b4002c3008e4cf8fb7f550e228579cb459c167095da7eb1930a1504325ad30b08de63df8854f7b47becf4e82d19629ba5ee2ae0a43d74f4af216b38db702b4d7325abc47dc9e9ead359f5f892dee204ec12a4dba509c2fe4892d2fe6fcac1911116fd01a5901af1c60b107ae53a588fb2bfadfa88fdcf2b7ddbd14c4d658ad2b580004cf888379c3339a95e93b7e03c41068b6b2c27c8bc29cf8c075f794f33ee5cff0ad08320c06c28b43308015c3ec4084062714aee486db9e0aa492637917f8a68d544515ec38546f9535f24d4fe44190a4cd7b75a8986f789fa083975f031339af222e6ad84da67d633c4afc7bfcc88c01ba16dc3d9f81952ebd4f2e940d427213fbe7628d1fb53c280c14599cfc6fa500e67abd3a989a275c605c0f2993d15a21a887df3e1d508cc4e5089eb3f5ab9f8a0f8e6b04f9f630025adb8986367f14a2523ddd12e46a9baf761a161dd1e28037d701e7f452784ceaf6e804d021ff29ab1043c6d088fc2942c8fa8c66bcc0c76ba52c4ec527d3327f598992a30390d3dcefc64d626b4a60c5320a7e02f10e6d55a685153cf677d519e2c521c36e35a5f64dc3a4bd05fc5a4201e2f04354646b8e539723eaaf112899f0d9b34a1b3370e6e65a41b474503d85f1052064430939732e7b1212df608011d9e220965ab48c7c4925f81437d7d3c93995f0d6f9f92ec74d4faf4ffdf3a25c8eb4df5140e1afa3f5409edf52eb2a2c14e0b65d9d0ccf9f3c435fcd51676d0db022705a517a732634b2869e01ad3a2669aa84c9ced95dbba2203bc0134944b568a0d9dce086b7dfbd11b4066e2572d1d4c00854cd476fcb27a7b8dd262ba9da2de4da1db90f47ad3053967e24de047fde2e7dbd8933176cf47b2cd51297d5aafbbfd801b71df15768d159a69556acf580f012b6230891b6b5fd61c9c80ef7f7a76a12b4018cad6e2d419b072e9622811253cfa73cc780a310cedd439797bf2aceb7d9855c8ad06e6e2b7daacc0c93d89cdc265b27d8d46d1101ba1518bfad0d5dc869b0c1d8879ee8ba85ff41aae3adb7a3a4c85b939b15591b022ffa43b89ec305668f755a230e59362007a035421f4ddd0b1ee4a4d4f18db66d758a9bfb8d26610f0e340153d551dfc11c48ae816de02e2aaae4d4b2b6a2aaa2c5c11d4d2ef5410bd0b230c8e9d0bacce1906fffdb0e28d5ccdfb54682845bbe59906d3e50b896f888a5eb91120c1192046228a27e9e8a13d525c7d1df963d947a71bb95cd07a4526bf61c8b3986e8963871e94bc8e7db723cc9646fed49b5f823c601aa12dc2c61c2f4035e6a2f68793d31285f1d54b195b8a3126677ebcba699ba055beef1adae9c29213faf38a6e7cd889bb7ff37e6cda3e0ce5bc1274dd2b373da6fff9e9cae18e714b9a43698b1e3ebd31b3a2abd8bdcf500834b5aad1ec8220e1375b558cf53459b4f77d1746abfb6311c9b0f12035642bd307ca926622c07ab5b68487a41cb90f503303b33f828c48dabc4076b0a72e4aee69e367e4a8e145ad5955afa4a901ba32acd46f75b7f7cf9f9e8f0557a5687f8097ca8f0af694cee2f2adff0d31683c0526f99c29e6bf54c62f71f61315b566fd9aa15131722e07a27b014632a82b9f6746ab8c9e2826d37056aff5658303f0c6e5d3a08616a3c49be7ddc1f6b7e0f2bed7a9d17b5fdbc9e99aae9e3ccf683da49b5123ea90cc25887751c2bbc3b931b0fa2891cbd2619aad145898a71105e393284311f39a642570540c7d8936e0284c269b178f1aca07a7d378caeabb7273ac2b114120caf05080d27485f11515313561b4b7cc573da43745b623b56ac4facaa6e970f2f191422ba45d12744754d290034694b2f7eb950c225e0b53907ea68985e3b2c27eaba4ecf774a24aba842826d73c2fc5b1e2671c80a392bbe72c45c0bdca3e62d3a87fddf6684187b577e9d3da21833747e6d25d15b06e035d892acf1242e4a739e844c9b1a62592ba83eaacdcef19cbeda4c9f5fa152a8219f735b8c3d43553b799fbedf1013883f9aee7b3069650f53b117790261d2b48e1fe289061aaca736dbaa8118a836b5b1045bfe4e2707829ee2d9fb978814f79fd2be61f36c3d490e149201731fc3c38685de1620306340a5259d62550560c9e36f1b60c0264b5a64e865f5cf21756fdda21270111d02e13947a651b14056296d268c1b9b89edfc983233541797a70c7831a361b94d830c96f02765ed2bd27cb15c4f06228d723db97c61ef679074960db5bcd533d88485589224412cbd02676d63a70588c4d864c9eb20703d8413749d4ec2195a118524ff63097750c68e991b6a53971ced2ad22d22c13300af131a8133b64c68095e4f4a52689a9368d339e0ec0b769f0a83e7002fa02ad4c954499680fd93c42d0e8aa7864eac7bad8aea8c560815ba620e55f6157b20e937db6d02a6abc3f04588c07e1f02445a0c01230316def1f7f4fb7bedecf8d49034dcb27aeabf3a733e8c02160ef1a91909edc20a49266a38eae88e83f66a6809a0a9edefc8feeba2bced621cbba28a3a400df83f152292e3a9ad0074599a90387fbd67bbe9a9c64611176ee81623283839e3959304b5addca8e5875b32f84a0b446bbbe391c323c41f7aeee5a992419da68f5fd47da1b3a227c8532eebe46fd3491f02ea9e11ab4932a74a0770800301c311afb2af8918511fe6d2051a4af053e34629543e23870b064173b0b8bde9ef6745b62b6f6ff9f6a54d138ff3fcc6fd710d3f136a3780269d2d92babd145319aa64e441c516426640dfde81d70a07f24c8956d512a9db47c1d3d928d56bf183206b8f67f2fb91dba8bab52f23e477db35d633e5a63e22daa78b33d28dcceb7820bb43ec99cc8a1a30164c5a0a090bc2065df37f184ab3075618917222cc4f2bbf8680e881507124b5f0b7460a1a590ee142d9fd4097cd9bd375cf4f14b9b7b21243456752f100e07d25818e7e7383637fc6c96ecd60c91ac6bd8ad82b3efcf60ad0f874ae681f896ea249478e1fc1eda90417d7352bad6b06a67cfa70a0b2d6f5063da403c182eebd05896e20e4dd13f409f34a6afc8c378bb42966c0ade4368275feb11b642d5038e8cf01a9738bd09f10a49fb4daf9d84bdcf5703bf575125369b15e59a980511187a9a5365fe5aa43fd68a012d673f6899e919d0e7ef5223bd594c1b0035ed1bed609f2e38e46e8311b58b9706c7dbeec8e0d3887e6f5dfb611df3ee8a67a122cda70d8dbf5dcf299048c85408d32765c0fb9fd2febb8c1d067f6d2fe8d82ce499197943f22d375f8cc4c5546a23136b08bc90b288abea36e22b87e8bd37bf3aa9dbeb1f643da7a42fb01a245a892db4ae375365d3eda2a0ffe83fe953d0cdfbfd46a6869dd13b5953d4343c452f0f66b2825cb6a819e586fd53ea7c3b8dc7a8bf2e09c28747e7e9883be9a50ae
@@ -13,30 +13,22 @@ import { encrypt, decrypt, isEncrypted } from '../components/config/crypto';
13
13
  * - `decrypt` writes atomically to the plain filename (when given a `.enc` file it writes to the base name)
14
14
  */
15
15
  const [, , command, targetPath, argKey] = process.argv;
16
+ // Helper: obtain key from arg or env or .env.local (only used for encrypt/decrypt)
16
17
  let key = argKey || process.env.PIXELATED_CONFIG_KEY;
17
- // If key is still missing, try to load it from .env.local
18
18
  if (!key) {
19
19
  const envPath = path.join(process.cwd(), '.env.local');
20
20
  if (fs.existsSync(envPath)) {
21
- const envContent = fs.readFileSync(envPath, 'utf8');
22
- const match = envContent.match(/^PIXELATED_CONFIG_KEY=(.*)$/m);
23
- if (match && match[1]) {
24
- key = match[1].trim();
21
+ try {
22
+ const envContent = fs.readFileSync(envPath, 'utf8');
23
+ const match = envContent.match(/^PIXELATED_CONFIG_KEY=(.*)$/m);
24
+ if (match && match[1])
25
+ key = match[1].trim();
26
+ }
27
+ catch (e) {
28
+ // ignore
25
29
  }
26
30
  }
27
31
  }
28
- if (!command || !targetPath || !key) {
29
- console.log('Usage:');
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)');
32
- console.log('\nNote: Key can be passed as argument or via PIXELATED_CONFIG_KEY env var.');
33
- process.exit(1);
34
- }
35
- const fullPath = path.isAbsolute(targetPath) ? targetPath : path.resolve(process.cwd(), targetPath);
36
- if (!fs.existsSync(fullPath)) {
37
- console.error(`File not found: ${fullPath}`);
38
- process.exit(1);
39
- }
40
32
  const atomicWrite = (destPath, data) => {
41
33
  const dir = path.dirname(destPath);
42
34
  const base = path.basename(destPath);
@@ -44,29 +36,148 @@ const atomicWrite = (destPath, data) => {
44
36
  fs.writeFileSync(tmp, data, 'utf8');
45
37
  fs.renameSync(tmp, destPath);
46
38
  };
39
+ // Helper: print usage/help
40
+ function printUsage() {
41
+ console.log('Usage:');
42
+ console.log(' npx tsx src/scripts/config-vault.ts encrypt <filePath> [key] - Encrypts <filePath> (writes <filePath>.enc)');
43
+ console.log(' npx tsx src/scripts/config-vault.ts decrypt <filePath> [key] - Decrypts <filePath>.enc and writes plaintext');
44
+ console.log(' npx tsx src/scripts/config-vault.ts postbuild - CI helper: decrypts and injects into .next/server');
45
+ console.log('\nNotes:');
46
+ console.log(' - Key can be passed as argument or via PIXELATED_CONFIG_KEY env var.');
47
+ console.log(' - Use PIXELATED_CONFIG_DEBUG=1 for verbose output during postbuild.');
48
+ }
49
+ // Helpful messages when arguments are missing
50
+ if (!command) {
51
+ console.log('No command provided.');
52
+ printUsage();
53
+ process.exit(0);
54
+ }
55
+ if (command === 'help' || command === '--help' || command === '-h') {
56
+ printUsage();
57
+ process.exit(0);
58
+ }
59
+ // If encrypt/decrypt are requested, ensure targetPath and key exist; log informative messages
60
+ if (command === 'encrypt' || command === 'decrypt') {
61
+ if (!targetPath) {
62
+ console.log('No target path provided for encrypt/decrypt.');
63
+ printUsage();
64
+ process.exit(1);
65
+ }
66
+ if (!key) {
67
+ // we attempted to resolve key from env/.env.local earlier; if still missing, inform the user
68
+ console.log('No key provided for encrypt/decrypt (argument, PIXELATED_CONFIG_KEY, or .env.local).');
69
+ printUsage();
70
+ process.exit(1);
71
+ }
72
+ }
73
+ /**
74
+ * Post-build behavior used by CI (Amplify):
75
+ * - Look for an encrypted config file in standard candidate locations
76
+ * - Validate PIXELATED_CONFIG_KEY (from env or .env.local)
77
+ * - Decrypt in-place and copy plaintext to .next/server/pixelated.config.json
78
+ * - Validate JSON and emit a concise success message
79
+ */
80
+ function decryptPostBuild() {
81
+ const DEBUG = process.env.PIXELATED_CONFIG_DEBUG === '1';
82
+ const candidates = [
83
+ path.join(process.cwd(), 'src/app/config/pixelated.config.json.enc'),
84
+ path.join(process.cwd(), 'src/config/pixelated.config.json.enc'),
85
+ path.join(process.cwd(), 'src/pixelated.config.json.enc'),
86
+ ];
87
+ let foundEnc = null;
88
+ for (const p of candidates) {
89
+ if (fs.existsSync(p)) {
90
+ foundEnc = p;
91
+ break;
92
+ }
93
+ }
94
+ if (!foundEnc) {
95
+ if (DEBUG)
96
+ console.log('No encrypted config found; nothing to do.');
97
+ process.exit(0);
98
+ }
99
+ // Resolve key (env preferred, then .env.local)
100
+ let keyLocal = process.env.PIXELATED_CONFIG_KEY;
101
+ if (!keyLocal) {
102
+ const envPath = path.join(process.cwd(), '.env.local');
103
+ if (fs.existsSync(envPath)) {
104
+ try {
105
+ const envContent = fs.readFileSync(envPath, 'utf8');
106
+ const match = envContent.match(/^PIXELATED_CONFIG_KEY=(.*)$/m);
107
+ if (match && match[1])
108
+ keyLocal = match[1].trim();
109
+ }
110
+ catch (e) {
111
+ // ignore
112
+ }
113
+ }
114
+ }
115
+ if (!keyLocal) {
116
+ console.error('PIXELATED_CONFIG_KEY not set; cannot decrypt config.');
117
+ process.exit(1);
118
+ }
119
+ if (!/^[0-9a-fA-F]{64}$/.test(keyLocal)) {
120
+ console.error('PIXELATED_CONFIG_KEY invalid: must be 64 hex characters.');
121
+ process.exit(1);
122
+ }
123
+ try {
124
+ const raw = fs.readFileSync(foundEnc, 'utf8');
125
+ if (!isEncrypted(raw)) {
126
+ console.error('Found file is not in encrypted format.');
127
+ process.exit(1);
128
+ }
129
+ const decrypted = decrypt(raw, keyLocal);
130
+ const dest = foundEnc.endsWith('.enc') ? foundEnc.slice(0, -4) : `${foundEnc}.plain`;
131
+ atomicWrite(dest, decrypted);
132
+ // Copy to .next/server for SSR to pick up
133
+ const injectPath = path.join(process.cwd(), '.next', 'server', 'pixelated.config.json');
134
+ fs.mkdirSync(path.dirname(injectPath), { recursive: true });
135
+ fs.copyFileSync(dest, injectPath);
136
+ // Validate JSON
137
+ JSON.parse(decrypted);
138
+ console.log('Config injected into .next/server/pixelated.config.json');
139
+ if (DEBUG)
140
+ console.log(`Decrypted ${path.basename(foundEnc)} -> ${injectPath}`);
141
+ process.exit(0);
142
+ }
143
+ catch (err) {
144
+ console.error(`Post-build decrypt failed: ${err.message}`);
145
+ process.exit(1);
146
+ }
147
+ }
47
148
  try {
48
149
  if (command === 'encrypt') {
49
- const content = fs.readFileSync(fullPath, 'utf8');
150
+ if (!key) {
151
+ console.error('Encryption key is required.');
152
+ process.exit(1);
153
+ }
154
+ const content = fs.readFileSync(targetPath, 'utf8');
50
155
  if (isEncrypted(content)) {
51
156
  console.log('File is already encrypted. No action taken.');
52
157
  process.exit(0);
53
158
  }
54
159
  const encrypted = encrypt(content, key);
55
- const encPath = fullPath.endsWith('.enc') ? fullPath : `${fullPath}.enc`;
160
+ const encPath = targetPath.endsWith('.enc') ? targetPath : `${targetPath}.enc`;
56
161
  atomicWrite(encPath, encrypted);
57
162
  console.log(`Successfully encrypted ${targetPath} -> ${path.basename(encPath)}`);
58
163
  }
59
164
  else if (command === 'decrypt') {
60
- const content = fs.readFileSync(fullPath, 'utf8');
165
+ if (!key) {
166
+ console.error('Decryption key is required.');
167
+ process.exit(1);
168
+ }
169
+ const content = fs.readFileSync(targetPath, 'utf8');
61
170
  if (!isEncrypted(content)) {
62
171
  console.log('File is not encrypted. No action taken.');
63
172
  process.exit(0);
64
173
  }
65
174
  const decrypted = decrypt(content, key);
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;
175
+ const destPath = targetPath.endsWith('.enc') ? targetPath.slice(0, -4) : targetPath;
68
176
  atomicWrite(destPath, decrypted);
69
- console.log(`Successfully decrypted ${path.basename(fullPath)} -> ${path.basename(destPath)}`);
177
+ console.log(`Successfully decrypted ${path.basename(targetPath)} -> ${path.basename(destPath)}`);
178
+ }
179
+ else if (command === 'postbuild' || command === 'post-build' || command === 'inject') {
180
+ decryptPostBuild();
70
181
  }
71
182
  else {
72
183
  console.error(`Unknown command: ${command}`);
@@ -15,35 +15,22 @@ import { encrypt, decrypt, isEncrypted } from '../components/config/crypto';
15
15
  */
16
16
 
17
17
  const [,, command, targetPath, argKey] = process.argv;
18
- let key = argKey || process.env.PIXELATED_CONFIG_KEY;
19
18
 
20
- // If key is still missing, try to load it from .env.local
19
+ // Helper: obtain key from arg or env or .env.local (only used for encrypt/decrypt)
20
+ let key = argKey || process.env.PIXELATED_CONFIG_KEY;
21
21
  if (!key) {
22
22
  const envPath = path.join(process.cwd(), '.env.local');
23
23
  if (fs.existsSync(envPath)) {
24
- const envContent = fs.readFileSync(envPath, 'utf8');
25
- const match = envContent.match(/^PIXELATED_CONFIG_KEY=(.*)$/m);
26
- if (match && match[1]) {
27
- key = match[1].trim();
24
+ try {
25
+ const envContent = fs.readFileSync(envPath, 'utf8');
26
+ const match = envContent.match(/^PIXELATED_CONFIG_KEY=(.*)$/m);
27
+ if (match && match[1]) key = match[1].trim();
28
+ } catch (e) {
29
+ // ignore
28
30
  }
29
31
  }
30
32
  }
31
33
 
32
- if (!command || !targetPath || !key) {
33
- console.log('Usage:');
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)');
36
- console.log('\nNote: Key can be passed as argument or via PIXELATED_CONFIG_KEY env var.');
37
- process.exit(1);
38
- }
39
-
40
- const fullPath = path.isAbsolute(targetPath) ? targetPath : path.resolve(process.cwd(), targetPath);
41
-
42
- if (!fs.existsSync(fullPath)) {
43
- console.error(`File not found: ${fullPath}`);
44
- process.exit(1);
45
- }
46
-
47
34
  const atomicWrite = (destPath: string, data: string) => {
48
35
  const dir = path.dirname(destPath);
49
36
  const base = path.basename(destPath);
@@ -52,28 +39,150 @@ const atomicWrite = (destPath: string, data: string) => {
52
39
  fs.renameSync(tmp, destPath);
53
40
  };
54
41
 
42
+ // Helper: print usage/help
43
+ function printUsage(): void {
44
+ console.log('Usage:');
45
+ console.log(' npx tsx src/scripts/config-vault.ts encrypt <filePath> [key] - Encrypts <filePath> (writes <filePath>.enc)');
46
+ console.log(' npx tsx src/scripts/config-vault.ts decrypt <filePath> [key] - Decrypts <filePath>.enc and writes plaintext');
47
+ console.log(' npx tsx src/scripts/config-vault.ts postbuild - CI helper: decrypts and injects into .next/server');
48
+ console.log('\nNotes:');
49
+ console.log(' - Key can be passed as argument or via PIXELATED_CONFIG_KEY env var.');
50
+ console.log(' - Use PIXELATED_CONFIG_DEBUG=1 for verbose output during postbuild.');
51
+ }
52
+
53
+ // Helpful messages when arguments are missing
54
+ if (!command) {
55
+ console.log('No command provided.');
56
+ printUsage();
57
+ process.exit(0);
58
+ }
59
+ if (command === 'help' || command === '--help' || command === '-h') {
60
+ printUsage();
61
+ process.exit(0);
62
+ }
63
+
64
+ // If encrypt/decrypt are requested, ensure targetPath and key exist; log informative messages
65
+ if (command === 'encrypt' || command === 'decrypt') {
66
+ if (!targetPath) {
67
+ console.log('No target path provided for encrypt/decrypt.');
68
+ printUsage();
69
+ process.exit(1);
70
+ }
71
+ if (!key) {
72
+ // we attempted to resolve key from env/.env.local earlier; if still missing, inform the user
73
+ console.log('No key provided for encrypt/decrypt (argument, PIXELATED_CONFIG_KEY, or .env.local).');
74
+ printUsage();
75
+ process.exit(1);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Post-build behavior used by CI (Amplify):
81
+ * - Look for an encrypted config file in standard candidate locations
82
+ * - Validate PIXELATED_CONFIG_KEY (from env or .env.local)
83
+ * - Decrypt in-place and copy plaintext to .next/server/pixelated.config.json
84
+ * - Validate JSON and emit a concise success message
85
+ */
86
+ function decryptPostBuild(): void {
87
+ const DEBUG = process.env.PIXELATED_CONFIG_DEBUG === '1';
88
+ const candidates = [
89
+ path.join(process.cwd(), 'src/app/config/pixelated.config.json.enc'),
90
+ path.join(process.cwd(), 'src/config/pixelated.config.json.enc'),
91
+ path.join(process.cwd(), 'src/pixelated.config.json.enc'),
92
+ ];
93
+
94
+ let foundEnc: string | null = null;
95
+ for (const p of candidates) {
96
+ if (fs.existsSync(p)) {
97
+ foundEnc = p;
98
+ break;
99
+ }
100
+ }
101
+
102
+ if (!foundEnc) {
103
+ if (DEBUG) console.log('No encrypted config found; nothing to do.');
104
+ process.exit(0);
105
+ }
106
+
107
+ // Resolve key (env preferred, then .env.local)
108
+ let keyLocal = process.env.PIXELATED_CONFIG_KEY;
109
+ if (!keyLocal) {
110
+ const envPath = path.join(process.cwd(), '.env.local');
111
+ if (fs.existsSync(envPath)) {
112
+ try {
113
+ const envContent = fs.readFileSync(envPath, 'utf8');
114
+ const match = envContent.match(/^PIXELATED_CONFIG_KEY=(.*)$/m);
115
+ if (match && match[1]) keyLocal = match[1].trim();
116
+ } catch (e) {
117
+ // ignore
118
+ }
119
+ }
120
+ }
121
+
122
+ if (!keyLocal) {
123
+ console.error('PIXELATED_CONFIG_KEY not set; cannot decrypt config.');
124
+ process.exit(1);
125
+ }
126
+ if (!/^[0-9a-fA-F]{64}$/.test(keyLocal)) {
127
+ console.error('PIXELATED_CONFIG_KEY invalid: must be 64 hex characters.');
128
+ process.exit(1);
129
+ }
130
+
131
+ try {
132
+ const raw = fs.readFileSync(foundEnc, 'utf8');
133
+ if (!isEncrypted(raw)) {
134
+ console.error('Found file is not in encrypted format.');
135
+ process.exit(1);
136
+ }
137
+ const decrypted = decrypt(raw, keyLocal);
138
+ const dest = foundEnc.endsWith('.enc') ? foundEnc.slice(0, -4) : `${foundEnc}.plain`;
139
+ atomicWrite(dest, decrypted);
140
+ // Copy to .next/server for SSR to pick up
141
+ const injectPath = path.join(process.cwd(), '.next', 'server', 'pixelated.config.json');
142
+ fs.mkdirSync(path.dirname(injectPath), { recursive: true });
143
+ fs.copyFileSync(dest, injectPath);
144
+ // Validate JSON
145
+ JSON.parse(decrypted);
146
+ console.log('Config injected into .next/server/pixelated.config.json');
147
+ if (DEBUG) console.log(`Decrypted ${path.basename(foundEnc)} -> ${injectPath}`);
148
+ process.exit(0);
149
+ } catch (err: any) {
150
+ console.error(`Post-build decrypt failed: ${err.message}`);
151
+ process.exit(1);
152
+ }
153
+ }
154
+
55
155
  try {
56
156
  if (command === 'encrypt') {
57
- const content = fs.readFileSync(fullPath, 'utf8');
157
+ if (!key) {
158
+ console.error('Encryption key is required.');
159
+ process.exit(1);
160
+ }
161
+ const content = fs.readFileSync(targetPath, 'utf8');
58
162
  if (isEncrypted(content)) {
59
163
  console.log('File is already encrypted. No action taken.');
60
164
  process.exit(0);
61
165
  }
62
166
  const encrypted = encrypt(content, key);
63
- const encPath = fullPath.endsWith('.enc') ? fullPath : `${fullPath}.enc`;
167
+ const encPath = targetPath.endsWith('.enc') ? targetPath : `${targetPath}.enc`;
64
168
  atomicWrite(encPath, encrypted);
65
169
  console.log(`Successfully encrypted ${targetPath} -> ${path.basename(encPath)}`);
66
170
  } else if (command === 'decrypt') {
67
- const content = fs.readFileSync(fullPath, 'utf8');
171
+ if (!key) {
172
+ console.error('Decryption key is required.');
173
+ process.exit(1);
174
+ }
175
+ const content = fs.readFileSync(targetPath, 'utf8');
68
176
  if (!isEncrypted(content)) {
69
177
  console.log('File is not encrypted. No action taken.');
70
178
  process.exit(0);
71
179
  }
72
180
  const decrypted = decrypt(content, key);
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;
181
+ const destPath = targetPath.endsWith('.enc') ? targetPath.slice(0, -4) : targetPath;
75
182
  atomicWrite(destPath, decrypted);
76
- console.log(`Successfully decrypted ${path.basename(fullPath)} -> ${path.basename(destPath)}`);
183
+ console.log(`Successfully decrypted ${path.basename(targetPath)} -> ${path.basename(destPath)}`);
184
+ } else if (command === 'postbuild' || command === 'post-build' || command === 'inject') {
185
+ decryptPostBuild();
77
186
  } else {
78
187
  console.error(`Unknown command: ${command}`);
79
188
  process.exit(1);