@csszyx/runtime 0.9.9 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -22
- package/dist/index.cjs +518 -52
- package/dist/index.d.cts +186 -75
- package/dist/index.d.mts +186 -75
- package/dist/index.mjs +511 -52
- package/dist/lite.cjs +0 -4
- package/dist/lite.d.cts +1 -15
- package/dist/lite.d.mts +1 -15
- package/dist/lite.mjs +1 -4
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -43,53 +43,6 @@ type SzInput = string | SzObject | SzInput[] | null | undefined | false;
|
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
45
|
declare function _sz(...classes: SzInput[]): string;
|
|
46
|
-
/**
|
|
47
|
-
* Conditionally applies className based on a condition.
|
|
48
|
-
*
|
|
49
|
-
* Supports both pre-compiled strings and SzObjects for dynamic styling.
|
|
50
|
-
* This is the recommended helper for conditional class application.
|
|
51
|
-
*
|
|
52
|
-
* @param {boolean} condition - Whether to apply the truthy value
|
|
53
|
-
* @param {SzInput} truthyValue - ClassName or SzObject when condition is true
|
|
54
|
-
* @param {SzInput} falsyValue - ClassName or SzObject when condition is false
|
|
55
|
-
* @returns {string} The resolved className string
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```typescript
|
|
59
|
-
* // With strings (pre-compiled)
|
|
60
|
-
* _szIf(isActive, 'bg-green-500', 'bg-gray-500')
|
|
61
|
-
* // Returns: "bg-green-500" if isActive, "bg-gray-500" otherwise
|
|
62
|
-
*
|
|
63
|
-
* // With SzObjects (runtime transform)
|
|
64
|
-
* _szIf(isActive, { bg: 'green-500' }, { bg: 'gray-500' })
|
|
65
|
-
* // Returns: "bg-green-500" if isActive, "bg-gray-500" otherwise
|
|
66
|
-
*
|
|
67
|
-
* // Without fallback
|
|
68
|
-
* _szIf(isActive, { bg: 'green-500' })
|
|
69
|
-
* // Returns: "bg-green-500" if isActive, "" otherwise
|
|
70
|
-
* ```
|
|
71
|
-
*/
|
|
72
|
-
declare function _szIf(condition: boolean, truthyValue: SzInput, falsyValue?: SzInput): string;
|
|
73
|
-
/**
|
|
74
|
-
* Applies className based on multiple conditions (switch-like).
|
|
75
|
-
*
|
|
76
|
-
* Returns the className for the first truthy condition, or the default.
|
|
77
|
-
* Supports both strings and SzObjects.
|
|
78
|
-
*
|
|
79
|
-
* @param {Array<[boolean, SzInput]>} conditions - Array of [condition, value] tuples
|
|
80
|
-
* @param {SzInput} defaultValue - Default value if no conditions match
|
|
81
|
-
* @returns {string} The matched className or default
|
|
82
|
-
*
|
|
83
|
-
* @example
|
|
84
|
-
* ```typescript
|
|
85
|
-
* _szSwitch([
|
|
86
|
-
* [status === 'success', { text: 'green-500' }],
|
|
87
|
-
* [status === 'error', { text: 'red-500' }],
|
|
88
|
-
* [status === 'warning', { text: 'yellow-500' }]
|
|
89
|
-
* ], { text: 'gray-500' })
|
|
90
|
-
* ```
|
|
91
|
-
*/
|
|
92
|
-
declare function _szSwitch(conditions: Array<[boolean, SzInput]>, defaultValue?: SzInput): string;
|
|
93
46
|
/**
|
|
94
47
|
* Merges className strings, removing duplicates.
|
|
95
48
|
*
|
|
@@ -349,19 +302,19 @@ declare function disableCSRRecovery(): void;
|
|
|
349
302
|
*/
|
|
350
303
|
declare function isCSRRecoveryAllowed(): boolean;
|
|
351
304
|
/**
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
*
|
|
305
|
+
* Validate a parsed mangle map before it is used to rewrite class names. The map
|
|
306
|
+
* is read from the DOM (attacker-writable if the served HTML is compromised), so
|
|
307
|
+
* it must be a plain object of string→string with no prototype-polluting keys.
|
|
308
|
+
* A malformed map is rejected rather than applied.
|
|
355
309
|
*
|
|
356
|
-
* @
|
|
310
|
+
* @param value - the `JSON.parse`d candidate.
|
|
311
|
+
* @returns true when `value` is a safe `MangleMap`.
|
|
312
|
+
*/
|
|
313
|
+
declare function isValidMangleMap(value: unknown): value is MangleMap;
|
|
314
|
+
/**
|
|
315
|
+
* Load and validate the mangle map embedded in the DOM by the SSR pipeline.
|
|
357
316
|
*
|
|
358
|
-
* @
|
|
359
|
-
* ```typescript
|
|
360
|
-
* const mangleMap = loadMangleMapFromDOM();
|
|
361
|
-
* if (mangleMap) {
|
|
362
|
-
* console.log('Mangle map loaded');
|
|
363
|
-
* }
|
|
364
|
-
* ```
|
|
317
|
+
* @returns the validated mangle map, or `null` if absent or invalid.
|
|
365
318
|
*/
|
|
366
319
|
declare function loadMangleMapFromDOM(): MangleMap | null;
|
|
367
320
|
/**
|
|
@@ -382,20 +335,53 @@ declare function loadMangleMapFromDOM(): MangleMap | null;
|
|
|
382
335
|
*/
|
|
383
336
|
declare function verifyMangleChecksum(expectedChecksum: string): boolean;
|
|
384
337
|
/**
|
|
385
|
-
*
|
|
338
|
+
* Recompute a mangle map's checksum the same way the Rust core does
|
|
339
|
+
* (`compute_checksum_internal`): SHA-256 over the entries sorted by key and
|
|
340
|
+
* formatted `orig:mangle`, joined by `|`, hex-encoded, first 16 chars (64 bits).
|
|
386
341
|
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
342
|
+
* Uses the Web Crypto API (`crypto.subtle`), so it works WITHOUT the WASM core —
|
|
343
|
+
* unlike the WASM-only sync path. Async because `crypto.subtle.digest` is async.
|
|
389
344
|
*
|
|
390
|
-
* @
|
|
345
|
+
* @param map - the mangle map to checksum.
|
|
346
|
+
* @returns the 16-char hex checksum (matches the Rust output byte-for-byte for
|
|
347
|
+
* ASCII class names).
|
|
348
|
+
*/
|
|
349
|
+
declare function computeMangleChecksumAsync(map: MangleMap): Promise<string>;
|
|
350
|
+
/**
|
|
351
|
+
* Verify a mangle map's integrity by RECOMPUTING its checksum (via Web Crypto)
|
|
352
|
+
* and comparing it to the expected value — real verification that works without
|
|
353
|
+
* the WASM core. Unlike the sync {@link verifyMangleChecksum} (a plain attribute
|
|
354
|
+
* compare), this recomputes from the map, so it detects a map that was altered
|
|
355
|
+
* without updating the checksum.
|
|
391
356
|
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
357
|
+
* Still tamper-DETECTION, not authentication: the checksum is unsigned, so an
|
|
358
|
+
* attacker who can rewrite the served HTML can recompute it after editing the
|
|
359
|
+
* map. Use it to catch corruption / accidental drift, not as a trust boundary.
|
|
360
|
+
*
|
|
361
|
+
* @param expectedChecksum - the checksum to match (e.g. from the manifest or the
|
|
362
|
+
* `data-sz-checksum` attribute).
|
|
363
|
+
* @param map - the mangle map; loaded (and schema-validated) from the DOM when omitted.
|
|
364
|
+
* @returns a promise resolving true when the map is present and its recomputed
|
|
365
|
+
* checksum matches.
|
|
366
|
+
*/
|
|
367
|
+
declare function verifyMangleChecksumAsync(expectedChecksum: string, map?: MangleMap): Promise<boolean>;
|
|
368
|
+
/**
|
|
369
|
+
* Verifies mangle map integrity using the Rust core checksum verifier.
|
|
370
|
+
*
|
|
371
|
+
* Loads the mangle map from the DOM, validates its shape, and (when the WASM
|
|
372
|
+
* core is present) verifies its checksum via `verify_mangle_checksum()`.
|
|
373
|
+
*
|
|
374
|
+
* IMPORTANT — this is tamper-DETECTION, not authentication. The checksum is an
|
|
375
|
+
* unsigned SHA-256 truncation: it catches accidental server/client drift, but an
|
|
376
|
+
* attacker who can rewrite the served HTML can recompute it after editing the
|
|
377
|
+
* map. Treat it as an integrity (corruption) check, not a trust boundary.
|
|
378
|
+
*
|
|
379
|
+
* When the WASM verifier is absent (the common no-core deployment), the checksum
|
|
380
|
+
* cannot be recomputed in this sync path, so verification degrades to a
|
|
381
|
+
* schema-validated load and emits a dev warning rather than failing closed
|
|
382
|
+
* (failing closed here would break every app not shipping the WASM core).
|
|
383
|
+
*
|
|
384
|
+
* @returns {boolean} True if the map is well-formed and (if verifiable) matches.
|
|
399
385
|
*/
|
|
400
386
|
declare function verifyMangleMapIntegrity(): boolean;
|
|
401
387
|
/**
|
|
@@ -612,6 +598,133 @@ declare function startHydration(): void;
|
|
|
612
598
|
*/
|
|
613
599
|
declare function endHydration(): void;
|
|
614
600
|
|
|
601
|
+
/** Which side of the CSS box-model border a property acts on. */
|
|
602
|
+
type BoxRole = 'outer' | 'inner';
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Route a (csszyx-emitted) className string to nested elements by CSS box-model
|
|
606
|
+
* role, plus a category-aware toolkit that exposes csszyx's class knowledge as
|
|
607
|
+
* primitives. Pure string functions — framework-agnostic, cross-platform, no
|
|
608
|
+
* React, no DOM. The class-token → box-role map is GENERATED from the compiler's
|
|
609
|
+
* property tables (see `box-role-map.generated.ts`), so it never drifts.
|
|
610
|
+
*
|
|
611
|
+
* The problem this solves: a caller passes one flat `className` (e.g. from an sz
|
|
612
|
+
* prop) to a component, but the component renders nested elements — the margin
|
|
613
|
+
* belongs on the outer frame while the padding belongs on the inner content. A
|
|
614
|
+
* slot recipe can't re-route a caller's flat string; only a runtime partition
|
|
615
|
+
* can. `splitBox` does that partition at the border line (outer = border-outward,
|
|
616
|
+
* inner = border-inward); the toolkit lets a project express cross-element
|
|
617
|
+
* dependency rules (e.g. "if the frame clips, make the scroller scroll") without
|
|
618
|
+
* hardcoding csszyx's class vocabulary.
|
|
619
|
+
*/
|
|
620
|
+
|
|
621
|
+
/** The classification of a single class token. */
|
|
622
|
+
interface Classification {
|
|
623
|
+
/** Which side of the border the property acts on. */
|
|
624
|
+
readonly role: BoxRole;
|
|
625
|
+
/** Semantic group (margin, padding, border, overflow, text, …). */
|
|
626
|
+
readonly category: string;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* A way to address a set of classes. One of:
|
|
630
|
+
* - a box-role: `'outer'` | `'inner'`
|
|
631
|
+
* - a box-layer alias: `'content'` (= inner) (`'margin'`/`'border'`/`'padding'`
|
|
632
|
+
* are also categories, so they work directly)
|
|
633
|
+
* - a category: `'overflow'`, `'text'`, `'bg'`, …
|
|
634
|
+
* - a class-prefix: `'px'`, `'bg'`, … (matches `px-2`, `bg-red-500`, …)
|
|
635
|
+
* - a category+value pair: `{ overflow: 'hidden' }`
|
|
636
|
+
*/
|
|
637
|
+
type BoxSelector = string | Readonly<Record<string, string>>;
|
|
638
|
+
/** Options controlling how `splitBox` partitions a className. */
|
|
639
|
+
interface SplitBoxOptions {
|
|
640
|
+
/** Force these selectors onto the outer node, overriding the default map. */
|
|
641
|
+
outer?: BoxSelector[];
|
|
642
|
+
/** Force these selectors onto the inner node, overriding the default map. */
|
|
643
|
+
inner?: BoxSelector[];
|
|
644
|
+
/** Where an unrecognized token goes. Defaults to `'outer'`. */
|
|
645
|
+
fallback?: BoxRole;
|
|
646
|
+
}
|
|
647
|
+
/** The two class buckets produced by `splitBox`. */
|
|
648
|
+
interface SplitBoxResult {
|
|
649
|
+
/** Classes for the outer (border-outward) element. */
|
|
650
|
+
outer: string;
|
|
651
|
+
/** Classes for the inner (border-inward) element. */
|
|
652
|
+
inner: string;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Classify a class token by box-model role + semantic category, or `undefined`
|
|
656
|
+
* if it is not a csszyx-owned utility. Variant-, important- and negative-aware.
|
|
657
|
+
*
|
|
658
|
+
* @param token - A single class token to classify.
|
|
659
|
+
* @returns The token's role and category, or `undefined` if unowned.
|
|
660
|
+
*/
|
|
661
|
+
declare function classify(token: string): Classification | undefined;
|
|
662
|
+
/**
|
|
663
|
+
* Partition a className string into `{ outer, inner }` at the CSS box-model
|
|
664
|
+
* border line. Every token lands in exactly one bucket (no loss, no duplication)
|
|
665
|
+
* and keeps its variant prefix. Overrides in `options.inner` / `options.outer`
|
|
666
|
+
* win over the default map; `inner` is checked first when a token matches both.
|
|
667
|
+
*
|
|
668
|
+
* @param className - The flat className string to partition.
|
|
669
|
+
* @param options - Overrides for forcing tokens onto a node and the fallback role.
|
|
670
|
+
* @returns The `{ outer, inner }` class buckets.
|
|
671
|
+
* @example splitBox('m-4 px-2 md:flex') // → { outer: 'm-4', inner: 'px-2 md:flex' }
|
|
672
|
+
*/
|
|
673
|
+
declare function splitBox(className: string, options?: SplitBoxOptions): SplitBoxResult;
|
|
674
|
+
/**
|
|
675
|
+
* Does any token in `classes` match `selector`? Variant- and mangle-robust.
|
|
676
|
+
*
|
|
677
|
+
* @param classes - A className string to scan.
|
|
678
|
+
* @param selector - The selector to test tokens against.
|
|
679
|
+
* @returns `true` if any token matches the selector.
|
|
680
|
+
*/
|
|
681
|
+
declare function has(classes: string, selector: BoxSelector): boolean;
|
|
682
|
+
/**
|
|
683
|
+
* Keep only the tokens in `classes` that match `selector`.
|
|
684
|
+
*
|
|
685
|
+
* @param classes - A className string to filter.
|
|
686
|
+
* @param selector - The selector tokens must match to be kept.
|
|
687
|
+
* @returns The matching tokens joined by spaces.
|
|
688
|
+
*/
|
|
689
|
+
declare function pick(classes: string, selector: BoxSelector): string;
|
|
690
|
+
/**
|
|
691
|
+
* Drop the tokens in `classes` that match `selector`, keeping the rest.
|
|
692
|
+
*
|
|
693
|
+
* @param classes - A className string to filter.
|
|
694
|
+
* @param selector - The selector tokens must match to be dropped.
|
|
695
|
+
* @returns The non-matching tokens joined by spaces.
|
|
696
|
+
*/
|
|
697
|
+
declare function omit(classes: string, selector: BoxSelector): string;
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Drop the `sz` prop before a component spreads `...rest` onto a host element.
|
|
701
|
+
*
|
|
702
|
+
* The compiler rewrites `sz` to `className` at build time, so a compiled
|
|
703
|
+
* component never carries a leftover `sz` prop. But when a file is NOT compiled
|
|
704
|
+
* — e.g. a workspace package missing from `compilePackages`, or any source the
|
|
705
|
+
* bundler skipped — a hand-forwarded `sz` survives and React spreads it to the
|
|
706
|
+
* DOM as `sz="[object Object]"`. `stripSzProps` removes `sz` from the forwarded
|
|
707
|
+
* props so it never reaches the DOM, and in development warns once when the
|
|
708
|
+
* leaked `sz` is a raw object, pointing at the real cause (an uncompiled file).
|
|
709
|
+
*
|
|
710
|
+
* Pure, framework-agnostic, no React/DOM import.
|
|
711
|
+
*
|
|
712
|
+
* @example
|
|
713
|
+
* function Box({ sz, ...rest }: BoxProps) {
|
|
714
|
+
* return <div {...stripSzProps(rest)} />; // rest may still carry sz when uncompiled
|
|
715
|
+
* }
|
|
716
|
+
*/
|
|
717
|
+
/**
|
|
718
|
+
* Return `props` without its `sz` key. When `sz` is absent the original object
|
|
719
|
+
* is returned unchanged (no allocation); otherwise a shallow copy without `sz`
|
|
720
|
+
* is returned. In development, a raw-object `sz` (the uncompiled-leak signature)
|
|
721
|
+
* triggers a one-time warning.
|
|
722
|
+
*
|
|
723
|
+
* @param props - the props a component is about to forward to a host element.
|
|
724
|
+
* @returns the same props without `sz`.
|
|
725
|
+
*/
|
|
726
|
+
declare function stripSzProps<T extends Record<string, unknown>>(props: T): Omit<T, 'sz'>;
|
|
727
|
+
|
|
615
728
|
/**
|
|
616
729
|
* szv() — variant-based sz object factory.
|
|
617
730
|
*
|
|
@@ -632,9 +745,7 @@ type VariantSchema = Record<string, Record<string, SzObject>>;
|
|
|
632
745
|
type VariantSelection<V extends VariantSchema> = {
|
|
633
746
|
[K in keyof V]?: keyof V[K] | null | undefined;
|
|
634
747
|
};
|
|
635
|
-
/**
|
|
636
|
-
*
|
|
637
|
-
*/
|
|
748
|
+
/** Configuration for a variant component: base styles, variants, and defaults. */
|
|
638
749
|
interface SzvConfig<V extends VariantSchema> {
|
|
639
750
|
base?: SzObject;
|
|
640
751
|
variants: V;
|
|
@@ -655,7 +766,7 @@ interface SzvConfig<V extends VariantSchema> {
|
|
|
655
766
|
* import { szv } from 'csszyx';
|
|
656
767
|
*
|
|
657
768
|
* const buttonSz = szv({
|
|
658
|
-
* base: {
|
|
769
|
+
* base: { display: 'inline-flex', items: 'center', rounded: 'md', weight: 'medium' },
|
|
659
770
|
* variants: {
|
|
660
771
|
* variant: {
|
|
661
772
|
* default: { bg: 'primary', text: 'primary-foreground' },
|
|
@@ -769,5 +880,5 @@ declare function isRuntimeInitialized(): boolean;
|
|
|
769
880
|
*/
|
|
770
881
|
declare function resetRuntime(): void;
|
|
771
882
|
|
|
772
|
-
export { DEFAULT_RUNTIME_CONFIG, VERSION, _sz, _sz2, _sz3,
|
|
773
|
-
export type { HydrationError, HydrationErrorType, MangleMap, RecoveryManifest, RecoveryMode, RuntimeConfig, SSRContext, SzInput, TokenData, VerificationResult };
|
|
883
|
+
export { DEFAULT_RUNTIME_CONFIG, VERSION, _sz, _sz2, _sz3, _szMerge, abortHydration, attemptCSRRecovery, classify, clearHydrationErrors, computeMangleChecksumAsync, disableCSRRecovery, enableCSRRecovery, endHydration, getAbortedSubtreeCount, getHydrationErrors, getRecoveryMode, getRuntimeConfig, getSSRContext, guardHydration, has, hasRecoveryToken, initRuntime, isCSRRecoveryAllowed, isHydrating, isHydrationAborted, isRuntimeInitialized, isSSREnvironment, isValidMangleMap, isValidManifest, loadMangleMapFromDOM, loadManifestFromDOM, omit, pick, resetRuntime, splitBox, startHydration, stripSzProps, szv, validateHydrationClass, verifyAllTokens, verifyMangleChecksum, verifyMangleChecksumAsync, verifyMangleMapIntegrity, verifyRecoveryToken };
|
|
884
|
+
export type { BoxRole, BoxSelector, Classification, HydrationError, HydrationErrorType, MangleMap, RecoveryManifest, RecoveryMode, RuntimeConfig, SSRContext, SplitBoxOptions, SplitBoxResult, SzInput, TokenData, VerificationResult };
|
package/dist/index.d.mts
CHANGED
|
@@ -43,53 +43,6 @@ type SzInput = string | SzObject | SzInput[] | null | undefined | false;
|
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
45
|
declare function _sz(...classes: SzInput[]): string;
|
|
46
|
-
/**
|
|
47
|
-
* Conditionally applies className based on a condition.
|
|
48
|
-
*
|
|
49
|
-
* Supports both pre-compiled strings and SzObjects for dynamic styling.
|
|
50
|
-
* This is the recommended helper for conditional class application.
|
|
51
|
-
*
|
|
52
|
-
* @param {boolean} condition - Whether to apply the truthy value
|
|
53
|
-
* @param {SzInput} truthyValue - ClassName or SzObject when condition is true
|
|
54
|
-
* @param {SzInput} falsyValue - ClassName or SzObject when condition is false
|
|
55
|
-
* @returns {string} The resolved className string
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```typescript
|
|
59
|
-
* // With strings (pre-compiled)
|
|
60
|
-
* _szIf(isActive, 'bg-green-500', 'bg-gray-500')
|
|
61
|
-
* // Returns: "bg-green-500" if isActive, "bg-gray-500" otherwise
|
|
62
|
-
*
|
|
63
|
-
* // With SzObjects (runtime transform)
|
|
64
|
-
* _szIf(isActive, { bg: 'green-500' }, { bg: 'gray-500' })
|
|
65
|
-
* // Returns: "bg-green-500" if isActive, "bg-gray-500" otherwise
|
|
66
|
-
*
|
|
67
|
-
* // Without fallback
|
|
68
|
-
* _szIf(isActive, { bg: 'green-500' })
|
|
69
|
-
* // Returns: "bg-green-500" if isActive, "" otherwise
|
|
70
|
-
* ```
|
|
71
|
-
*/
|
|
72
|
-
declare function _szIf(condition: boolean, truthyValue: SzInput, falsyValue?: SzInput): string;
|
|
73
|
-
/**
|
|
74
|
-
* Applies className based on multiple conditions (switch-like).
|
|
75
|
-
*
|
|
76
|
-
* Returns the className for the first truthy condition, or the default.
|
|
77
|
-
* Supports both strings and SzObjects.
|
|
78
|
-
*
|
|
79
|
-
* @param {Array<[boolean, SzInput]>} conditions - Array of [condition, value] tuples
|
|
80
|
-
* @param {SzInput} defaultValue - Default value if no conditions match
|
|
81
|
-
* @returns {string} The matched className or default
|
|
82
|
-
*
|
|
83
|
-
* @example
|
|
84
|
-
* ```typescript
|
|
85
|
-
* _szSwitch([
|
|
86
|
-
* [status === 'success', { text: 'green-500' }],
|
|
87
|
-
* [status === 'error', { text: 'red-500' }],
|
|
88
|
-
* [status === 'warning', { text: 'yellow-500' }]
|
|
89
|
-
* ], { text: 'gray-500' })
|
|
90
|
-
* ```
|
|
91
|
-
*/
|
|
92
|
-
declare function _szSwitch(conditions: Array<[boolean, SzInput]>, defaultValue?: SzInput): string;
|
|
93
46
|
/**
|
|
94
47
|
* Merges className strings, removing duplicates.
|
|
95
48
|
*
|
|
@@ -349,19 +302,19 @@ declare function disableCSRRecovery(): void;
|
|
|
349
302
|
*/
|
|
350
303
|
declare function isCSRRecoveryAllowed(): boolean;
|
|
351
304
|
/**
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
*
|
|
305
|
+
* Validate a parsed mangle map before it is used to rewrite class names. The map
|
|
306
|
+
* is read from the DOM (attacker-writable if the served HTML is compromised), so
|
|
307
|
+
* it must be a plain object of string→string with no prototype-polluting keys.
|
|
308
|
+
* A malformed map is rejected rather than applied.
|
|
355
309
|
*
|
|
356
|
-
* @
|
|
310
|
+
* @param value - the `JSON.parse`d candidate.
|
|
311
|
+
* @returns true when `value` is a safe `MangleMap`.
|
|
312
|
+
*/
|
|
313
|
+
declare function isValidMangleMap(value: unknown): value is MangleMap;
|
|
314
|
+
/**
|
|
315
|
+
* Load and validate the mangle map embedded in the DOM by the SSR pipeline.
|
|
357
316
|
*
|
|
358
|
-
* @
|
|
359
|
-
* ```typescript
|
|
360
|
-
* const mangleMap = loadMangleMapFromDOM();
|
|
361
|
-
* if (mangleMap) {
|
|
362
|
-
* console.log('Mangle map loaded');
|
|
363
|
-
* }
|
|
364
|
-
* ```
|
|
317
|
+
* @returns the validated mangle map, or `null` if absent or invalid.
|
|
365
318
|
*/
|
|
366
319
|
declare function loadMangleMapFromDOM(): MangleMap | null;
|
|
367
320
|
/**
|
|
@@ -382,20 +335,53 @@ declare function loadMangleMapFromDOM(): MangleMap | null;
|
|
|
382
335
|
*/
|
|
383
336
|
declare function verifyMangleChecksum(expectedChecksum: string): boolean;
|
|
384
337
|
/**
|
|
385
|
-
*
|
|
338
|
+
* Recompute a mangle map's checksum the same way the Rust core does
|
|
339
|
+
* (`compute_checksum_internal`): SHA-256 over the entries sorted by key and
|
|
340
|
+
* formatted `orig:mangle`, joined by `|`, hex-encoded, first 16 chars (64 bits).
|
|
386
341
|
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
342
|
+
* Uses the Web Crypto API (`crypto.subtle`), so it works WITHOUT the WASM core —
|
|
343
|
+
* unlike the WASM-only sync path. Async because `crypto.subtle.digest` is async.
|
|
389
344
|
*
|
|
390
|
-
* @
|
|
345
|
+
* @param map - the mangle map to checksum.
|
|
346
|
+
* @returns the 16-char hex checksum (matches the Rust output byte-for-byte for
|
|
347
|
+
* ASCII class names).
|
|
348
|
+
*/
|
|
349
|
+
declare function computeMangleChecksumAsync(map: MangleMap): Promise<string>;
|
|
350
|
+
/**
|
|
351
|
+
* Verify a mangle map's integrity by RECOMPUTING its checksum (via Web Crypto)
|
|
352
|
+
* and comparing it to the expected value — real verification that works without
|
|
353
|
+
* the WASM core. Unlike the sync {@link verifyMangleChecksum} (a plain attribute
|
|
354
|
+
* compare), this recomputes from the map, so it detects a map that was altered
|
|
355
|
+
* without updating the checksum.
|
|
391
356
|
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
357
|
+
* Still tamper-DETECTION, not authentication: the checksum is unsigned, so an
|
|
358
|
+
* attacker who can rewrite the served HTML can recompute it after editing the
|
|
359
|
+
* map. Use it to catch corruption / accidental drift, not as a trust boundary.
|
|
360
|
+
*
|
|
361
|
+
* @param expectedChecksum - the checksum to match (e.g. from the manifest or the
|
|
362
|
+
* `data-sz-checksum` attribute).
|
|
363
|
+
* @param map - the mangle map; loaded (and schema-validated) from the DOM when omitted.
|
|
364
|
+
* @returns a promise resolving true when the map is present and its recomputed
|
|
365
|
+
* checksum matches.
|
|
366
|
+
*/
|
|
367
|
+
declare function verifyMangleChecksumAsync(expectedChecksum: string, map?: MangleMap): Promise<boolean>;
|
|
368
|
+
/**
|
|
369
|
+
* Verifies mangle map integrity using the Rust core checksum verifier.
|
|
370
|
+
*
|
|
371
|
+
* Loads the mangle map from the DOM, validates its shape, and (when the WASM
|
|
372
|
+
* core is present) verifies its checksum via `verify_mangle_checksum()`.
|
|
373
|
+
*
|
|
374
|
+
* IMPORTANT — this is tamper-DETECTION, not authentication. The checksum is an
|
|
375
|
+
* unsigned SHA-256 truncation: it catches accidental server/client drift, but an
|
|
376
|
+
* attacker who can rewrite the served HTML can recompute it after editing the
|
|
377
|
+
* map. Treat it as an integrity (corruption) check, not a trust boundary.
|
|
378
|
+
*
|
|
379
|
+
* When the WASM verifier is absent (the common no-core deployment), the checksum
|
|
380
|
+
* cannot be recomputed in this sync path, so verification degrades to a
|
|
381
|
+
* schema-validated load and emits a dev warning rather than failing closed
|
|
382
|
+
* (failing closed here would break every app not shipping the WASM core).
|
|
383
|
+
*
|
|
384
|
+
* @returns {boolean} True if the map is well-formed and (if verifiable) matches.
|
|
399
385
|
*/
|
|
400
386
|
declare function verifyMangleMapIntegrity(): boolean;
|
|
401
387
|
/**
|
|
@@ -612,6 +598,133 @@ declare function startHydration(): void;
|
|
|
612
598
|
*/
|
|
613
599
|
declare function endHydration(): void;
|
|
614
600
|
|
|
601
|
+
/** Which side of the CSS box-model border a property acts on. */
|
|
602
|
+
type BoxRole = 'outer' | 'inner';
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Route a (csszyx-emitted) className string to nested elements by CSS box-model
|
|
606
|
+
* role, plus a category-aware toolkit that exposes csszyx's class knowledge as
|
|
607
|
+
* primitives. Pure string functions — framework-agnostic, cross-platform, no
|
|
608
|
+
* React, no DOM. The class-token → box-role map is GENERATED from the compiler's
|
|
609
|
+
* property tables (see `box-role-map.generated.ts`), so it never drifts.
|
|
610
|
+
*
|
|
611
|
+
* The problem this solves: a caller passes one flat `className` (e.g. from an sz
|
|
612
|
+
* prop) to a component, but the component renders nested elements — the margin
|
|
613
|
+
* belongs on the outer frame while the padding belongs on the inner content. A
|
|
614
|
+
* slot recipe can't re-route a caller's flat string; only a runtime partition
|
|
615
|
+
* can. `splitBox` does that partition at the border line (outer = border-outward,
|
|
616
|
+
* inner = border-inward); the toolkit lets a project express cross-element
|
|
617
|
+
* dependency rules (e.g. "if the frame clips, make the scroller scroll") without
|
|
618
|
+
* hardcoding csszyx's class vocabulary.
|
|
619
|
+
*/
|
|
620
|
+
|
|
621
|
+
/** The classification of a single class token. */
|
|
622
|
+
interface Classification {
|
|
623
|
+
/** Which side of the border the property acts on. */
|
|
624
|
+
readonly role: BoxRole;
|
|
625
|
+
/** Semantic group (margin, padding, border, overflow, text, …). */
|
|
626
|
+
readonly category: string;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* A way to address a set of classes. One of:
|
|
630
|
+
* - a box-role: `'outer'` | `'inner'`
|
|
631
|
+
* - a box-layer alias: `'content'` (= inner) (`'margin'`/`'border'`/`'padding'`
|
|
632
|
+
* are also categories, so they work directly)
|
|
633
|
+
* - a category: `'overflow'`, `'text'`, `'bg'`, …
|
|
634
|
+
* - a class-prefix: `'px'`, `'bg'`, … (matches `px-2`, `bg-red-500`, …)
|
|
635
|
+
* - a category+value pair: `{ overflow: 'hidden' }`
|
|
636
|
+
*/
|
|
637
|
+
type BoxSelector = string | Readonly<Record<string, string>>;
|
|
638
|
+
/** Options controlling how `splitBox` partitions a className. */
|
|
639
|
+
interface SplitBoxOptions {
|
|
640
|
+
/** Force these selectors onto the outer node, overriding the default map. */
|
|
641
|
+
outer?: BoxSelector[];
|
|
642
|
+
/** Force these selectors onto the inner node, overriding the default map. */
|
|
643
|
+
inner?: BoxSelector[];
|
|
644
|
+
/** Where an unrecognized token goes. Defaults to `'outer'`. */
|
|
645
|
+
fallback?: BoxRole;
|
|
646
|
+
}
|
|
647
|
+
/** The two class buckets produced by `splitBox`. */
|
|
648
|
+
interface SplitBoxResult {
|
|
649
|
+
/** Classes for the outer (border-outward) element. */
|
|
650
|
+
outer: string;
|
|
651
|
+
/** Classes for the inner (border-inward) element. */
|
|
652
|
+
inner: string;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Classify a class token by box-model role + semantic category, or `undefined`
|
|
656
|
+
* if it is not a csszyx-owned utility. Variant-, important- and negative-aware.
|
|
657
|
+
*
|
|
658
|
+
* @param token - A single class token to classify.
|
|
659
|
+
* @returns The token's role and category, or `undefined` if unowned.
|
|
660
|
+
*/
|
|
661
|
+
declare function classify(token: string): Classification | undefined;
|
|
662
|
+
/**
|
|
663
|
+
* Partition a className string into `{ outer, inner }` at the CSS box-model
|
|
664
|
+
* border line. Every token lands in exactly one bucket (no loss, no duplication)
|
|
665
|
+
* and keeps its variant prefix. Overrides in `options.inner` / `options.outer`
|
|
666
|
+
* win over the default map; `inner` is checked first when a token matches both.
|
|
667
|
+
*
|
|
668
|
+
* @param className - The flat className string to partition.
|
|
669
|
+
* @param options - Overrides for forcing tokens onto a node and the fallback role.
|
|
670
|
+
* @returns The `{ outer, inner }` class buckets.
|
|
671
|
+
* @example splitBox('m-4 px-2 md:flex') // → { outer: 'm-4', inner: 'px-2 md:flex' }
|
|
672
|
+
*/
|
|
673
|
+
declare function splitBox(className: string, options?: SplitBoxOptions): SplitBoxResult;
|
|
674
|
+
/**
|
|
675
|
+
* Does any token in `classes` match `selector`? Variant- and mangle-robust.
|
|
676
|
+
*
|
|
677
|
+
* @param classes - A className string to scan.
|
|
678
|
+
* @param selector - The selector to test tokens against.
|
|
679
|
+
* @returns `true` if any token matches the selector.
|
|
680
|
+
*/
|
|
681
|
+
declare function has(classes: string, selector: BoxSelector): boolean;
|
|
682
|
+
/**
|
|
683
|
+
* Keep only the tokens in `classes` that match `selector`.
|
|
684
|
+
*
|
|
685
|
+
* @param classes - A className string to filter.
|
|
686
|
+
* @param selector - The selector tokens must match to be kept.
|
|
687
|
+
* @returns The matching tokens joined by spaces.
|
|
688
|
+
*/
|
|
689
|
+
declare function pick(classes: string, selector: BoxSelector): string;
|
|
690
|
+
/**
|
|
691
|
+
* Drop the tokens in `classes` that match `selector`, keeping the rest.
|
|
692
|
+
*
|
|
693
|
+
* @param classes - A className string to filter.
|
|
694
|
+
* @param selector - The selector tokens must match to be dropped.
|
|
695
|
+
* @returns The non-matching tokens joined by spaces.
|
|
696
|
+
*/
|
|
697
|
+
declare function omit(classes: string, selector: BoxSelector): string;
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Drop the `sz` prop before a component spreads `...rest` onto a host element.
|
|
701
|
+
*
|
|
702
|
+
* The compiler rewrites `sz` to `className` at build time, so a compiled
|
|
703
|
+
* component never carries a leftover `sz` prop. But when a file is NOT compiled
|
|
704
|
+
* — e.g. a workspace package missing from `compilePackages`, or any source the
|
|
705
|
+
* bundler skipped — a hand-forwarded `sz` survives and React spreads it to the
|
|
706
|
+
* DOM as `sz="[object Object]"`. `stripSzProps` removes `sz` from the forwarded
|
|
707
|
+
* props so it never reaches the DOM, and in development warns once when the
|
|
708
|
+
* leaked `sz` is a raw object, pointing at the real cause (an uncompiled file).
|
|
709
|
+
*
|
|
710
|
+
* Pure, framework-agnostic, no React/DOM import.
|
|
711
|
+
*
|
|
712
|
+
* @example
|
|
713
|
+
* function Box({ sz, ...rest }: BoxProps) {
|
|
714
|
+
* return <div {...stripSzProps(rest)} />; // rest may still carry sz when uncompiled
|
|
715
|
+
* }
|
|
716
|
+
*/
|
|
717
|
+
/**
|
|
718
|
+
* Return `props` without its `sz` key. When `sz` is absent the original object
|
|
719
|
+
* is returned unchanged (no allocation); otherwise a shallow copy without `sz`
|
|
720
|
+
* is returned. In development, a raw-object `sz` (the uncompiled-leak signature)
|
|
721
|
+
* triggers a one-time warning.
|
|
722
|
+
*
|
|
723
|
+
* @param props - the props a component is about to forward to a host element.
|
|
724
|
+
* @returns the same props without `sz`.
|
|
725
|
+
*/
|
|
726
|
+
declare function stripSzProps<T extends Record<string, unknown>>(props: T): Omit<T, 'sz'>;
|
|
727
|
+
|
|
615
728
|
/**
|
|
616
729
|
* szv() — variant-based sz object factory.
|
|
617
730
|
*
|
|
@@ -632,9 +745,7 @@ type VariantSchema = Record<string, Record<string, SzObject>>;
|
|
|
632
745
|
type VariantSelection<V extends VariantSchema> = {
|
|
633
746
|
[K in keyof V]?: keyof V[K] | null | undefined;
|
|
634
747
|
};
|
|
635
|
-
/**
|
|
636
|
-
*
|
|
637
|
-
*/
|
|
748
|
+
/** Configuration for a variant component: base styles, variants, and defaults. */
|
|
638
749
|
interface SzvConfig<V extends VariantSchema> {
|
|
639
750
|
base?: SzObject;
|
|
640
751
|
variants: V;
|
|
@@ -655,7 +766,7 @@ interface SzvConfig<V extends VariantSchema> {
|
|
|
655
766
|
* import { szv } from 'csszyx';
|
|
656
767
|
*
|
|
657
768
|
* const buttonSz = szv({
|
|
658
|
-
* base: {
|
|
769
|
+
* base: { display: 'inline-flex', items: 'center', rounded: 'md', weight: 'medium' },
|
|
659
770
|
* variants: {
|
|
660
771
|
* variant: {
|
|
661
772
|
* default: { bg: 'primary', text: 'primary-foreground' },
|
|
@@ -769,5 +880,5 @@ declare function isRuntimeInitialized(): boolean;
|
|
|
769
880
|
*/
|
|
770
881
|
declare function resetRuntime(): void;
|
|
771
882
|
|
|
772
|
-
export { DEFAULT_RUNTIME_CONFIG, VERSION, _sz, _sz2, _sz3,
|
|
773
|
-
export type { HydrationError, HydrationErrorType, MangleMap, RecoveryManifest, RecoveryMode, RuntimeConfig, SSRContext, SzInput, TokenData, VerificationResult };
|
|
883
|
+
export { DEFAULT_RUNTIME_CONFIG, VERSION, _sz, _sz2, _sz3, _szMerge, abortHydration, attemptCSRRecovery, classify, clearHydrationErrors, computeMangleChecksumAsync, disableCSRRecovery, enableCSRRecovery, endHydration, getAbortedSubtreeCount, getHydrationErrors, getRecoveryMode, getRuntimeConfig, getSSRContext, guardHydration, has, hasRecoveryToken, initRuntime, isCSRRecoveryAllowed, isHydrating, isHydrationAborted, isRuntimeInitialized, isSSREnvironment, isValidMangleMap, isValidManifest, loadMangleMapFromDOM, loadManifestFromDOM, omit, pick, resetRuntime, splitBox, startHydration, stripSzProps, szv, validateHydrationClass, verifyAllTokens, verifyMangleChecksum, verifyMangleChecksumAsync, verifyMangleMapIntegrity, verifyRecoveryToken };
|
|
884
|
+
export type { BoxRole, BoxSelector, Classification, HydrationError, HydrationErrorType, MangleMap, RecoveryManifest, RecoveryMode, RuntimeConfig, SSRContext, SplitBoxOptions, SplitBoxResult, SzInput, TokenData, VerificationResult };
|