@csszyx/unplugin 0.5.0 → 0.6.2

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.
@@ -154,6 +154,7 @@ import { preprocess as vuePreprocess } from "@csszyx/vue-adapter";
154
154
  import { createUnplugin } from "unplugin";
155
155
 
156
156
  // src/html-transformer.ts
157
+ import { createHash } from "crypto";
157
158
  function injectChecksum(html, checksum, minify = false) {
158
159
  const attrName = minify ? "data-sz-cs" : "data-sz-checksum";
159
160
  const htmlTagPattern = /<html([^>]*)>/i;
@@ -213,6 +214,46 @@ function injectHydrationData(html, mangleMap, checksum, options = {}) {
213
214
  function transformIndexHtml(html, mangleMap, checksum, options = {}) {
214
215
  return injectHydrationData(html, mangleMap, checksum, options);
215
216
  }
217
+ function buildRecoveryManifest(tokens, options = {}) {
218
+ const stripped = options.production === true;
219
+ const strippedDevOnlyPaths = [];
220
+ const sorted = {};
221
+ const sortedKeys = [...tokens.keys()].sort();
222
+ for (const key of sortedKeys) {
223
+ const data = tokens.get(key);
224
+ if (!data) {
225
+ continue;
226
+ }
227
+ if (stripped && data.mode === "dev-only") {
228
+ strippedDevOnlyPaths.push(data.path);
229
+ continue;
230
+ }
231
+ sorted[key] = stripped ? { mode: data.mode, component: data.component, path: "" } : data;
232
+ }
233
+ const serialised = JSON.stringify(sorted);
234
+ const fullChecksum = createHash("sha256").update(serialised).digest("hex");
235
+ const checksum = fullChecksum.substring(0, 16);
236
+ const buildId = `${Date.now().toString(36)}-${fullChecksum.substring(0, 6)}`;
237
+ return {
238
+ manifest: { buildId, checksum, tokens: sorted },
239
+ strippedDevOnlyPaths
240
+ };
241
+ }
242
+ function injectRecoveryManifest(html, manifest) {
243
+ if (Object.keys(manifest.tokens).length === 0) {
244
+ return html;
245
+ }
246
+ const json = JSON.stringify(manifest);
247
+ const scriptTag = `<script id="__SZ_RECOVERY_MANIFEST__" type="application/json">${json}</script>`;
248
+ if (html.includes("</head>")) {
249
+ return html.replace("</head>", `${scriptTag}
250
+ </head>`);
251
+ } else if (html.includes("</html>")) {
252
+ return html.replace("</html>", `${scriptTag}
253
+ </html>`);
254
+ }
255
+ return html + scriptTag;
256
+ }
216
257
 
217
258
  // src/theme-type-writer.ts
218
259
  import { mkdirSync, writeFileSync } from "fs";
@@ -537,12 +578,14 @@ function mangleCodeClassesSync(code, mangleMap) {
537
578
  }
538
579
  function createCsszyxPlugins(options = {}) {
539
580
  const manglingEnabled = options.production?.mangle !== false;
581
+ const astBudgetOverride = options.build?.astBudgetLimit;
540
582
  const state = {
541
583
  classes: /* @__PURE__ */ new Set(),
542
584
  mangleMap: {},
543
585
  checksum: "",
544
586
  finalized: false,
545
- rootDir: process.cwd()
587
+ rootDir: process.cwd(),
588
+ recoveryTokens: /* @__PURE__ */ new Map()
546
589
  };
547
590
  const SAFELIST_FILENAME = "csszyx-classes.html";
548
591
  const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx", ".ts", ".js"]);
@@ -587,7 +630,7 @@ function createCsszyxPlugins(options = {}) {
587
630
  if (!content.includes("sz=") && !content.includes("sz:")) {
588
631
  continue;
589
632
  }
590
- const result = transformSourceCode(content);
633
+ const result = transformSourceCode(content, filePath, { astBudget: astBudgetOverride });
591
634
  if (!result.transformed) {
592
635
  continue;
593
636
  }
@@ -597,6 +640,9 @@ function createCsszyxPlugins(options = {}) {
597
640
  for (const cls of result.rawClassNames) {
598
641
  rawDiscoveredClasses.add(cls);
599
642
  }
643
+ for (const [token, data] of result.recoveryTokens) {
644
+ state.recoveryTokens.set(token, data);
645
+ }
600
646
  if (result.usesRuntime) {
601
647
  const szCallRe = /_sz\(\s*\{/g;
602
648
  let szMatch;
@@ -818,7 +864,7 @@ ${sourceDirective}`
818
864
  transformed = true;
819
865
  }
820
866
  } else {
821
- const result = transformSourceCode(code);
867
+ const result = transformSourceCode(code, id, { astBudget: astBudgetOverride });
822
868
  transformedCode = result.code;
823
869
  usesRuntime = result.usesRuntime;
824
870
  usesMerge = result.usesMerge;
@@ -831,6 +877,9 @@ ${sourceDirective}`
831
877
  ${msg}`);
832
878
  }
833
879
  }
880
+ for (const [token, data] of result.recoveryTokens) {
881
+ state.recoveryTokens.set(token, data);
882
+ }
834
883
  }
835
884
  }
836
885
  if (transformedCode.includes("<html") && /layout|Root|Document|app\\.tsx?$/i.test(id)) {
@@ -971,7 +1020,7 @@ ${sourceDirective}`
971
1020
  return;
972
1021
  }
973
1022
  try {
974
- result = transformSourceCode(fileContent);
1023
+ result = transformSourceCode(fileContent, ctx.file, { astBudget: astBudgetOverride });
975
1024
  } catch {
976
1025
  return;
977
1026
  }
@@ -982,6 +1031,9 @@ ${sourceDirective}`
982
1031
  for (const cls of result.classes) {
983
1032
  state.classes.add(cls);
984
1033
  }
1034
+ for (const [token, data] of result.recoveryTokens) {
1035
+ state.recoveryTokens.set(token, data);
1036
+ }
985
1037
  if (state.classes.size > sizeBefore) {
986
1038
  writeSafelistFile(state.classes);
987
1039
  const safelistPath = path.join(state.rootDir, SAFELIST_FILENAME);
@@ -998,10 +1050,24 @@ ${sourceDirective}`
998
1050
  */
999
1051
  handler(html) {
1000
1052
  finalizeMangleMap();
1001
- return transformIndexHtml(html, state.mangleMap, state.checksum, {
1053
+ let result = transformIndexHtml(html, state.mangleMap, state.checksum, {
1002
1054
  mode: options.production?.injectChecksum === false ? "script" : "script",
1003
1055
  minify: process.env.NODE_ENV === "production"
1004
1056
  });
1057
+ if (state.recoveryTokens.size > 0) {
1058
+ const isProduction = process.env.NODE_ENV === "production";
1059
+ const { manifest, strippedDevOnlyPaths } = buildRecoveryManifest(
1060
+ state.recoveryTokens,
1061
+ { production: isProduction }
1062
+ );
1063
+ if (strippedDevOnlyPaths.length > 0) {
1064
+ console.warn(
1065
+ `[csszyx] Stripped ${strippedDevOnlyPaths.length} szRecover="dev-only" token(s) from the production manifest. Recovery for these elements is disabled in production by design. Sites: ${strippedDevOnlyPaths.join(", ")}`
1066
+ );
1067
+ }
1068
+ result = injectRecoveryManifest(result, manifest);
1069
+ }
1070
+ return result;
1005
1071
  }
1006
1072
  }
1007
1073
  }
package/dist/index.cjs CHANGED
@@ -395,6 +395,7 @@ var import_vue_adapter = require("@csszyx/vue-adapter");
395
395
  var import_unplugin = require("unplugin");
396
396
 
397
397
  // src/html-transformer.ts
398
+ var import_node_crypto = require("crypto");
398
399
  function injectChecksum(html, checksum, minify = false) {
399
400
  const attrName = minify ? "data-sz-cs" : "data-sz-checksum";
400
401
  const htmlTagPattern = /<html([^>]*)>/i;
@@ -454,6 +455,46 @@ function injectHydrationData(html, mangleMap, checksum, options = {}) {
454
455
  function transformIndexHtml(html, mangleMap, checksum, options = {}) {
455
456
  return injectHydrationData(html, mangleMap, checksum, options);
456
457
  }
458
+ function buildRecoveryManifest(tokens, options = {}) {
459
+ const stripped = options.production === true;
460
+ const strippedDevOnlyPaths = [];
461
+ const sorted = {};
462
+ const sortedKeys = [...tokens.keys()].sort();
463
+ for (const key of sortedKeys) {
464
+ const data = tokens.get(key);
465
+ if (!data) {
466
+ continue;
467
+ }
468
+ if (stripped && data.mode === "dev-only") {
469
+ strippedDevOnlyPaths.push(data.path);
470
+ continue;
471
+ }
472
+ sorted[key] = stripped ? { mode: data.mode, component: data.component, path: "" } : data;
473
+ }
474
+ const serialised = JSON.stringify(sorted);
475
+ const fullChecksum = (0, import_node_crypto.createHash)("sha256").update(serialised).digest("hex");
476
+ const checksum = fullChecksum.substring(0, 16);
477
+ const buildId = `${Date.now().toString(36)}-${fullChecksum.substring(0, 6)}`;
478
+ return {
479
+ manifest: { buildId, checksum, tokens: sorted },
480
+ strippedDevOnlyPaths
481
+ };
482
+ }
483
+ function injectRecoveryManifest(html, manifest) {
484
+ if (Object.keys(manifest.tokens).length === 0) {
485
+ return html;
486
+ }
487
+ const json = JSON.stringify(manifest);
488
+ const scriptTag = `<script id="__SZ_RECOVERY_MANIFEST__" type="application/json">${json}</script>`;
489
+ if (html.includes("</head>")) {
490
+ return html.replace("</head>", `${scriptTag}
491
+ </head>`);
492
+ } else if (html.includes("</html>")) {
493
+ return html.replace("</html>", `${scriptTag}
494
+ </html>`);
495
+ }
496
+ return html + scriptTag;
497
+ }
457
498
 
458
499
  // src/theme-type-writer.ts
459
500
  var import_node_fs = require("fs");
@@ -778,12 +819,14 @@ function mangleCodeClassesSync(code, mangleMap) {
778
819
  }
779
820
  function createCsszyxPlugins(options = {}) {
780
821
  const manglingEnabled = options.production?.mangle !== false;
822
+ const astBudgetOverride = options.build?.astBudgetLimit;
781
823
  const state = {
782
824
  classes: /* @__PURE__ */ new Set(),
783
825
  mangleMap: {},
784
826
  checksum: "",
785
827
  finalized: false,
786
- rootDir: process.cwd()
828
+ rootDir: process.cwd(),
829
+ recoveryTokens: /* @__PURE__ */ new Map()
787
830
  };
788
831
  const SAFELIST_FILENAME = "csszyx-classes.html";
789
832
  const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx", ".ts", ".js"]);
@@ -828,7 +871,7 @@ function createCsszyxPlugins(options = {}) {
828
871
  if (!content.includes("sz=") && !content.includes("sz:")) {
829
872
  continue;
830
873
  }
831
- const result = (0, import_compiler.transformSourceCode)(content);
874
+ const result = (0, import_compiler.transformSourceCode)(content, filePath, { astBudget: astBudgetOverride });
832
875
  if (!result.transformed) {
833
876
  continue;
834
877
  }
@@ -838,6 +881,9 @@ function createCsszyxPlugins(options = {}) {
838
881
  for (const cls of result.rawClassNames) {
839
882
  rawDiscoveredClasses.add(cls);
840
883
  }
884
+ for (const [token, data] of result.recoveryTokens) {
885
+ state.recoveryTokens.set(token, data);
886
+ }
841
887
  if (result.usesRuntime) {
842
888
  const szCallRe = /_sz\(\s*\{/g;
843
889
  let szMatch;
@@ -1059,7 +1105,7 @@ ${sourceDirective}`
1059
1105
  transformed = true;
1060
1106
  }
1061
1107
  } else {
1062
- const result = (0, import_compiler.transformSourceCode)(code);
1108
+ const result = (0, import_compiler.transformSourceCode)(code, id, { astBudget: astBudgetOverride });
1063
1109
  transformedCode = result.code;
1064
1110
  usesRuntime = result.usesRuntime;
1065
1111
  usesMerge = result.usesMerge;
@@ -1072,6 +1118,9 @@ ${sourceDirective}`
1072
1118
  ${msg}`);
1073
1119
  }
1074
1120
  }
1121
+ for (const [token, data] of result.recoveryTokens) {
1122
+ state.recoveryTokens.set(token, data);
1123
+ }
1075
1124
  }
1076
1125
  }
1077
1126
  if (transformedCode.includes("<html") && /layout|Root|Document|app\\.tsx?$/i.test(id)) {
@@ -1212,7 +1261,7 @@ ${sourceDirective}`
1212
1261
  return;
1213
1262
  }
1214
1263
  try {
1215
- result = (0, import_compiler.transformSourceCode)(fileContent);
1264
+ result = (0, import_compiler.transformSourceCode)(fileContent, ctx.file, { astBudget: astBudgetOverride });
1216
1265
  } catch {
1217
1266
  return;
1218
1267
  }
@@ -1223,6 +1272,9 @@ ${sourceDirective}`
1223
1272
  for (const cls of result.classes) {
1224
1273
  state.classes.add(cls);
1225
1274
  }
1275
+ for (const [token, data] of result.recoveryTokens) {
1276
+ state.recoveryTokens.set(token, data);
1277
+ }
1226
1278
  if (state.classes.size > sizeBefore) {
1227
1279
  writeSafelistFile(state.classes);
1228
1280
  const safelistPath = path.join(state.rootDir, SAFELIST_FILENAME);
@@ -1239,10 +1291,24 @@ ${sourceDirective}`
1239
1291
  */
1240
1292
  handler(html) {
1241
1293
  finalizeMangleMap();
1242
- return transformIndexHtml(html, state.mangleMap, state.checksum, {
1294
+ let result = transformIndexHtml(html, state.mangleMap, state.checksum, {
1243
1295
  mode: options.production?.injectChecksum === false ? "script" : "script",
1244
1296
  minify: process.env.NODE_ENV === "production"
1245
1297
  });
1298
+ if (state.recoveryTokens.size > 0) {
1299
+ const isProduction = process.env.NODE_ENV === "production";
1300
+ const { manifest, strippedDevOnlyPaths } = buildRecoveryManifest(
1301
+ state.recoveryTokens,
1302
+ { production: isProduction }
1303
+ );
1304
+ if (strippedDevOnlyPaths.length > 0) {
1305
+ console.warn(
1306
+ `[csszyx] Stripped ${strippedDevOnlyPaths.length} szRecover="dev-only" token(s) from the production manifest. Recovery for these elements is disabled in production by design. Sites: ${strippedDevOnlyPaths.join(", ")}`
1307
+ );
1308
+ }
1309
+ result = injectRecoveryManifest(result, manifest);
1310
+ }
1311
+ return result;
1246
1312
  }
1247
1313
  }
1248
1314
  }
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  unplugin,
9
9
  vitePlugin,
10
10
  webpackPlugin
11
- } from "./chunk-CW4XYEQR.js";
11
+ } from "./chunk-JGJOUK2R.js";
12
12
  import {
13
13
  createPostCSSPlugin,
14
14
  escapeCSSClassName,
package/dist/vite.cjs CHANGED
@@ -140,6 +140,7 @@ function mangleCSSSync(css, mangleMap, options = {}) {
140
140
  }
141
141
 
142
142
  // src/html-transformer.ts
143
+ var import_node_crypto = require("crypto");
143
144
  function injectChecksum(html, checksum, minify = false) {
144
145
  const attrName = minify ? "data-sz-cs" : "data-sz-checksum";
145
146
  const htmlTagPattern = /<html([^>]*)>/i;
@@ -199,6 +200,46 @@ function injectHydrationData(html, mangleMap, checksum, options = {}) {
199
200
  function transformIndexHtml(html, mangleMap, checksum, options = {}) {
200
201
  return injectHydrationData(html, mangleMap, checksum, options);
201
202
  }
203
+ function buildRecoveryManifest(tokens, options = {}) {
204
+ const stripped = options.production === true;
205
+ const strippedDevOnlyPaths = [];
206
+ const sorted = {};
207
+ const sortedKeys = [...tokens.keys()].sort();
208
+ for (const key of sortedKeys) {
209
+ const data = tokens.get(key);
210
+ if (!data) {
211
+ continue;
212
+ }
213
+ if (stripped && data.mode === "dev-only") {
214
+ strippedDevOnlyPaths.push(data.path);
215
+ continue;
216
+ }
217
+ sorted[key] = stripped ? { mode: data.mode, component: data.component, path: "" } : data;
218
+ }
219
+ const serialised = JSON.stringify(sorted);
220
+ const fullChecksum = (0, import_node_crypto.createHash)("sha256").update(serialised).digest("hex");
221
+ const checksum = fullChecksum.substring(0, 16);
222
+ const buildId = `${Date.now().toString(36)}-${fullChecksum.substring(0, 6)}`;
223
+ return {
224
+ manifest: { buildId, checksum, tokens: sorted },
225
+ strippedDevOnlyPaths
226
+ };
227
+ }
228
+ function injectRecoveryManifest(html, manifest) {
229
+ if (Object.keys(manifest.tokens).length === 0) {
230
+ return html;
231
+ }
232
+ const json = JSON.stringify(manifest);
233
+ const scriptTag = `<script id="__SZ_RECOVERY_MANIFEST__" type="application/json">${json}</script>`;
234
+ if (html.includes("</head>")) {
235
+ return html.replace("</head>", `${scriptTag}
236
+ </head>`);
237
+ } else if (html.includes("</html>")) {
238
+ return html.replace("</html>", `${scriptTag}
239
+ </html>`);
240
+ }
241
+ return html + scriptTag;
242
+ }
202
243
 
203
244
  // src/theme-scanner.ts
204
245
  var EMPTY_THEME = { colors: [], spacings: [], fonts: [], radii: [], shadows: [] };
@@ -662,12 +703,14 @@ function mangleCodeClassesSync(code, mangleMap) {
662
703
  }
663
704
  function createCsszyxPlugins(options = {}) {
664
705
  const manglingEnabled = options.production?.mangle !== false;
706
+ const astBudgetOverride = options.build?.astBudgetLimit;
665
707
  const state = {
666
708
  classes: /* @__PURE__ */ new Set(),
667
709
  mangleMap: {},
668
710
  checksum: "",
669
711
  finalized: false,
670
- rootDir: process.cwd()
712
+ rootDir: process.cwd(),
713
+ recoveryTokens: /* @__PURE__ */ new Map()
671
714
  };
672
715
  const SAFELIST_FILENAME = "csszyx-classes.html";
673
716
  const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx", ".ts", ".js"]);
@@ -712,7 +755,7 @@ function createCsszyxPlugins(options = {}) {
712
755
  if (!content.includes("sz=") && !content.includes("sz:")) {
713
756
  continue;
714
757
  }
715
- const result = (0, import_compiler.transformSourceCode)(content);
758
+ const result = (0, import_compiler.transformSourceCode)(content, filePath, { astBudget: astBudgetOverride });
716
759
  if (!result.transformed) {
717
760
  continue;
718
761
  }
@@ -722,6 +765,9 @@ function createCsszyxPlugins(options = {}) {
722
765
  for (const cls of result.rawClassNames) {
723
766
  rawDiscoveredClasses.add(cls);
724
767
  }
768
+ for (const [token, data] of result.recoveryTokens) {
769
+ state.recoveryTokens.set(token, data);
770
+ }
725
771
  if (result.usesRuntime) {
726
772
  const szCallRe = /_sz\(\s*\{/g;
727
773
  let szMatch;
@@ -943,7 +989,7 @@ ${sourceDirective}`
943
989
  transformed = true;
944
990
  }
945
991
  } else {
946
- const result = (0, import_compiler.transformSourceCode)(code);
992
+ const result = (0, import_compiler.transformSourceCode)(code, id, { astBudget: astBudgetOverride });
947
993
  transformedCode = result.code;
948
994
  usesRuntime = result.usesRuntime;
949
995
  usesMerge = result.usesMerge;
@@ -956,6 +1002,9 @@ ${sourceDirective}`
956
1002
  ${msg}`);
957
1003
  }
958
1004
  }
1005
+ for (const [token, data] of result.recoveryTokens) {
1006
+ state.recoveryTokens.set(token, data);
1007
+ }
959
1008
  }
960
1009
  }
961
1010
  if (transformedCode.includes("<html") && /layout|Root|Document|app\\.tsx?$/i.test(id)) {
@@ -1096,7 +1145,7 @@ ${sourceDirective}`
1096
1145
  return;
1097
1146
  }
1098
1147
  try {
1099
- result = (0, import_compiler.transformSourceCode)(fileContent);
1148
+ result = (0, import_compiler.transformSourceCode)(fileContent, ctx.file, { astBudget: astBudgetOverride });
1100
1149
  } catch {
1101
1150
  return;
1102
1151
  }
@@ -1107,6 +1156,9 @@ ${sourceDirective}`
1107
1156
  for (const cls of result.classes) {
1108
1157
  state.classes.add(cls);
1109
1158
  }
1159
+ for (const [token, data] of result.recoveryTokens) {
1160
+ state.recoveryTokens.set(token, data);
1161
+ }
1110
1162
  if (state.classes.size > sizeBefore) {
1111
1163
  writeSafelistFile(state.classes);
1112
1164
  const safelistPath = path.join(state.rootDir, SAFELIST_FILENAME);
@@ -1123,10 +1175,24 @@ ${sourceDirective}`
1123
1175
  */
1124
1176
  handler(html) {
1125
1177
  finalizeMangleMap();
1126
- return transformIndexHtml(html, state.mangleMap, state.checksum, {
1178
+ let result = transformIndexHtml(html, state.mangleMap, state.checksum, {
1127
1179
  mode: options.production?.injectChecksum === false ? "script" : "script",
1128
1180
  minify: process.env.NODE_ENV === "production"
1129
1181
  });
1182
+ if (state.recoveryTokens.size > 0) {
1183
+ const isProduction = process.env.NODE_ENV === "production";
1184
+ const { manifest, strippedDevOnlyPaths } = buildRecoveryManifest(
1185
+ state.recoveryTokens,
1186
+ { production: isProduction }
1187
+ );
1188
+ if (strippedDevOnlyPaths.length > 0) {
1189
+ console.warn(
1190
+ `[csszyx] Stripped ${strippedDevOnlyPaths.length} szRecover="dev-only" token(s) from the production manifest. Recovery for these elements is disabled in production by design. Sites: ${strippedDevOnlyPaths.join(", ")}`
1191
+ );
1192
+ }
1193
+ result = injectRecoveryManifest(result, manifest);
1194
+ }
1195
+ return result;
1130
1196
  }
1131
1197
  }
1132
1198
  }
package/dist/vite.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  vitePlugin
3
- } from "./chunk-CW4XYEQR.js";
3
+ } from "./chunk-JGJOUK2R.js";
4
4
  import "./chunk-4M7CPGP7.js";
5
5
 
6
6
  // src/vite.ts
package/dist/webpack.cjs CHANGED
@@ -140,6 +140,7 @@ function mangleCSSSync(css, mangleMap, options = {}) {
140
140
  }
141
141
 
142
142
  // src/html-transformer.ts
143
+ var import_node_crypto = require("crypto");
143
144
  function injectChecksum(html, checksum, minify = false) {
144
145
  const attrName = minify ? "data-sz-cs" : "data-sz-checksum";
145
146
  const htmlTagPattern = /<html([^>]*)>/i;
@@ -199,6 +200,46 @@ function injectHydrationData(html, mangleMap, checksum, options = {}) {
199
200
  function transformIndexHtml(html, mangleMap, checksum, options = {}) {
200
201
  return injectHydrationData(html, mangleMap, checksum, options);
201
202
  }
203
+ function buildRecoveryManifest(tokens, options = {}) {
204
+ const stripped = options.production === true;
205
+ const strippedDevOnlyPaths = [];
206
+ const sorted = {};
207
+ const sortedKeys = [...tokens.keys()].sort();
208
+ for (const key of sortedKeys) {
209
+ const data = tokens.get(key);
210
+ if (!data) {
211
+ continue;
212
+ }
213
+ if (stripped && data.mode === "dev-only") {
214
+ strippedDevOnlyPaths.push(data.path);
215
+ continue;
216
+ }
217
+ sorted[key] = stripped ? { mode: data.mode, component: data.component, path: "" } : data;
218
+ }
219
+ const serialised = JSON.stringify(sorted);
220
+ const fullChecksum = (0, import_node_crypto.createHash)("sha256").update(serialised).digest("hex");
221
+ const checksum = fullChecksum.substring(0, 16);
222
+ const buildId = `${Date.now().toString(36)}-${fullChecksum.substring(0, 6)}`;
223
+ return {
224
+ manifest: { buildId, checksum, tokens: sorted },
225
+ strippedDevOnlyPaths
226
+ };
227
+ }
228
+ function injectRecoveryManifest(html, manifest) {
229
+ if (Object.keys(manifest.tokens).length === 0) {
230
+ return html;
231
+ }
232
+ const json = JSON.stringify(manifest);
233
+ const scriptTag = `<script id="__SZ_RECOVERY_MANIFEST__" type="application/json">${json}</script>`;
234
+ if (html.includes("</head>")) {
235
+ return html.replace("</head>", `${scriptTag}
236
+ </head>`);
237
+ } else if (html.includes("</html>")) {
238
+ return html.replace("</html>", `${scriptTag}
239
+ </html>`);
240
+ }
241
+ return html + scriptTag;
242
+ }
202
243
 
203
244
  // src/theme-scanner.ts
204
245
  var EMPTY_THEME = { colors: [], spacings: [], fonts: [], radii: [], shadows: [] };
@@ -662,12 +703,14 @@ function mangleCodeClassesSync(code, mangleMap) {
662
703
  }
663
704
  function createCsszyxPlugins(options = {}) {
664
705
  const manglingEnabled = options.production?.mangle !== false;
706
+ const astBudgetOverride = options.build?.astBudgetLimit;
665
707
  const state = {
666
708
  classes: /* @__PURE__ */ new Set(),
667
709
  mangleMap: {},
668
710
  checksum: "",
669
711
  finalized: false,
670
- rootDir: process.cwd()
712
+ rootDir: process.cwd(),
713
+ recoveryTokens: /* @__PURE__ */ new Map()
671
714
  };
672
715
  const SAFELIST_FILENAME = "csszyx-classes.html";
673
716
  const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx", ".ts", ".js"]);
@@ -712,7 +755,7 @@ function createCsszyxPlugins(options = {}) {
712
755
  if (!content.includes("sz=") && !content.includes("sz:")) {
713
756
  continue;
714
757
  }
715
- const result = (0, import_compiler.transformSourceCode)(content);
758
+ const result = (0, import_compiler.transformSourceCode)(content, filePath, { astBudget: astBudgetOverride });
716
759
  if (!result.transformed) {
717
760
  continue;
718
761
  }
@@ -722,6 +765,9 @@ function createCsszyxPlugins(options = {}) {
722
765
  for (const cls of result.rawClassNames) {
723
766
  rawDiscoveredClasses.add(cls);
724
767
  }
768
+ for (const [token, data] of result.recoveryTokens) {
769
+ state.recoveryTokens.set(token, data);
770
+ }
725
771
  if (result.usesRuntime) {
726
772
  const szCallRe = /_sz\(\s*\{/g;
727
773
  let szMatch;
@@ -943,7 +989,7 @@ ${sourceDirective}`
943
989
  transformed = true;
944
990
  }
945
991
  } else {
946
- const result = (0, import_compiler.transformSourceCode)(code);
992
+ const result = (0, import_compiler.transformSourceCode)(code, id, { astBudget: astBudgetOverride });
947
993
  transformedCode = result.code;
948
994
  usesRuntime = result.usesRuntime;
949
995
  usesMerge = result.usesMerge;
@@ -956,6 +1002,9 @@ ${sourceDirective}`
956
1002
  ${msg}`);
957
1003
  }
958
1004
  }
1005
+ for (const [token, data] of result.recoveryTokens) {
1006
+ state.recoveryTokens.set(token, data);
1007
+ }
959
1008
  }
960
1009
  }
961
1010
  if (transformedCode.includes("<html") && /layout|Root|Document|app\\.tsx?$/i.test(id)) {
@@ -1096,7 +1145,7 @@ ${sourceDirective}`
1096
1145
  return;
1097
1146
  }
1098
1147
  try {
1099
- result = (0, import_compiler.transformSourceCode)(fileContent);
1148
+ result = (0, import_compiler.transformSourceCode)(fileContent, ctx.file, { astBudget: astBudgetOverride });
1100
1149
  } catch {
1101
1150
  return;
1102
1151
  }
@@ -1107,6 +1156,9 @@ ${sourceDirective}`
1107
1156
  for (const cls of result.classes) {
1108
1157
  state.classes.add(cls);
1109
1158
  }
1159
+ for (const [token, data] of result.recoveryTokens) {
1160
+ state.recoveryTokens.set(token, data);
1161
+ }
1110
1162
  if (state.classes.size > sizeBefore) {
1111
1163
  writeSafelistFile(state.classes);
1112
1164
  const safelistPath = path.join(state.rootDir, SAFELIST_FILENAME);
@@ -1123,10 +1175,24 @@ ${sourceDirective}`
1123
1175
  */
1124
1176
  handler(html) {
1125
1177
  finalizeMangleMap();
1126
- return transformIndexHtml(html, state.mangleMap, state.checksum, {
1178
+ let result = transformIndexHtml(html, state.mangleMap, state.checksum, {
1127
1179
  mode: options.production?.injectChecksum === false ? "script" : "script",
1128
1180
  minify: process.env.NODE_ENV === "production"
1129
1181
  });
1182
+ if (state.recoveryTokens.size > 0) {
1183
+ const isProduction = process.env.NODE_ENV === "production";
1184
+ const { manifest, strippedDevOnlyPaths } = buildRecoveryManifest(
1185
+ state.recoveryTokens,
1186
+ { production: isProduction }
1187
+ );
1188
+ if (strippedDevOnlyPaths.length > 0) {
1189
+ console.warn(
1190
+ `[csszyx] Stripped ${strippedDevOnlyPaths.length} szRecover="dev-only" token(s) from the production manifest. Recovery for these elements is disabled in production by design. Sites: ${strippedDevOnlyPaths.join(", ")}`
1191
+ );
1192
+ }
1193
+ result = injectRecoveryManifest(result, manifest);
1194
+ }
1195
+ return result;
1130
1196
  }
1131
1197
  }
1132
1198
  }
package/dist/webpack.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  webpackPlugin
3
- } from "./chunk-CW4XYEQR.js";
3
+ } from "./chunk-JGJOUK2R.js";
4
4
  import "./chunk-4M7CPGP7.js";
5
5
 
6
6
  // src/webpack.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@csszyx/unplugin",
3
- "version": "0.5.0",
3
+ "version": "0.6.2",
4
4
  "description": "Vite and Webpack integration for csszyx",
5
5
  "keywords": [
6
6
  "csszyx",
@@ -55,11 +55,11 @@
55
55
  "postcss": "^8.4.35",
56
56
  "postcss-selector-parser": "^6.0.15",
57
57
  "unplugin": "^1.10.1",
58
- "@csszyx/compiler": "0.5.0",
59
- "@csszyx/core": "0.5.0",
60
- "@csszyx/svelte-adapter": "0.5.0",
61
- "@csszyx/types": "0.5.0",
62
- "@csszyx/vue-adapter": "0.5.0"
58
+ "@csszyx/core": "0.6.2",
59
+ "@csszyx/compiler": "0.6.2",
60
+ "@csszyx/svelte-adapter": "0.6.2",
61
+ "@csszyx/types": "0.6.2",
62
+ "@csszyx/vue-adapter": "0.6.2"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@types/node": "^20.11.0",