wensity 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +3 -3
  2. package/dist/index.js +166 -65
  3. package/package.json +10 -10
  4. package/LICENSE +0 -21
package/README.md CHANGED
@@ -7,8 +7,8 @@ Install open-code components and UI primitives from the Wensity registry into yo
7
7
  npx wensity@latest init
8
8
 
9
9
  # Or apply a shareable preset from https://ui.wensity.com/docs/primitives/setup
10
- # Preset support requires wensity 0.1.6 or later (pin — @latest may be older)
11
- npx wensity@0.1.6 init --preset <wsty1-code>
10
+ # Preset support requires wensity 0.1.8 or later
11
+ npx wensity@latest init --preset <wsty1-code>
12
12
 
13
13
  # Install a primitive or component
14
14
  npx wensity@latest add button
@@ -38,7 +38,7 @@ Plain `init` (no `--preset`) refuses to overwrite an existing `wensity.json` unl
38
38
  | `wensity list` | List registry entries |
39
39
  | `wensity add <slug>` | Install source (skips existing files) |
40
40
  | `wensity update <slug>` | Re-download and overwrite local source |
41
- | `wensity version` | Print `0.1.6` |
41
+ | `wensity version` | Print `0.1.8` |
42
42
 
43
43
  Premium components and blocks require an API token from the Wensity dashboard. Tokens are stored at `~/.config/wensity/credentials.json` with `0600` permissions.
44
44
 
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { dirname as dirname6, join as join6 } from "path";
6
6
 
7
7
  // src/constants.ts
8
8
  var CLI_NAME = "wensity";
9
- var CLI_VERSION = "0.1.7";
9
+ var CLI_VERSION = "0.1.8";
10
10
  var CONFIG_FILE_NAME = "wensity.json";
11
11
  var DEFAULT_API_ORIGIN = "https://ui.wensity.com";
12
12
  var DEFAULT_REGISTRY_PATH = "/api/registry";
@@ -769,6 +769,9 @@ function utf8ByteLength(text) {
769
769
  return new TextEncoder().encode(text).byteLength;
770
770
  }
771
771
  var BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
772
+ var COMPACT_CANONICAL_PREFIX = "c";
773
+ var COMPACT_CANONICAL_BODY_LENGTH = 3;
774
+ var COMPACT_CANONICAL_ENCODED_LENGTH = COMPACT_CANONICAL_PREFIX.length + COMPACT_CANONICAL_BODY_LENGTH;
772
775
  function toBase64Url(bytes) {
773
776
  let out = "";
774
777
  for (let i = 0; i < bytes.length; i += 3) {
@@ -808,6 +811,66 @@ function fromBase64Url(code) {
808
811
  }
809
812
  return outIndex === out.length ? out : out.subarray(0, outIndex);
810
813
  }
814
+ function indexOfPresetValue(values, value, path) {
815
+ const index = values.indexOf(value);
816
+ if (index < 0) {
817
+ throw new PresetValidationError(`Invalid compact preset value at ${path}.`, path);
818
+ }
819
+ return index;
820
+ }
821
+ function readCompactChar(char) {
822
+ if (!char) return -1;
823
+ return BASE64URL_ALPHABET.indexOf(char);
824
+ }
825
+ function encodeCompactCanonicalPayload(payload) {
826
+ let value = indexOfPresetValue(BASE_COLOR_IDS, payload.baseColor, "preset.baseColor");
827
+ value = value << 3 | indexOfPresetValue(THEME_COLOR_IDS, payload.themeColor, "preset.themeColor");
828
+ value = value << 2 | indexOfPresetValue(CHART_PALETTE_IDS, payload.chartPalette, "preset.chartPalette");
829
+ value = value << 1 | indexOfPresetValue(HEADING_FONT_IDS, payload.headingFont, "preset.headingFont");
830
+ value = value << 1 | indexOfPresetValue(BODY_FONT_IDS, payload.bodyFont, "preset.bodyFont");
831
+ value = value << 1 | indexOfPresetValue(ICON_LIBRARIES, payload.iconLibrary, "preset.iconLibrary");
832
+ value = value << 2 | indexOfPresetValue(RADIUS_PRESETS, payload.radius, "preset.radius");
833
+ return `${COMPACT_CANONICAL_PREFIX}${BASE64URL_ALPHABET[value >> 12 & 63]}${BASE64URL_ALPHABET[value >> 6 & 63]}${BASE64URL_ALPHABET[value & 63]}`;
834
+ }
835
+ function decodeCompactCanonicalPayload(encoded) {
836
+ if (encoded.length !== COMPACT_CANONICAL_ENCODED_LENGTH || !encoded.startsWith(COMPACT_CANONICAL_PREFIX)) {
837
+ throw new PresetValidationError("Compact preset code has an invalid length.", "preset");
838
+ }
839
+ const a = readCompactChar(encoded[1]);
840
+ const b = readCompactChar(encoded[2]);
841
+ const c = readCompactChar(encoded[3]);
842
+ if (a < 0 || b < 0 || c < 0) {
843
+ throw new PresetValidationError("Compact preset code is not valid base64url.", "preset");
844
+ }
845
+ let value = a << 12 | b << 6 | c;
846
+ const radius = RADIUS_PRESETS[value & 3];
847
+ value >>= 2;
848
+ const iconLibrary = ICON_LIBRARIES[value & 1];
849
+ value >>= 1;
850
+ const bodyFont = BODY_FONT_IDS[value & 1];
851
+ value >>= 1;
852
+ const headingFont = HEADING_FONT_IDS[value & 1];
853
+ value >>= 1;
854
+ const chartPalette = CHART_PALETTE_IDS[value & 3];
855
+ value >>= 2;
856
+ const themeColor = THEME_COLOR_IDS[value & 7];
857
+ value >>= 3;
858
+ const baseColor = BASE_COLOR_IDS[value & 7];
859
+ value >>= 3;
860
+ if (value !== 0 || !baseColor || !themeColor || !chartPalette || !headingFont || !bodyFont || !iconLibrary || !radius) {
861
+ throw new PresetValidationError("Compact preset code contains an out-of-range value.", "preset");
862
+ }
863
+ return {
864
+ v: 2,
865
+ baseColor,
866
+ themeColor,
867
+ chartPalette,
868
+ headingFont,
869
+ bodyFont,
870
+ iconLibrary,
871
+ radius
872
+ };
873
+ }
811
874
  function stableStringifyCodecPayload(payload) {
812
875
  const parts = [
813
876
  `"v":${payload.v}`,
@@ -1039,18 +1102,6 @@ function validateCodecPayloadCanonical(value) {
1039
1102
  radius: value.radius
1040
1103
  };
1041
1104
  }
1042
- function stableStringifyCodecPayloadCanonical(payload) {
1043
- return `{${[
1044
- `"v":${payload.v}`,
1045
- `"baseColor":${JSON.stringify(payload.baseColor)}`,
1046
- `"themeColor":${JSON.stringify(payload.themeColor)}`,
1047
- `"chartPalette":${JSON.stringify(payload.chartPalette)}`,
1048
- `"headingFont":${JSON.stringify(payload.headingFont)}`,
1049
- `"bodyFont":${JSON.stringify(payload.bodyFont)}`,
1050
- `"iconLibrary":${JSON.stringify(payload.iconLibrary)}`,
1051
- `"radius":${JSON.stringify(payload.radius)}`
1052
- ].join(",")}}`;
1053
- }
1054
1105
  function encodePresetCanonical(style) {
1055
1106
  const normalized = normalizeStyleConfigCanonical(style);
1056
1107
  const payload = {
@@ -1063,15 +1114,7 @@ function encodePresetCanonical(style) {
1063
1114
  iconLibrary: normalized.iconLibrary,
1064
1115
  radius: normalized.radius
1065
1116
  };
1066
- const json = stableStringifyCodecPayloadCanonical(payload);
1067
- const bytes = new TextEncoder().encode(json);
1068
- if (bytes.byteLength > PRESET_CODEC_MAX_DECODED_JSON_BYTES) {
1069
- throw new PresetValidationError(
1070
- `Preset JSON exceeds ${PRESET_CODEC_MAX_DECODED_JSON_BYTES} bytes.`,
1071
- "preset"
1072
- );
1073
- }
1074
- const code = `${PRESET_CODEC_PREFIX}.${toBase64Url(bytes)}`;
1117
+ const code = `${PRESET_CODEC_PREFIX}.${encodeCompactCanonicalPayload(payload)}`;
1075
1118
  if (code.length > PRESET_CODEC_MAX_CODE_LENGTH) {
1076
1119
  throw new PresetValidationError(
1077
1120
  `Preset code exceeds ${PRESET_CODEC_MAX_CODE_LENGTH} characters.`,
@@ -1101,6 +1144,9 @@ function decodePresetEnvelope(code) {
1101
1144
  if (!encoded) {
1102
1145
  throw new PresetValidationError("Preset code payload is empty.", "preset");
1103
1146
  }
1147
+ if (encoded.length === COMPACT_CANONICAL_ENCODED_LENGTH && encoded.startsWith(COMPACT_CANONICAL_PREFIX)) {
1148
+ return decodeCompactCanonicalPayload(encoded);
1149
+ }
1104
1150
  if (encoded.includes("=") || /[^A-Za-z0-9_-]/.test(encoded)) {
1105
1151
  throw new PresetValidationError("Preset code payload is not valid unpadded base64url.", "preset");
1106
1152
  }
@@ -1313,74 +1359,122 @@ var THEME_COLOR_PALETTE = {
1313
1359
  light: { ...DEFAULT_CONTROL_SOLID_LIGHT },
1314
1360
  dark: { ...DEFAULT_CONTROL_SOLID_DARK }
1315
1361
  },
1362
+ //
1363
+ // Named hues stay the same true, saturated color family in both modes —
1364
+ // dark mode gets one step deeper (never a washed-out pastel tint of the
1365
+ // light-mode color). This mirrors how shadcn's own theme presets work:
1366
+ // e.g. its "red" theme ships `oklch(0.505 … 27.518)` (~Tailwind red-700)
1367
+ // for light and `oklch(0.444 … 26.899)` (~red-800, darker not lighter)
1368
+ // for dark, with a near-white foreground in both. Hex stops below are
1369
+ // Tailwind v4's red/blue/violet/green/orange 600/700/800/900/50 values.
1316
1370
  red: {
1317
1371
  light: {
1318
- controlSolid: "#b91c1c",
1319
- controlSolidHover: "#dc2626",
1320
- controlSolidActive: "#991b1b",
1321
- controlSolidForeground: "#ffffff"
1372
+ controlSolid: "#c10007",
1373
+ // red-700
1374
+ controlSolidHover: "#e7000b",
1375
+ // red-600 — brighter on hover
1376
+ controlSolidActive: "#9f0712",
1377
+ // red-800 — darker on press
1378
+ controlSolidForeground: "#fef2f2"
1379
+ // red-50
1322
1380
  },
1323
1381
  dark: {
1324
- controlSolid: "#f87171",
1325
- controlSolidHover: "#fca5a5",
1326
- controlSolidActive: "#ef4444",
1327
- controlSolidForeground: "#450a0a"
1382
+ controlSolid: "#9f0712",
1383
+ // red-800
1384
+ controlSolidHover: "#c10007",
1385
+ // red-700 — brighter on hover
1386
+ controlSolidActive: "#82181a",
1387
+ // red-900 — darker on press
1388
+ controlSolidForeground: "#fef2f2"
1389
+ // red-50
1328
1390
  }
1329
1391
  },
1330
1392
  blue: {
1331
1393
  light: {
1332
- controlSolid: "#1d4ed8",
1333
- controlSolidHover: "#2563eb",
1334
- controlSolidActive: "#1e40af",
1335
- controlSolidForeground: "#ffffff"
1394
+ controlSolid: "#1447e6",
1395
+ // blue-700
1396
+ controlSolidHover: "#155dfc",
1397
+ // blue-600
1398
+ controlSolidActive: "#193cb8",
1399
+ // blue-800
1400
+ controlSolidForeground: "#eff6ff"
1401
+ // blue-50
1336
1402
  },
1337
1403
  dark: {
1338
- controlSolid: "#60a5fa",
1339
- controlSolidHover: "#93c5fd",
1340
- controlSolidActive: "#3b82f6",
1341
- controlSolidForeground: "#172554"
1404
+ controlSolid: "#193cb8",
1405
+ // blue-800
1406
+ controlSolidHover: "#1447e6",
1407
+ // blue-700
1408
+ controlSolidActive: "#1c398e",
1409
+ // blue-900
1410
+ controlSolidForeground: "#eff6ff"
1411
+ // blue-50
1342
1412
  }
1343
1413
  },
1344
1414
  violet: {
1345
1415
  light: {
1346
- controlSolid: "#6d28d9",
1347
- controlSolidHover: "#7c3aed",
1348
- controlSolidActive: "#5b21b6",
1349
- controlSolidForeground: "#ffffff"
1416
+ controlSolid: "#7008e7",
1417
+ // violet-700
1418
+ controlSolidHover: "#7f22fe",
1419
+ // violet-600
1420
+ controlSolidActive: "#5d0ec0",
1421
+ // violet-800
1422
+ controlSolidForeground: "#f5f3ff"
1423
+ // violet-50
1350
1424
  },
1351
1425
  dark: {
1352
- controlSolid: "#a78bfa",
1353
- controlSolidHover: "#c4b5fd",
1354
- controlSolidActive: "#8b5cf6",
1355
- controlSolidForeground: "#2e1065"
1426
+ controlSolid: "#5d0ec0",
1427
+ // violet-800
1428
+ controlSolidHover: "#7008e7",
1429
+ // violet-700
1430
+ controlSolidActive: "#4d179a",
1431
+ // violet-900
1432
+ controlSolidForeground: "#f5f3ff"
1433
+ // violet-50
1356
1434
  }
1357
1435
  },
1358
1436
  green: {
1359
1437
  light: {
1360
- controlSolid: "#047857",
1361
- controlSolidHover: "#059669",
1362
- controlSolidActive: "#065f46",
1363
- controlSolidForeground: "#ffffff"
1438
+ controlSolid: "#008236",
1439
+ // green-700
1440
+ controlSolidHover: "#00a63e",
1441
+ // green-600
1442
+ controlSolidActive: "#016630",
1443
+ // green-800
1444
+ controlSolidForeground: "#f0fdf4"
1445
+ // green-50
1364
1446
  },
1365
1447
  dark: {
1366
- controlSolid: "#34d399",
1367
- controlSolidHover: "#6ee7b7",
1368
- controlSolidActive: "#10b981",
1369
- controlSolidForeground: "#022c22"
1448
+ controlSolid: "#016630",
1449
+ // green-800
1450
+ controlSolidHover: "#008236",
1451
+ // green-700
1452
+ controlSolidActive: "#0d542b",
1453
+ // green-900
1454
+ controlSolidForeground: "#f0fdf4"
1455
+ // green-50
1370
1456
  }
1371
1457
  },
1372
1458
  orange: {
1373
1459
  light: {
1374
- controlSolid: "#c2410c",
1375
- controlSolidHover: "#ea580c",
1376
- controlSolidActive: "#9a3412",
1377
- controlSolidForeground: "#ffffff"
1460
+ controlSolid: "#ca3500",
1461
+ // orange-700
1462
+ controlSolidHover: "#f54900",
1463
+ // orange-600
1464
+ controlSolidActive: "#9f2d00",
1465
+ // orange-800
1466
+ controlSolidForeground: "#fff7ed"
1467
+ // orange-50
1378
1468
  },
1379
1469
  dark: {
1380
- controlSolid: "#fb923c",
1381
- controlSolidHover: "#fdba74",
1382
- controlSolidActive: "#f97316",
1383
- controlSolidForeground: "#431407"
1470
+ controlSolid: "#9f2d00",
1471
+ // orange-800
1472
+ controlSolidHover: "#ca3500",
1473
+ // orange-700
1474
+ controlSolidActive: "#7e2a0c",
1475
+ // orange-900
1476
+ controlSolidForeground: "#fff7ed"
1477
+ // orange-50
1384
1478
  }
1385
1479
  }
1386
1480
  };
@@ -2709,8 +2803,15 @@ function encodePresetFileJson(parsed) {
2709
2803
  }
2710
2804
  if (v === 2) {
2711
2805
  const payload = validateCodecPayloadCanonical(parsed);
2712
- const json = stableStringifyCodecPayloadCanonical(payload);
2713
- return `${PRESET_CODEC_PREFIX}.${Buffer.from(json, "utf8").toString("base64url")}`;
2806
+ return encodePresetCanonical({
2807
+ baseColor: payload.baseColor,
2808
+ themeColor: payload.themeColor,
2809
+ chartPalette: payload.chartPalette,
2810
+ headingFont: payload.headingFont,
2811
+ bodyFont: payload.bodyFont,
2812
+ iconLibrary: payload.iconLibrary,
2813
+ radius: payload.radius
2814
+ });
2714
2815
  }
2715
2816
  throw new PresetValidationError(
2716
2817
  `Unsupported preset payload version ${String(v)}. This preset may require a newer version of the Wensity CLI.`,
@@ -2744,7 +2845,7 @@ function toCliPresetError(error) {
2744
2845
  const message = error.message;
2745
2846
  if (/Unsupported preset payload version/i.test(message)) {
2746
2847
  return new CliError(
2747
- `Invalid preset: ${message} Upgrade the Wensity CLI (wensity@0.1.7 or newer) and try again.`
2848
+ `Invalid preset: ${message} Upgrade the Wensity CLI (wensity@latest) and try again.`
2748
2849
  );
2749
2850
  }
2750
2851
  return new CliError(`Invalid preset: ${message}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wensity",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Wensity component registry CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,16 +13,22 @@
13
13
  "dist",
14
14
  "README.md"
15
15
  ],
16
+ "scripts": {
17
+ "build": "tsup --config tsup.config.ts",
18
+ "typecheck": "tsc --noEmit",
19
+ "test": "vitest run --config vitest.config.ts",
20
+ "lint": "echo 'no lint'"
21
+ },
16
22
  "engines": {
17
23
  "node": ">=20.0.0"
18
24
  },
19
25
  "devDependencies": {
20
26
  "@types/node": "^22.10.2",
27
+ "@wensity/preset": "workspace:*",
21
28
  "lucide-react": "^1.24.0",
22
29
  "tsup": "^8.3.5",
23
30
  "typescript": "^5.7.2",
24
- "vitest": "^4.1.5",
25
- "@wensity/preset": "0.1.0"
31
+ "vitest": "^4.1.5"
26
32
  },
27
33
  "publishConfig": {
28
34
  "access": "public"
@@ -32,11 +38,5 @@
32
38
  "cli-table3": "^0.6.5",
33
39
  "ora": "^9.4.0",
34
40
  "picocolors": "^1.1.1"
35
- },
36
- "scripts": {
37
- "build": "tsup --config tsup.config.ts",
38
- "typecheck": "tsc --noEmit",
39
- "test": "vitest run --config vitest.config.ts",
40
- "lint": "echo 'no lint'"
41
41
  }
42
- }
42
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Ksparth12
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.