@utilix-tech/sdk 0.1.1 → 0.1.4

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 CHANGED
@@ -1,13 +1,14 @@
1
1
  # @utilix-tech/sdk
2
2
 
3
- **100+ developer utility tools that run entirely in Node.js — no API key, no internet required.**
3
+ **100+ developer utility functions for Node.js — runs locally, no API key required.**
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@utilix-tech/sdk?style=flat-square)](https://www.npmjs.com/package/@utilix-tech/sdk)
5
+ [![npm version](https://img.shields.io/npm/v/@utilix-tech/sdk?style=flat-square&color=cb3837)](https://www.npmjs.com/package/@utilix-tech/sdk)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/@utilix-tech/sdk?style=flat-square)](https://www.npmjs.com/package/@utilix-tech/sdk)
7
- [![Node.js version](https://img.shields.io/node/v/@utilix-tech/sdk?style=flat-square)](https://nodejs.org)
8
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
7
+ [![Node.js version](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=flat-square)](https://nodejs.org)
8
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://opensource.org/licenses/MIT)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-ready-3178c6?style=flat-square)](https://www.typescriptlang.org/)
9
10
 
10
- The same tools available at [utilix.tech](https://utilix.tech), packaged for local use in your Node.js projects. Works offline, ships zero runtime secrets, and is fully tree-shakeable via subpath imports.
11
+ The same tools available at **[utilix.tech](https://utilix.tech)**, packaged as a tree-shakeable Node.js SDK. Works offline, ships zero runtime secrets, and has full TypeScript types included.
11
12
 
12
13
  ---
13
14
 
@@ -25,168 +26,415 @@ yarn add @utilix-tech/sdk
25
26
  pnpm add @utilix-tech/sdk
26
27
  ```
27
28
 
29
+ **Requires Node.js 18 or later.** TypeScript types are bundled — no `@types/` package needed.
30
+
28
31
  ---
29
32
 
30
33
  ## Quick Start
31
34
 
32
- Each module is available as a dedicated subpath import so your bundler only pulls in what you use.
35
+ Each of the 14 modules is available as a dedicated subpath import. Import only what you use; bundlers automatically tree-shake the rest.
36
+
37
+ ```ts
38
+ // Pick exactly the modules you need
39
+ import { formatJson, diffJson } from "@utilix-tech/sdk/json";
40
+ import { encodeBase64, decodeBase64 } from "@utilix-tech/sdk/encoding";
41
+ import { hashAll, hashPassword } from "@utilix-tech/sdk/hashing";
42
+ import { convertColor, generatePalette } from "@utilix-tech/sdk/color";
43
+ import { generateUuid, generatePassword } from "@utilix-tech/sdk/generators";
44
+ import { buildCurl, decodeJwt } from "@utilix-tech/sdk/api";
45
+ import { formatSql, testRegex } from "@utilix-tech/sdk/code";
46
+ import { convertCase, slugify } from "@utilix-tech/sdk/text";
47
+ import { parseCsv, yamlToJson } from "@utilix-tech/sdk/data";
48
+ import { diffDates, parseCron } from "@utilix-tech/sdk/time";
49
+ import { convertBytes, pxToAll } from "@utilix-tech/sdk/units";
50
+ import { parseUrl, getStatusCode } from "@utilix-tech/sdk/network";
51
+ import { generateGradient, generateBoxShadow } from "@utilix-tech/sdk/css";
52
+ import { generateQrCode, optimizeSvg } from "@utilix-tech/sdk/misc";
53
+ ```
33
54
 
34
- ### Format JSON
55
+ CommonJS works too:
35
56
 
36
57
  ```js
37
- import { formatJson } from "@utilix-tech/sdk/json";
58
+ const { formatJson } = require("@utilix-tech/sdk/json");
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Modules
64
+
65
+ ### `/json` — JSON Tools
66
+
67
+ ```ts
68
+ import { formatJson, minifyJson, diffJson, jsonToTypescript, validateJson,
69
+ evaluateJsonPath, jsonToCsv, yamlToJson, jsonToYaml, getJsonStats } from "@utilix-tech/sdk/json";
70
+
71
+ // Format with 2-space indent
72
+ formatJson('{"name":"alice","age":30}', { indent: 2 });
73
+
74
+ // Diff two JSON strings — returns line-by-line diff
75
+ diffJson(jsonA, jsonB);
76
+
77
+ // Generate TypeScript interface from JSON
78
+ jsonToTypescript('{"id":1,"name":"Alice"}', { rootName: "User" });
79
+
80
+ // Query with JSONPath
81
+ evaluateJsonPath(obj, "$.users[*].name");
38
82
 
39
- const pretty = formatJson('{"name":"alice","age":30}', { indent: 2 });
40
- console.log(pretty);
41
- // {
42
- // "name": "alice",
43
- // "age": 30
44
- // }
83
+ // Convert JSON to CSV
84
+ jsonToCsv('[{"a":1,"b":2}]');
85
+
86
+ // Validate against JSON Schema
87
+ validateJson(data, schema);
45
88
  ```
46
89
 
47
- ### Encode / Decode Base64
90
+ ---
91
+
92
+ ### `/encoding` — Encode & Decode
48
93
 
49
- ```js
50
- import { encodeBase64 } from "@utilix-tech/sdk/encoding";
94
+ ```ts
95
+ import { encodeBase64, decodeBase64, encodeUrl, decodeUrl,
96
+ encodeHtmlEntities, decodeHtmlEntities, base32Encode, base32Decode } from "@utilix-tech/sdk/encoding";
51
97
 
52
- const encoded = encodeBase64("Hello, World!");
53
- console.log(encoded); // SGVsbG8sIFdvcmxkIQ==
98
+ encodeBase64("Hello, World!"); // "SGVsbG8sIFdvcmxkIQ=="
99
+ decodeBase64("SGVsbG8sIFdvcmxkIQ=="); // "Hello, World!"
100
+ encodeUrl("hello world?"); // "hello%20world%3F"
101
+ encodeHtmlEntities("<div class=\"a\">"); // "&lt;div class=&quot;a&quot;&gt;"
102
+ base32Encode("hello"); // "NBSWY3DPEB3W64TMMQ======"
54
103
  ```
55
104
 
56
- ### Hash a Value
105
+ ---
57
106
 
58
- ```js
59
- import { hashAll } from "@utilix-tech/sdk/hashing";
107
+ ### `/hashing` — Hash & Password
108
+
109
+ ```ts
110
+ import { hashAll, hashOne, hashPassword, verifyPassword, generateHtpasswdFile } from "@utilix-tech/sdk/hashing";
60
111
 
61
- const results = await hashAll("my-secret-string");
62
- console.log(results);
112
+ // Hash with MD5, SHA-1, SHA-256, SHA-512 in one call
113
+ const hashes = await hashAll("my-string");
63
114
  // { md5: "...", sha1: "...", sha256: "...", sha512: "..." }
115
+
116
+ // bcrypt
117
+ const hash = await hashPassword("my-password", 12);
118
+ const valid = await verifyPassword("my-password", hash);
119
+
120
+ // Generate .htpasswd file
121
+ generateHtpasswdFile([{ username: "alice", password: "secret" }]);
64
122
  ```
65
123
 
66
- ### Convert Color Formats
124
+ ---
67
125
 
68
- ```js
69
- import { convertColor } from "@utilix-tech/sdk/color";
126
+ ### `/text` — String & Text
127
+
128
+ ```ts
129
+ import { convertCase, slugify, countWords, generateWords, generateParagraphs,
130
+ escapeString, htmlToMarkdown, applyOps } from "@utilix-tech/sdk/text";
131
+
132
+ convertCase("hello world", "camelCase"); // "helloWorld"
133
+ convertCase("hello world", "PascalCase"); // "HelloWorld"
134
+ convertCase("hello world", "kebab-case"); // "hello-world"
135
+ convertCase("hello world", "snake_case"); // "hello_world"
136
+ convertCase("hello world", "CONSTANT"); // "HELLO_WORLD"
137
+
138
+ slugify("Hello, World! 123"); // "hello-world-123"
70
139
 
71
- const result = convertColor("#1a2b3c");
72
- console.log(result);
73
- // { hex: "#1a2b3c", rgb: "rgb(26, 43, 60)", hsl: "hsl(210, 40%, 17%)" }
140
+ const { words, sentences, readingTime } = countWords("some long text...");
141
+
142
+ generateParagraphs(3); // lorem ipsum paragraphs
143
+
144
+ // Apply line operations: sort, deduplicate, trim, reverse, shuffle
145
+ applyOps(text, ["sort", "deduplicate", "trim"]);
146
+
147
+ htmlToMarkdown("<h1>Hello</h1><p>World</p>");
74
148
  ```
75
149
 
76
- ### Build a cURL Command
150
+ ---
77
151
 
78
- ```js
79
- import { buildCurlCommand } from "@utilix-tech/sdk/api";
152
+ ### `/data` — CSV / YAML / TOML / XML / INI
153
+
154
+ ```ts
155
+ import { parseCsv, csvToJson, validateYaml, tomlToJson, jsonToToml,
156
+ formatXml, xmlToJson, jsonToXml, parseIni } from "@utilix-tech/sdk/data";
157
+
158
+ // CSV
159
+ const rows = parseCsv("name,age\nalice,30\nbob,25");
160
+ csvToJson("name,age\nalice,30"); // [{ name: "alice", age: "30" }]
161
+
162
+ // YAML
163
+ validateYaml("key: value\nlist:\n - a\n - b");
164
+
165
+ // TOML
166
+ tomlToJson('[server]\nhost = "localhost"\nport = 8080');
167
+ jsonToToml({ server: { host: "localhost", port: 8080 } });
168
+
169
+ // XML
170
+ formatXml("<root><item>hello</item></root>");
171
+ xmlToJson("<root><item>hello</item></root>");
172
+
173
+ // INI
174
+ parseIni("[db]\nhost=localhost\nport=5432");
175
+ ```
176
+
177
+ ---
178
+
179
+ ### `/generators` — UUID, Passwords, Fake Data
180
+
181
+ ```ts
182
+ import { generateUuid, generateV4, generateV7, generateUlid,
183
+ generatePassword, checkStrength, generateData } from "@utilix-tech/sdk/generators";
184
+
185
+ generateUuid(); // "f47ac10b-58cc-4372-a567-0e02b2c3d479" (v4)
186
+ generateV7(); // time-ordered UUID v7
187
+ generateUlid(); // "01ARZ3NDEKTSV4RRFFQ69G5FAV"
188
+
189
+ generatePassword({ length: 16, symbols: true, numbers: true });
190
+ checkStrength("P@ssw0rd!"); // { score: 4, label: "Strong", entropy: 52.4 }
191
+
192
+ // Generate fake data rows
193
+ generateData([
194
+ { name: "id", type: "uuid" },
195
+ { name: "email", type: "email" },
196
+ { name: "age", type: "number" },
197
+ ], 10); // 10 rows
198
+ ```
199
+
200
+ ---
201
+
202
+ ### `/time` — Dates, Timezones, Cron
203
+
204
+ ```ts
205
+ import { diffDates, parseCron, convertTime, formatRelative,
206
+ getNextRuns, humanizeDiff } from "@utilix-tech/sdk/time";
207
+
208
+ formatRelative(new Date("2024-01-01")); // "2 years ago"
209
+
210
+ diffDates("2024-01-01", "2025-06-15");
211
+ // { years: 1, months: 5, days: 14, ... }
212
+
213
+ // Timezone conversion
214
+ convertTime("2025-01-01T12:00:00", "America/New_York", "Asia/Tokyo");
215
+
216
+ // Cron parser
217
+ parseCron("0 9 * * MON-FRI");
218
+ // { description: "At 09:00, Monday through Friday", ... }
80
219
 
81
- const curl = buildCurlCommand({
220
+ getNextRuns("*/5 * * * *", 5); // next 5 run timestamps
221
+ ```
222
+
223
+ ---
224
+
225
+ ### `/units` — Conversions
226
+
227
+ ```ts
228
+ import { convertBytes, pxToAll, convert, formatValue } from "@utilix-tech/sdk/units";
229
+
230
+ // File sizes
231
+ convertBytes(1073741824, "GB"); // 1
232
+ convertBytes(1073741824); // "1 GB" (auto-format)
233
+
234
+ // CSS units
235
+ pxToAll(16);
236
+ // { rem: "1rem", em: "1em", pt: "12pt", vw: "...", vh: "..." }
237
+
238
+ // Number bases
239
+ convert("255", 10, 16); // "ff"
240
+ convert("ff", 16, 10); // "255"
241
+ convert("11111111", 2, 10); // "255"
242
+
243
+ // Currency / locale formatting
244
+ formatValue(1234567.89, { locale: "en-US", currency: "USD" });
245
+ // "$1,234,567.89"
246
+ ```
247
+
248
+ ---
249
+
250
+ ### `/network` — URLs, IPs, HTTP
251
+
252
+ ```ts
253
+ import { getStatusCode, isValidIp, isValidIpv4, isValidIpv6,
254
+ searchStatusCodes, buildGeoUrl, countryCodeToFlag } from "@utilix-tech/sdk/network";
255
+
256
+ getStatusCode(404);
257
+ // { code: 404, text: "Not Found", description: "...", category: "Client Error" }
258
+
259
+ searchStatusCodes("unauthorized");
260
+
261
+ isValidIpv4("192.168.1.1"); // true
262
+ isValidIpv6("::1"); // true
263
+ isValidIp("256.0.0.1"); // false
264
+
265
+ countryCodeToFlag("US"); // "🇺🇸"
266
+ ```
267
+
268
+ ---
269
+
270
+ ### `/api` — cURL, JWT, CORS, HTTP
271
+
272
+ ```ts
273
+ import { buildCurl, parseCurlCommand, decodeJwt, signJwt,
274
+ generateCors, generateCspHeader } from "@utilix-tech/sdk/api";
275
+
276
+ buildCurl({
82
277
  method: "POST",
83
278
  url: "https://api.example.com/data",
84
279
  headers: { "Content-Type": "application/json" },
85
280
  body: { key: "value" },
86
281
  });
87
- console.log(curl);
88
282
  // curl -X POST https://api.example.com/data \
89
283
  // -H "Content-Type: application/json" \
90
284
  // -d '{"key":"value"}'
91
- ```
92
285
 
93
- ### Generate a UUID
286
+ // Parse a curl command back into its parts
287
+ parseCurlCommand('curl -X GET https://api.example.com -H "Authorization: Bearer token"');
94
288
 
95
- ```js
96
- import { generateUuid } from "@utilix-tech/sdk/generators";
289
+ // JWT — decode without verification
290
+ decodeJwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...");
291
+ // { header: {...}, payload: {...}, isExpired: false, expiresIn: "2h" }
292
+
293
+ // Generate CORS headers
294
+ generateCors({ origins: ["https://myapp.com"], methods: ["GET", "POST"] });
97
295
 
98
- const id = generateUuid();
99
- console.log(id); // e.g. "f47ac10b-58cc-4372-a567-0e02b2c3d479"
296
+ // Generate Content-Security-Policy header
297
+ generateCspHeader({ "default-src": ["'self'"], "script-src": ["'self'", "cdn.example.com"] });
100
298
  ```
101
299
 
102
- ### Format SQL
300
+ ---
103
301
 
104
- ```js
105
- import { formatSql } from "@utilix-tech/sdk/code";
302
+ ### `/code` — SQL, HTML, RegEx, GQL
106
303
 
107
- const formatted = formatSql("SELECT id,name FROM users WHERE active=1");
108
- console.log(formatted);
109
- ```
304
+ ```ts
305
+ import { formatSql, minifySql, testRegex, formatHtml, formatGql,
306
+ detectDialect, splitStatements } from "@utilix-tech/sdk/code";
110
307
 
111
- ### Convert Units
308
+ // SQL
309
+ formatSql("SELECT id,name FROM users WHERE active=1 ORDER BY name");
310
+ // SELECT
311
+ // id,
312
+ // name
313
+ // FROM users
314
+ // WHERE active = 1
315
+ // ORDER BY name
112
316
 
113
- ```js
114
- import { convertLength } from "@utilix-tech/sdk/units";
317
+ detectDialect("SELECT TOP 10 * FROM users"); // "tsql"
318
+ splitStatements("SELECT 1; SELECT 2; SELECT 3;");
319
+
320
+ // Regex
321
+ testRegex("^\\d+$", "12345", ["g"]);
322
+ // { isValid: true, matches: ["12345"], ... }
115
323
 
116
- const result = convertLength(100, "cm", "in");
117
- console.log(result); // 39.37
324
+ // HTML
325
+ formatHtml("<div><p>hello</p></div>", { indent: 2 });
326
+ minifyHtml("<div> <p> hello </p> </div>");
327
+
328
+ // GraphQL
329
+ formatGql("query { user(id: 1) { name email } }");
118
330
  ```
119
331
 
120
332
  ---
121
333
 
122
- ## Modules
334
+ ### `/color` — Color Conversion & Palettes
123
335
 
124
- All 14 subpath modules and what they cover:
336
+ ```ts
337
+ import { parseColor, convertColor, generatePalette, checkContrast } from "@utilix-tech/sdk/color";
125
338
 
126
- | Subpath | Description |
127
- |---|---|
128
- | `@utilix-tech/sdk/json` | Format, minify, validate, sort keys, and query JSON documents |
129
- | `@utilix-tech/sdk/encoding` | Base64, URL, HTML, hex, and binary encode/decode |
130
- | `@utilix-tech/sdk/hashing` | MD5, SHA-1, SHA-256, SHA-512, bcrypt, and HMAC |
131
- | `@utilix-tech/sdk/text` | Case conversion, slugify, truncate, word count, and string transforms |
132
- | `@utilix-tech/sdk/data` | CSV/YAML/TOML/XML parse and convert, JSON diff and merge |
133
- | `@utilix-tech/sdk/generators` | UUID v4/v7, nanoid, random strings, passwords, and lorem ipsum |
134
- | `@utilix-tech/sdk/time` | Parse, format, and calculate durations; cron expression helpers |
135
- | `@utilix-tech/sdk/units` | Convert length, weight, temperature, speed, area, volume, and more |
136
- | `@utilix-tech/sdk/network` | Parse URLs, query strings, IP addresses, and CIDR ranges |
137
- | `@utilix-tech/sdk/api` | Build cURL commands, parse HTTP headers, validate OpenAPI specs |
138
- | `@utilix-tech/sdk/code` | Format SQL, minify JS/CSS, detect language, evaluate math expressions |
139
- | `@utilix-tech/sdk/color` | Convert between hex, RGB, HSL, HSV, CMYK; generate palettes |
140
- | `@utilix-tech/sdk/css` | Parse, minify, and format CSS; extract variables and rules |
141
- | `@utilix-tech/sdk/misc` | QR code generation, markdown conversion, semver comparison |
339
+ parseColor("#1a2b3c");
340
+ // { hex: "#1a2b3c", rgb: { r: 26, g: 43, b: 60 }, hsl: { h: 210, s: 40, l: 17 } }
341
+
342
+ // Generate a color palette
343
+ generatePalette("#3b82f6", "analogous"); // 5 analogous colors
344
+ generatePalette("#3b82f6", "complementary");
345
+ generatePalette("#3b82f6", "triadic");
346
+
347
+ // WCAG contrast check
348
+ checkContrast("#ffffff", "#000000");
349
+ // { ratio: 21, aa: true, aaa: true, level: "AAA" }
350
+ ```
142
351
 
143
352
  ---
144
353
 
145
- ## Node.js SDK vs Python SDK
354
+ ### `/css` CSS Generators
146
355
 
147
- `@utilix-tech/sdk` is the Node.js companion to [`utilix-sdk`](https://pypi.org/project/utilix-sdk/) on PyPI. Both SDKs expose the same 100+ tools and return identically shaped results.
356
+ ```ts
357
+ import { generateGradient, generateBoxShadow, generateBorderRadius,
358
+ generateAnimationCSS, generateKeyframesCSS } from "@utilix-tech/sdk/css";
148
359
 
149
- | | Node.js | Python |
150
- |---|---|---|
151
- | Install | `npm install @utilix-tech/sdk` | `pip install utilix-sdk` |
152
- | Import style | `import { fn } from "@utilix-tech/sdk/json"` | `from utilix.tools.json_tools import fn` |
153
- | Tree-shaking | Yes — subpath imports only bundle what you use | Not applicable |
154
- | Return shapes | Identical JSON-serializable objects | Identical JSON-serializable dicts |
155
- | Runtime | Node 18+ | Python 3.9+ |
360
+ generateGradient({
361
+ type: "linear",
362
+ angle: 135,
363
+ stops: [{ color: "#6366f1", position: 0 }, { color: "#8b5cf6", position: 100 }],
364
+ });
365
+ // "linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)"
366
+
367
+ generateBoxShadow([{ x: 0, y: 4, blur: 6, spread: -1, color: "rgba(0,0,0,0.1)" }]);
368
+ // "0px 4px 6px -1px rgba(0,0,0,0.1)"
369
+
370
+ generateBorderRadius({ tl: 8, tr: 8, br: 0, bl: 0 });
371
+ // "8px 8px 0px 0px"
372
+ ```
156
373
 
157
374
  ---
158
375
 
159
- ## Surface A (Local) vs Surface B (REST API)
376
+ ### `/misc` SVG, QR, Unicode
160
377
 
161
- ### Surface A — Local (this package)
378
+ ```ts
379
+ import { optimizeSvg, sanitizeSvg, analyzeString, toUnicodeEscape,
380
+ formatBytes, calcSavings } from "@utilix-tech/sdk/misc";
162
381
 
163
- `@utilix-tech/sdk` is **Surface A**: everything runs in-process, in your Node.js runtime. No outbound network requests are made. Ideal for:
382
+ // SVG
383
+ optimizeSvg("<svg>...</svg>"); // minified, cleaned SVG
384
+ sanitizeSvg("<svg>...</svg>"); // XSS-safe SVG
164
385
 
165
- - CI pipelines and build scripts
166
- - CLI tools and developer tooling
167
- - Server-side Node.js applications
168
- - Offline or air-gapped environments
386
+ // QR code (returns SVG or data URL)
387
+ // Note: QR generation requires the browser canvas API; use the utilix.tech API for server-side QR codes
169
388
 
170
- ### Surface B — REST API (coming soon)
389
+ // File size
390
+ formatBytes(1048576); // "1 MB"
391
+ calcSavings(1048576, 524288); // { saved: 524288, percent: 50 }
171
392
 
172
- **Surface B** is a language-agnostic REST API hosted at `api.utilix.tech`. It exposes the same tools over HTTP so any language or environment can call them with a single `fetch`. Currently in development — follow [utilix.tech](https://utilix.tech) for announcements.
393
+ // Unicode
394
+ toUnicodeEscape("Hello"); // "\\u0048\\u0065\\u006C\\u006C\\u006F"
395
+ analyzeString("café"); // { length: 4, codePoints: [...], ... }
396
+ ```
173
397
 
174
398
  ---
175
399
 
176
- ## Requirements
400
+ ## All Modules at a Glance
177
401
 
178
- - **Node.js 18 or later** uses the built-in `crypto` module APIs stabilized in Node 18.
179
- - **ESM and CommonJS both supported** — the package ships dual exports.
402
+ | Import | What it does |
403
+ |---|---|
404
+ | `@utilix-tech/sdk/json` | Format, minify, diff, validate, JSONPath, CSV↔JSON, YAML↔JSON, TS types |
405
+ | `@utilix-tech/sdk/encoding` | Base64, URL, HTML entities, Base32 encode/decode |
406
+ | `@utilix-tech/sdk/hashing` | MD5, SHA-1/256/512, bcrypt, HMAC, .htpasswd |
407
+ | `@utilix-tech/sdk/text` | Case convert, slugify, word count, lorem ipsum, line ops, HTML→Markdown |
408
+ | `@utilix-tech/sdk/data` | CSV, YAML, TOML, XML, INI parse and convert |
409
+ | `@utilix-tech/sdk/generators` | UUID v4/v7, ULID, passwords, strength check, fake data |
410
+ | `@utilix-tech/sdk/time` | Date diff, timezone convert, cron parse, relative time |
411
+ | `@utilix-tech/sdk/units` | Bytes, CSS px/rem, number bases, currency format |
412
+ | `@utilix-tech/sdk/network` | HTTP status codes, IP validation, country flags, geolocation URLs |
413
+ | `@utilix-tech/sdk/api` | cURL build/parse, JWT decode/sign, CORS headers, CSP header |
414
+ | `@utilix-tech/sdk/code` | SQL format/minify, HTML format/minify, regex tester, GraphQL format |
415
+ | `@utilix-tech/sdk/color` | Hex/RGB/HSL/HSV/CMYK convert, palette generation, contrast check |
416
+ | `@utilix-tech/sdk/css` | CSS gradient, box-shadow, border-radius, keyframe animation generators |
417
+ | `@utilix-tech/sdk/misc` | SVG optimize/sanitize, file size format, Unicode inspector |
180
418
 
181
- ```js
182
- // ESM
183
- import { formatJson } from "@utilix-tech/sdk/json";
419
+ ---
184
420
 
185
- // CommonJS
186
- const { formatJson } = require("@utilix-tech/sdk/json");
421
+ ## Python SDK
422
+
423
+ `@utilix-tech/sdk` has a Python companion — [`utilix-sdk`](https://pypi.org/project/utilix-sdk/) on PyPI — with the same 100+ tools and identical return shapes.
424
+
425
+ ```bash
426
+ pip install utilix-sdk
187
427
  ```
188
428
 
189
- TypeScript types are included no `@types/` package needed.
429
+ Both SDKs return plain JSON-serializable objects so you can share test fixtures and API contracts across languages.
430
+
431
+ ---
432
+
433
+ ## Surface A vs Surface B
434
+
435
+ **This package is Surface A** — everything runs in-process in your Node.js runtime. No outbound requests, no API key, no rate limits.
436
+
437
+ A **Surface B REST API** (`api.utilix.tech`) is coming soon for use cases where you can't ship a Node.js or Python runtime. Same tools, callable from any language over HTTP.
190
438
 
191
439
  ---
192
440
 
@@ -13,10 +13,13 @@ __export(code_exports, {
13
13
  buildGitCommand: () => buildGitCommand,
14
14
  collapseHtmlWhitespace: () => collapseHtmlWhitespace,
15
15
  collapseJsWhitespace: () => collapseJsWhitespace,
16
+ countProperties: () => countProperties,
17
+ countRules: () => countRules,
16
18
  detectDialect: () => detectDialect,
17
19
  detectOperationType: () => detectOperationType,
18
20
  envToExport: () => envToExport,
19
21
  envToJson: () => envToJson,
22
+ formatCss: () => formatCss,
20
23
  formatGql: () => formatGql,
21
24
  formatHtml: () => formatHtml,
22
25
  formatSql: () => formatSql,
@@ -25,6 +28,7 @@ __export(code_exports, {
25
28
  getJsStats: () => getJsStats,
26
29
  getMethodColor: () => getMethodColor,
27
30
  isValidTag: () => isValidTag,
31
+ minifyCss: () => minifyCss,
28
32
  minifyGql: () => minifyGql,
29
33
  minifyHtml: () => minifyHtml,
30
34
  minifyJs: () => minifyJs,
@@ -2211,5 +2215,68 @@ function envToExport(input) {
2211
2215
  function validateEnvKey(key) {
2212
2216
  return /^[A-Za-z_][A-Za-z0-9_]*$/.test(key);
2213
2217
  }
2218
+ function _calcCssResult(input, output) {
2219
+ const originalSize = input.length;
2220
+ const outputSize = output.length;
2221
+ const savingsPercent = originalSize === 0 ? 0 : Math.round((originalSize - outputSize) / originalSize * 100 * 100) / 100;
2222
+ return { output, originalSize, outputSize, savingsPercent };
2223
+ }
2224
+ function minifyCss(input) {
2225
+ let output = input;
2226
+ output = output.replace(/\/\*[\s\S]*?\*\//g, "");
2227
+ output = output.replace(/\s+/g, " ");
2228
+ output = output.replace(/\s*{\s*/g, "{");
2229
+ output = output.replace(/\s*}\s*/g, "}");
2230
+ output = output.replace(/\s*:\s*/g, ":");
2231
+ output = output.replace(/\s*;\s*/g, ";");
2232
+ output = output.replace(/\s*,\s*/g, ",");
2233
+ output = output.replace(/;}/g, "}");
2234
+ output = output.trim();
2235
+ return _calcCssResult(input, output);
2236
+ }
2237
+ function formatCss(input, indentSize = 2) {
2238
+ const indent = " ".repeat(indentSize);
2239
+ const { output: minified } = minifyCss(input);
2240
+ let result = "";
2241
+ let insideBlock = false;
2242
+ let i = 0;
2243
+ while (i < minified.length) {
2244
+ const char = minified[i];
2245
+ if (char === "{") {
2246
+ result += " {\n";
2247
+ insideBlock = true;
2248
+ } else if (char === "}") {
2249
+ result = result.trimEnd() + "\n";
2250
+ result += "}\n\n";
2251
+ insideBlock = false;
2252
+ } else if (char === ";" && insideBlock) {
2253
+ result += ";\n";
2254
+ if (i + 1 < minified.length && minified[i + 1] !== "}") result += indent;
2255
+ } else {
2256
+ if (insideBlock && result.endsWith("{\n")) result += indent;
2257
+ result += char;
2258
+ }
2259
+ i++;
2260
+ }
2261
+ return _calcCssResult(input, result.trimEnd());
2262
+ }
2263
+ function countRules(css) {
2264
+ return (css.match(/{/g) ?? []).length;
2265
+ }
2266
+ function countProperties(css) {
2267
+ let count = 0;
2268
+ let insideBlock = false;
2269
+ for (const char of css) {
2270
+ if (char === "{") insideBlock = true;
2271
+ else if (char === "}") insideBlock = false;
2272
+ else if (char === ";" && insideBlock) count++;
2273
+ }
2274
+ css.replace(/{[^{}]*}/g, (block) => {
2275
+ const last = block.slice(1, -1).trim().split(";").pop()?.trim();
2276
+ if (last?.includes(":")) count++;
2277
+ return block;
2278
+ });
2279
+ return count;
2280
+ }
2214
2281
 
2215
- export { ALL_FLAGS, CHEATSHEET, OPERATIONS, SQL_DEFAULT_OPTIONS, buildDockerPull, buildDockerRun, buildGitCommand, code_exports, collapseHtmlWhitespace, collapseJsWhitespace, detectDialect, detectOperationType, envToExport, envToJson, formatGql, formatHtml, formatSql, getEndpointsByTag, getHtmlStats, getJsStats, getMethodColor, isValidTag, minifyGql, minifyHtml, minifyJs, minifySql, normalizeRef, parseDockerImage, parseEnv, parseGitCommand, parseSpec, removeConsoleCalls, removeEmptyAttributes, removeHtmlComments, removeJsComments, removeRedundantAttributes, searchCheatsheet, searchEndpoints, splitStatements, testPattern, testRegex, validateEnvKey };
2282
+ export { ALL_FLAGS, CHEATSHEET, OPERATIONS, SQL_DEFAULT_OPTIONS, buildDockerPull, buildDockerRun, buildGitCommand, code_exports, collapseHtmlWhitespace, collapseJsWhitespace, countProperties, countRules, detectDialect, detectOperationType, envToExport, envToJson, formatCss, formatGql, formatHtml, formatSql, getEndpointsByTag, getHtmlStats, getJsStats, getMethodColor, isValidTag, minifyCss, minifyGql, minifyHtml, minifyJs, minifySql, normalizeRef, parseDockerImage, parseEnv, parseGitCommand, parseSpec, removeConsoleCalls, removeEmptyAttributes, removeHtmlComments, removeJsComments, removeRedundantAttributes, searchCheatsheet, searchEndpoints, splitStatements, testPattern, testRegex, validateEnvKey };