@uniku/cli 0.0.12 → 0.1.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 CHANGED
@@ -9,6 +9,26 @@ Supports UUID v4/v7, ULID, CUID2, Nanoid, and KSUID.
9
9
 
10
10
  ## Installation
11
11
 
12
+ ### Pre-built Binary (recommended)
13
+
14
+ Download and install a standalone binary — no Node.js required:
15
+
16
+ ```bash
17
+ curl -fsSL https://raw.githubusercontent.com/jkomyno/uniku/main/install.sh | sh
18
+ ```
19
+
20
+ Supports macOS (Intel & Apple Silicon) and Linux (x64). Override the install location or version with environment variables:
21
+
22
+ ```bash
23
+ # Custom install directory
24
+ UNIKU_INSTALL_DIR=~/.local/bin curl -fsSL https://raw.githubusercontent.com/jkomyno/uniku/main/install.sh | sh
25
+
26
+ # Specific version
27
+ UNIKU_VERSION=0.0.12 curl -fsSL https://raw.githubusercontent.com/jkomyno/uniku/main/install.sh | sh
28
+ ```
29
+
30
+ ### npm
31
+
12
32
  ```bash
13
33
  # pnpm (recommended)
14
34
  pnpm add -g @uniku/cli
@@ -30,7 +50,7 @@ uniku uuid
30
50
  # => 550e8400-e29b-41d4-a716-446655440000
31
51
 
32
52
  # UUID v7 (time-ordered)
33
- uniku uuid --version 7
53
+ uniku uuid --uuid-version 7
34
54
  # => 018e5e5c-7c8a-7000-8000-000000000000
35
55
 
36
56
  # Generate multiple IDs
@@ -117,11 +137,11 @@ For time-ordered IDs (UUID v7, ULID, KSUID), inspect extracts the embedded times
117
137
 
118
138
  | Command | Option | Alias | Description |
119
139
  |---------|--------|-------|-------------|
120
- | `uuid` | `--version` | `-v` | UUID version: 4 or 7 (default: 4) |
121
- | `uuid` | `--lowercase` | `-l` | Output in lowercase |
140
+ | `uuid` | `--uuid-version` | `-v` | UUID version: 4 or 7 (default: 4) |
141
+ | `uuid` | `--lowercase` | | Output in lowercase |
122
142
  | `ulid` | `--monotonic` | | Generate monotonically increasing ULIDs |
123
143
  | `ulid` | `--timestamp` | | Unix timestamp in ms or "now" |
124
- | `ulid` | `--lowercase` | `-l` | Output in lowercase |
144
+ | `ulid` | `--lowercase` | | Output in lowercase |
125
145
  | `nanoid` | `--size` | `-s` | Length of ID, 1-256 (default: 21) |
126
146
  | `nanoid` | `--alphabet` | `-a` | Custom alphabet or preset: hex, numeric, alpha |
127
147
  | `cuid` | `--length` | `-l` | Length of ID, 2-32 (default: 24) |
package/build/bin.d.mts CHANGED
@@ -1,5 +1 @@
1
- //#region src/bin.d.ts
2
- declare function preprocessArgs(argv: readonly string[]): string[];
3
- //#endregion
4
- export { preprocessArgs };
5
- //# sourceMappingURL=bin.d.mts.map
1
+ export { };
package/build/bin.mjs CHANGED
@@ -1,6 +1,7 @@
1
- import{BunContext as e,BunRuntime as t}from"@effect/platform-bun";import*as n from"effect/Duration";import*as r from"effect/Effect";import*as i from"effect/Fiber";import*as a from"effect/Layer";import*as o from"effect/Option";import{Args as s,Command as c,Options as l}from"@effect/cli";import{cuid2 as u}from"uniku/cuid2";import{UniqueIdError as d}from"uniku/errors";import{ksuid as f}from"uniku/ksuid";import{nanoid as p}from"uniku/nanoid";import{ulid as m}from"uniku/ulid";import{uuidv4 as h}from"uniku/uuid/v4";import{uuidv7 as g}from"uniku/uuid/v7";import*as _ from"effect/Context";import{existsSync as v,mkdirSync as ee,readFileSync as te,renameSync as y,writeFileSync as b}from"node:fs";import{tmpdir as x}from"node:os";import{dirname as S,join as C}from"node:path";const w={hex:`0123456789abcdef`,numeric:`0123456789`,alpha:`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`};var T=class extends Error{constructor(e,t,n,r=1){super(t),this.code=e,this.hint=n,this.exitCode=r,this.name=`CliError`}},ne=class extends T{constructor(e){super(`VALIDATION_FAILED`,e,void 0,2),this.name=`ValidationFailedError`}};function E(e){return new T(e.code,e.message)}function re(e){let t={error:e.message,code:e.code};return e.hint&&(t.hint=e.hint),t}function ie(e){return r.try({try:()=>{let t=[];for(let n=0;n<e.count;n++)t.push(u({length:e.length}));return t},catch:e=>e instanceof d?E(e):new T(`GENERATE_FAILED`,String(e))})}function ae(e){return r.try({try:()=>{let t=[];for(let n=0;n<e.count;n++){let n=e.timestamp==null?void 0:{secs:e.timestamp};t.push(f(n))}return t},catch:e=>e instanceof d?E(e):new T(`GENERATE_FAILED`,String(e))})}function oe(e){if(e)return w[e]??e}function se(e){return r.try({try:()=>{let t=oe(e.alphabet),n=[];for(let r=0;r<e.count;r++)n.push(p({size:e.size,alphabet:t}));return n},catch:e=>e instanceof d?E(e):new T(`GENERATE_FAILED`,String(e))})}function ce(e){return e.monotonic&&e.timestamp!=null?r.fail(new T(`INVALID_OPTIONS`,`--monotonic and --timestamp are mutually exclusive`,`Use --monotonic for monotonically increasing ULIDs, or --timestamp to specify a fixed timestamp`)):r.try({try:()=>{let t=[];for(let n=0;n<e.count;n++){let n=m(e.timestamp==null?void 0:{msecs:e.timestamp});e.lowercase&&(n=n.toLowerCase()),t.push(n)}return t},catch:e=>e instanceof d?E(e):new T(`GENERATE_FAILED`,String(e))})}function le(e){return r.try({try:()=>{let t=e.version===7?g:h,n=[];for(let r=0;r<e.count;r++){let r=t();e.lowercase&&(r=r.toLowerCase()),n.push(r)}return n},catch:e=>e instanceof d?E(e):new T(`GENERATE_FAILED`,String(e))})}var D=class extends _.Tag(`OutputService`)(){};function ue(e){if(e.valid){let t=[`valid (${e.type}`];return e.version!=null&&t.push(` v${e.version}`),t.push(`)`),t.join(``)}return`invalid: ${e.error??`malformed identifier`}`}function de(e){let t=[],n=e.version==null?e.type:`${e.type} (v${e.version})`;return t.push(`Type: ${n}`),e.timestamp&&t.push(`Timestamp: ${e.timestamp}`),e.random&&t.push(`Random: ${e.random}`),e.note&&t.push(`Note: ${e.note}`),t.join(`
2
- `)}const fe=D.of({writeIds(e,t){return r.sync(()=>{if(t.json){let t=e.length===1?JSON.stringify(e[0]):JSON.stringify(e);process.stdout.write(`${t}\n`)}else for(let t of e)process.stdout.write(`${t}\n`)})},writeValidation(e,t){return r.sync(()=>{if(!t.quiet)if(t.json){let t=e.length===1?JSON.stringify(e[0]):JSON.stringify(e);process.stdout.write(`${t}\n`)}else for(let t of e)process.stdout.write(`${ue(t)}\n`)})},writeInspect(e,t){return r.sync(()=>{t.json?process.stdout.write(`${JSON.stringify(e)}\n`):process.stdout.write(`${de(e)}\n`)})},writeError(e,t){return r.sync(()=>{if(t.json)process.stderr.write(`${JSON.stringify(re(e))}\n`);else{let t=`Error: ${e.message}`;e.hint&&(t+=`\n ${e.hint}`),process.stderr.write(`${t}\n`)}})}}),O=l.integer(`count`).pipe(l.withAlias(`n`),l.withDescription(`Number of IDs to generate`),l.withDefault(1)),k=l.boolean(`json`).pipe(l.withDescription(`Output as JSON`),l.withDefault(!1)),A=l.choiceWithValue(`version`,[[`4`,4],[`7`,7]]).pipe(l.withAlias(`v`),l.withDescription(`UUID version: 4, 7`),l.withDefault(4)),j=l.boolean(`lowercase`).pipe(l.withAlias(`l`),l.withDescription(`Output in lowercase`),l.withDefault(!1)),M=c.make(`uuid`,{count:O,json:k,version:A,lowercase:j},({count:e,json:t,version:n,lowercase:i})=>r.gen(function*(){let r=yield*D,a=yield*le({count:e,version:n,lowercase:i});yield*r.writeIds(a,{json:t})})).pipe(c.withDescription(`Generate UUIDs (v4 or v7)`)),N=l.boolean(`monotonic`).pipe(l.withDescription(`Generate monotonically increasing ULIDs`),l.withDefault(!1)),P=l.text(`timestamp`).pipe(l.withDescription(`Unix timestamp in milliseconds (or "now")`),l.optional),F=c.make(`ulid`,{count:O,json:k,monotonic:N,timestamp:P,lowercase:j},({count:e,json:t,monotonic:n,timestamp:i,lowercase:a})=>r.gen(function*(){let r=yield*D,s=yield*ce({count:e,monotonic:n,timestamp:o.isSome(i)?ye(o.getOrThrow(i)):void 0,lowercase:a});yield*r.writeIds(s,{json:t})})).pipe(c.withDescription(`Generate ULIDs`)),I=l.integer(`size`).pipe(l.withAlias(`s`),l.withDescription(`Length of ID (1-256)`),l.withDefault(21)),L=l.text(`alphabet`).pipe(l.withAlias(`a`),l.withDescription(`Custom alphabet or preset: hex, numeric, alpha`),l.optional),R=c.make(`nanoid`,{count:O,json:k,size:I,alphabet:L},({count:e,json:t,size:n,alphabet:i})=>r.gen(function*(){let r=yield*D,a=yield*se({count:e,size:n,alphabet:o.isSome(i)?o.getOrThrow(i):void 0});yield*r.writeIds(a,{json:t})})).pipe(c.withDescription(`Generate Nanoids`)),z=l.integer(`length`).pipe(l.withAlias(`l`),l.withDescription(`Length of ID (2-32)`),l.withDefault(24)),B=c.make(`cuid`,{count:O,json:k,length:z},({count:e,json:t,length:n})=>r.gen(function*(){let r=yield*D,i=yield*ie({count:e,length:n});yield*r.writeIds(i,{json:t})})).pipe(c.withDescription(`Generate CUIDs (v2)`)),V=l.text(`timestamp`).pipe(l.withDescription(`Unix timestamp in seconds (or "now")`),l.optional),H=c.make(`ksuid`,{count:O,json:k,timestamp:V},({count:e,json:t,timestamp:n})=>r.gen(function*(){let r=yield*D,i=yield*ae({count:e,timestamp:o.isSome(n)?be(o.getOrThrow(n)):void 0});yield*r.writeIds(i,{json:t})})).pipe(c.withDescription(`Generate KSUIDs`)),pe=c.make(`generate`).pipe(c.withDescription(`Generate new IDs`),c.withSubcommands([M,F,R,B,H])),me=M,he=F,ge=R,_e=B,ve=H;function ye(e){if(e===`now`)return Date.now();let t=Number(e);if(!Number.isFinite(t)||t<0)throw new T(`INVALID_TIMESTAMP`,`Invalid timestamp: "${e}"`,`Provide a Unix timestamp in milliseconds or "now"`);return t}function be(e){if(e===`now`)return Math.floor(Date.now()/1e3);let t=Number(e);if(!Number.isFinite(t)||t<0)throw new T(`INVALID_TIMESTAMP`,`Invalid timestamp: "${e}"`,`Provide a Unix timestamp in seconds or "now"`);return t}function xe(e,t){switch(t){case`uuid`:return Se(e);case`ulid`:return Ce(e);case`ksuid`:return we(e);case`cuid`:return Te(e);case`nanoid`:return Ee(e)}}function U(e){return g.isValid(e)?{id:e,valid:!0,type:`uuid`,version:7}:h.isValid(e)?{id:e,valid:!0,type:`uuid`,version:4}:m.isValid(e)?{id:e,valid:!0,type:`ulid`}:f.isValid(e)?{id:e,valid:!0,type:`ksuid`}:u.isValid(e)?{id:e,valid:!0,type:`cuid`}:p.isValid(e)?{id:e,valid:!0,type:`nanoid`}:{id:e,valid:!1,error:`malformed identifier`}}function Se(e){return g.isValid(e)?{id:e,valid:!0,type:`uuid`,version:7}:h.isValid(e)?{id:e,valid:!0,type:`uuid`,version:4}:{id:e,valid:!1,type:`uuid`,error:`invalid UUID format`}}function Ce(e){return m.isValid(e)?{id:e,valid:!0,type:`ulid`}:{id:e,valid:!1,type:`ulid`,error:`invalid ULID format`}}function we(e){return f.isValid(e)?{id:e,valid:!0,type:`ksuid`}:{id:e,valid:!1,type:`ksuid`,error:`invalid KSUID format`}}function Te(e){return u.isValid(e)?{id:e,valid:!0,type:`cuid`}:{id:e,valid:!1,type:`cuid`,error:`invalid CUID format`}}function Ee(e){return p.isValid(e)?{id:e,valid:!0,type:`nanoid`}:{id:e,valid:!1,type:`nanoid`,error:`invalid Nanoid format`}}function De(e,t){let n=t??Oe(e);if(!n)return null;switch(n){case`uuid`:return ke(e);case`ulid`:return Ae(e);case`ksuid`:return je(e);case`cuid`:return Me(e);case`nanoid`:return Ne(e)}}function Oe(e){let t=U(e);return t.valid?t.type??null:null}function ke(e){if(g.isValid(e)){let t=g.timestamp(e),n=g.toBytes(e),r=Buffer.from(n.slice(10)).toString(`hex`);return{id:e,type:`uuid`,version:7,timestamp:new Date(t).toISOString(),timestamp_ms:t,random:r}}return h.isValid(e)?{id:e,type:`uuid`,version:4,note:`This ID type contains no decodable metadata.`}:{id:e,type:`uuid`,note:`Unrecognized UUID version.`}}function Ae(e){let t=m.timestamp(e),n=e.slice(10);return{id:e,type:`ulid`,timestamp:new Date(t).toISOString(),timestamp_ms:t,random:n}}function je(e){let t=f.timestamp(e),n=f.toBytes(e),r=Buffer.from(n.slice(4)).toString(`hex`);return{id:e,type:`ksuid`,timestamp:new Date(t).toISOString(),timestamp_ms:t,random:r}}function Me(e){return{id:e,type:`cuid`,note:`This ID type contains no decodable metadata.`}}function Ne(e){return{id:e,type:`nanoid`,note:`This ID type contains no decodable metadata.`}}const Pe=s.text({name:`id`}).pipe(s.withDescription(`The ID to inspect`)),Fe=l.choice(`type`,[`uuid`,`ulid`,`nanoid`,`cuid`,`ksuid`]).pipe(l.withDescription(`ID type (auto-detected if omitted)`),l.optional),Ie=l.boolean(`json`).pipe(l.withDescription(`Output as JSON`),l.withDefault(!1)),Le=c.make(`inspect`,{id:Pe,type:Fe,json:Ie},({id:e,type:t,json:n})=>r.gen(function*(){let i=yield*D,a=De(e,o.isSome(t)?o.getOrThrow(t):void 0);if(!a){yield*r.fail(new T(`UNKNOWN_ID_TYPE`,`Could not identify ID type for: "${e}"`,`Use --type to specify the ID type`));return}yield*i.writeInspect(a,{json:n})})).pipe(c.withDescription(`Decode and inspect an ID`));var W=class extends _.Tag(`StdinService`)(){};const Re=W.of({readLines(){return r.async(e=>{let t=[];process.stdin.on(`data`,e=>{t.push(e)}),process.stdin.on(`end`,()=>{let n=Buffer.concat(t).toString(`utf-8`).split(`
3
- `).map(e=>e.trim()).filter(e=>e.length>0);e(r.succeed(n))}),process.stdin.on(`error`,t=>{e(r.fail(new T(`STDIN_ERROR`,t.message)))}),process.stdin.resume()})}}),ze=s.text({name:`id`}).pipe(s.withDescription(`The ID to validate`),s.optional),Be=l.choice(`type`,[`uuid`,`ulid`,`nanoid`,`cuid`,`ksuid`]).pipe(l.withDescription(`Expected ID type (auto-detected if omitted)`),l.optional),Ve=l.boolean(`stdin`).pipe(l.withDescription(`Read IDs from stdin (one per line)`),l.withDefault(!1)),He=l.boolean(`json`).pipe(l.withDescription(`Output validation results as JSON`),l.withDefault(!1)),Ue=l.boolean(`quiet`).pipe(l.withDescription(`No output, exit code only`),l.withDefault(!1)),We=c.make(`validate`,{id:ze,type:Be,stdin:Ve,json:He,quiet:Ue},({id:e,type:t,stdin:n,json:i,quiet:a})=>r.gen(function*(){let s=yield*D,c=yield*W,l=o.isSome(t)?o.getOrThrow(t):void 0,u;if(n){if(u=yield*c.readLines(),u.length===0){yield*r.fail(new T(`NO_INPUT`,`No IDs provided on stdin`));return}}else if(o.isSome(e))u=[o.getOrThrow(e)];else{yield*r.fail(new T(`NO_INPUT`,`No ID provided`,`Pass an ID as argument or use --stdin`));return}let d=u.map(e=>l?xe(e,l):U(e));yield*s.writeValidation(d,{json:i,quiet:a}),d.some(e=>!e.valid)&&(yield*r.fail(new ne(`One or more IDs are invalid`)))})).pipe(c.withDescription(`Check if an ID is valid`)),Ge=c.make(`uniku`).pipe(c.withDescription(`Generate and validate unique identifiers`),c.withSubcommands([pe,We,Le,me,he,ge,_e,ve])),Ke=e=>c.run(Ge,{name:`uniku`,version:e});var G=class extends _.Tag(`UpdateCheckService`)(){};const K=`@uniku/cli`,q=C(x(),`uniku-update-check.json`);function J(e){let t=e.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);return t?{major:Number(t[1]),minor:Number(t[2]),patch:Number(t[3]),prerelease:t[4]??null}:null}function Y(e,t){let n=J(e),r=J(t);return!n||!r?!1:n.major===r.major?n.minor===r.minor?n.patch===r.patch?n.prerelease===null&&r.prerelease!==null?!0:(n.prerelease!==null&&r.prerelease,!1):n.patch>r.patch:n.minor>r.minor:n.major>r.major}function qe(){return!!process.env.NO_UPDATE_NOTIFIER||!!process.env.CI||!!process.env.CONTINUOUS_INTEGRATION||process.env.NODE_ENV===`test`||!process.stderr.isTTY}function X(e){if(process.env.NO_COLOR){let t=e.isStandaloneBinary?`Download at https://github.com/jkomyno/uniku/releases`:`Run \`npm install -g ${K}\` to update`;return[``,` Update available: ${e.currentVersion} → ${e.latestVersion}`,` ${t}`,` Set NO_UPDATE_NOTIFIER=1 to disable`,``].join(`
4
- `)}let t=`\x1B[2m`,n=`\x1B[36m`,r=`\x1B[0m`,i=e.isStandaloneBinary?`Download at ${n}https://github.com/jkomyno/uniku/releases${r}`:`Run ${n}\`npm install -g ${K}\`${r} to update`;return[``,` ${t}Update available:${r} ${t}${e.currentVersion}${r} ${t}→${r} ${e.latestVersion}${r}`,` ${i}`,` ${t}Set NO_UPDATE_NOTIFIER=1 to disable${r}`,``].join(`
5
- `)}function Je(){try{if(!v(q))return null;let e=te(q,`utf-8`);return JSON.parse(e)}catch{return null}}function Ye(e){try{ee(S(q),{recursive:!0});let t=`${q}.tmp`;b(t,JSON.stringify(e)),y(t,q)}catch{}}function Xe(e){return r.tryPromise({try:t=>fetch(`https://registry.npmjs.org/%40uniku%2Fcli/latest`,{headers:{Accept:`application/json`,"User-Agent":`${K}/${e}`},signal:AbortSignal.any([t,AbortSignal.timeout(5e3)])}).then(async e=>{if(!e.ok)throw Error(`HTTP ${e.status}`);let t=await e.json();if(!t.version)throw Error(`Missing version field`);return t.version}),catch:()=>Error(`fetch failed`)}).pipe(r.catchAll(()=>r.succeed(null)))}function Z(){try{return typeof __STANDALONE_BINARY__<`u`&&__STANDALONE_BINARY__===!0}catch{return!1}}const Ze=G.of({check(e){return r.gen(function*(){if(qe())return o.none();let t=Je(),n=Date.now();if(t&&n-t.checkedAt<864e5)return Y(t.latestVersion,e)?o.some({currentVersion:e,latestVersion:t.latestVersion,isStandaloneBinary:Z()}):o.none();let r=yield*Xe(e);return r===null?o.none():(Ye({latestVersion:r,checkedAt:n}),Y(r,e)?o.some({currentVersion:e,latestVersion:r,isStandaloneBinary:Z()}):o.none())}).pipe(r.catchAll(()=>r.succeed(o.none())))},notify(e){return r.sync(()=>{process.stderr.write(X(e))})}});var Q=`0.0.12`;const Qe=Ke(Q);function $(e){let t=[...e];for(let e=2;e<t.length;e++)t[e]===`-V`&&(t[e]=`--version`);return t.length<=2&&t.push(`--help`),t}const $e=a.mergeAll(a.succeed(D,fe),a.succeed(W,Re),a.succeed(G,Ze)),et=a.mergeAll($e,e.layer);r.gen(function*(){let e=yield*G,t=$(process.argv),a=yield*r.fork(e.check(Q));yield*r.suspend(()=>Qe(t)).pipe(r.catchAll(e=>r.sync(()=>{e instanceof T?(process.stderr.write(`Error: ${e.message}\n`),e.hint&&process.stderr.write(` ${e.hint}\n`),process.exitCode=e.exitCode):(process.stderr.write(`Error: ${String(e)}\n`),process.exitCode=1)})));let s=yield*i.join(a).pipe(r.timeout(n.seconds(5)),r.catchAll(()=>r.succeed(o.none())));o.isSome(s)&&!t.includes(`--json`)&&(yield*e.notify(s.value))}).pipe(r.provide(et),t.runMain);export{$ as preprocessArgs};
1
+ #!/usr/bin/env node
2
+ import*as e from"@effect/platform-bun/BunRuntime";import*as t from"@effect/platform-bun/BunServices";import*as n from"effect/Duration";import*as r from"effect/Effect";import*as i from"effect/Fiber";import*as a from"effect/Layer";import*as o from"effect/Option";import{Argument as s,Command as c,Flag as l}from"effect/unstable/cli";import*as u from"effect/Clock";import*as d from"effect/Schema";import{cuid2 as f}from"uniku/cuid2";import{UniqueIdError as p}from"uniku/errors";import{ksuid as m}from"uniku/ksuid";import{nanoid as h}from"uniku/nanoid";import{ulid as g}from"uniku/ulid";import{uuidv4 as _}from"uniku/uuid/v4";import{uuidv7 as v}from"uniku/uuid/v7";import*as y from"effect/Context";import*as ee from"effect/Console";import*as b from"effect/Match";import{mkdirSync as te,readFileSync as ne,renameSync as re,writeFileSync as ie}from"node:fs";import{tmpdir as ae,userInfo as oe}from"node:os";import{dirname as x,join as S}from"node:path";import*as C from"effect/Config";const se={hex:`0123456789abcdef`,numeric:`0123456789`,alpha:`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`};var w=class extends d.TaggedErrorClass()(`CliError`,{code:d.String,message:d.String,hint:d.optionalKey(d.String)}){exitCode=1},ce=class extends d.TaggedErrorClass()(`ValidationFailedError`,{message:d.String}){code=`VALIDATION_FAILED`;hint=void 0;exitCode=2};function T(e){return new w({code:e.code,message:e.message})}function le(e){let t={error:e.message,code:e.code};return e.hint&&(t.hint=e.hint),t}function ue(e){return r.try({try:()=>{let t=[];for(let n=0;n<e.count;n++)t.push(f({length:e.length}));return t},catch:e=>e instanceof p?T(e):new w({code:`GENERATE_FAILED`,message:String(e)})})}function de(e){return r.try({try:()=>{let t=[];for(let n=0;n<e.count;n++){let n=e.timestamp==null?void 0:{secs:e.timestamp};t.push(m(n))}return t},catch:e=>e instanceof p?T(e):new w({code:`GENERATE_FAILED`,message:String(e)})})}function fe(e){if(e)return se[e]??e}function pe(e){return r.try({try:()=>{let t=fe(e.alphabet),n=[];for(let r=0;r<e.count;r++)n.push(h({size:e.size,alphabet:t}));return n},catch:e=>e instanceof p?T(e):new w({code:`GENERATE_FAILED`,message:String(e)})})}function me(e){return e.monotonic&&e.timestamp!=null?r.fail(new w({code:`INVALID_OPTIONS`,message:`--monotonic and --timestamp are mutually exclusive`,hint:`Use --monotonic for monotonically increasing ULIDs, or --timestamp to specify a fixed timestamp`})):r.try({try:()=>{let t=[];for(let n=0;n<e.count;n++){let n=g(e.timestamp==null?void 0:{msecs:e.timestamp});e.lowercase&&(n=n.toLowerCase()),t.push(n)}return t},catch:e=>e instanceof p?T(e):new w({code:`GENERATE_FAILED`,message:String(e)})})}function he(e){return r.try({try:()=>{let t=e.version===7?v:_,n=[];for(let r=0;r<e.count;r++){let r=t();e.lowercase&&(r=r.toLowerCase()),n.push(r)}return n},catch:e=>e instanceof p?T(e):new w({code:`GENERATE_FAILED`,message:String(e)})})}function E(e,t){return t.json?[JSON.stringify(e.json())]:e.text()}var D=class e extends y.Service()(`uniku/cli/OutputService`){static layer=a.succeed(e,e.of({write:(e,t)=>r.sync(()=>O(process.stdout,E(e,t))),writeError:(e,t)=>r.sync(()=>O(process.stderr,E(e,t)))}))};function O(e,t){for(let n of t)e.write(`${n}\n`)}function k(e){return{json:()=>e.length===1?e[0]:e,text:()=>e}}function ge(e){return{json:()=>e.length===1?e[0]:e,text:()=>e.map(ye)}}function _e(e){return{json:()=>e,text:()=>[be(e)]}}function ve(e){return{json:()=>le(e),text:()=>[A(e)]}}function ye(e){if(e.valid){let t=e.version==null?``:` v${e.version}`;return`valid (${e.type}${t})`}return`invalid: ${e.error??`malformed identifier`}`}function be(e){let t=[],n=e.version==null?e.type:`${e.type} (v${e.version})`;return t.push(`Type: ${n}`),e.timestamp&&t.push(`Timestamp: ${e.timestamp}`),e.random&&t.push(`Random: ${e.random}`),e.note&&t.push(`Note: ${e.note}`),t.join(`
3
+ `)}function A(e){return e.hint?`Error: ${e.message}\n ${e.hint}`:`Error: ${e.message}`}const j=l.integer(`count`).pipe(l.withAlias(`n`),l.withDescription(`Number of IDs to generate`),l.withDefault(1)),M=l.boolean(`json`).pipe(l.withDescription(`Output as JSON`),l.withDefault(!1)),N=l.choiceWithValue(`uuid-version`,[[`4`,4],[`7`,7]]).pipe(l.withAlias(`v`),l.withDescription(`UUID version: 4, 7`),l.withDefault(4)),P=l.boolean(`lowercase`).pipe(l.withDescription(`Output in lowercase`),l.withDefault(!1)),F=c.make(`uuid`,{count:j,json:M,version:N,lowercase:P},r.fn(`cli.generate.uuid`)(function*({count:e,json:t,version:n,lowercase:r}){let i=yield*D,a=yield*he({count:e,version:n,lowercase:r});yield*i.write(k(a),{json:t})})).pipe(c.withDescription(`Generate UUIDs (v4 or v7)`),c.withExamples([{command:`uniku uuid -n 5 --json`,description:`Generate 5 UUIDs as a JSON array (machine-readable)`},{command:`uniku uuid -v 7`,description:`Generate a time-sortable UUID v7`},{command:`uniku uuid`,description:`Generate one random UUID v4`}])),xe=l.boolean(`monotonic`).pipe(l.withDescription(`Generate monotonically increasing ULIDs`),l.withDefault(!1)),Se=l.string(`timestamp`).pipe(l.withDescription(`Unix timestamp in milliseconds (or "now")`),l.optional),I=c.make(`ulid`,{count:j,json:M,monotonic:xe,timestamp:Se,lowercase:P},r.fn(`cli.generate.ulid`)(function*({count:e,json:t,monotonic:n,timestamp:r,lowercase:i}){let a=yield*D,s=o.getOrUndefined(r),c=yield*me({count:e,monotonic:n,timestamp:s===void 0?void 0:yield*Ne(s),lowercase:i});yield*a.write(k(c),{json:t})})).pipe(c.withDescription(`Generate ULIDs`),c.withExamples([{command:`uniku ulid -n 10 --monotonic --json`,description:`Generate 10 strictly ordered ULIDs as a JSON array`},{command:`uniku ulid --timestamp 1720000000000`,description:`Generate a ULID for a fixed Unix timestamp (ms)`}])),Ce=l.integer(`size`).pipe(l.withAlias(`s`),l.withDescription(`Length of ID (1-256)`),l.withDefault(21)),we=l.string(`alphabet`).pipe(l.withAlias(`a`),l.withDescription(`Custom alphabet or preset: hex, numeric, alpha`),l.optional),L=c.make(`nanoid`,{count:j,json:M,size:Ce,alphabet:we},r.fn(`cli.generate.nanoid`)(function*({count:e,json:t,size:n,alphabet:r}){let i=yield*D,a=yield*pe({count:e,size:n,alphabet:o.getOrUndefined(r)});yield*i.write(k(a),{json:t})})).pipe(c.withDescription(`Generate Nanoids`),c.withExamples([{command:`uniku nanoid -n 5 --json`,description:`Generate 5 Nanoids as a JSON array`},{command:`uniku nanoid --size 10 --alphabet hex`,description:`Generate a 10-char ID from the hex preset`}])),Te=l.integer(`length`).pipe(l.withAlias(`l`),l.withDescription(`Length of ID (2-32)`),l.withDefault(24)),R=c.make(`cuid`,{count:j,json:M,length:Te},r.fn(`cli.generate.cuid`)(function*({count:e,json:t,length:n}){let r=yield*D,i=yield*ue({count:e,length:n});yield*r.write(k(i),{json:t})})).pipe(c.withDescription(`Generate CUIDs (v2)`),c.withExamples([{command:`uniku cuid -n 5 --json`,description:`Generate 5 CUIDs as a JSON array`},{command:`uniku cuid --length 10`,description:`Generate a 10-char CUID`}])),Ee=l.string(`timestamp`).pipe(l.withDescription(`Unix timestamp in seconds (or "now")`),l.optional),z=c.make(`ksuid`,{count:j,json:M,timestamp:Ee},r.fn(`cli.generate.ksuid`)(function*({count:e,json:t,timestamp:n}){let r=yield*D,i=o.getOrUndefined(n),a=yield*de({count:e,timestamp:i===void 0?void 0:yield*Pe(i)});yield*r.write(k(a),{json:t})})).pipe(c.withDescription(`Generate KSUIDs`),c.withExamples([{command:`uniku ksuid -n 5 --json`,description:`Generate 5 KSUIDs as a JSON array`},{command:`uniku ksuid --timestamp 1720000000`,description:`Generate a KSUID for a fixed Unix timestamp (s)`}])),De=c.make(`generate`).pipe(c.withDescription(`Generate new IDs`),c.withSubcommands([F,I,L,R,z]),c.withExamples([{command:`uniku generate uuid -n 5 --json`,description:`Generate 5 UUIDs as a JSON array`},{command:`uniku generate ulid`,description:"Generate one ULID (subcommands also work top-level: `uniku ulid`)"}])),Oe=F,ke=I,Ae=L,je=R,Me=z,B=r.fn(`cli.generate.parseTimestamp`)(function*(e,t,n){if(e===`now`)return t(yield*u.currentTimeMillis);let r=Number(e);return!Number.isFinite(r)||r<0?yield*new w({code:`INVALID_TIMESTAMP`,message:`Invalid timestamp: "${e}"`,hint:n}):r}),Ne=e=>B(e,e=>e,`Provide a Unix timestamp in milliseconds or "now"`),Pe=e=>B(e,e=>Math.floor(e/1e3),`Provide a Unix timestamp in seconds or "now"`);function Fe(e,t){switch(t){case`uuid`:return Ie(e);case`ulid`:return Le(e);case`ksuid`:return Re(e);case`cuid`:return ze(e);case`nanoid`:return Be(e)}}function V(e){return v.isValid(e)?{id:e,valid:!0,type:`uuid`,version:7}:_.isValid(e)?{id:e,valid:!0,type:`uuid`,version:4}:g.isValid(e)?{id:e,valid:!0,type:`ulid`}:m.isValid(e)?{id:e,valid:!0,type:`ksuid`}:f.isValid(e)?{id:e,valid:!0,type:`cuid`}:h.isValid(e)?{id:e,valid:!0,type:`nanoid`}:{id:e,valid:!1,error:`malformed identifier`}}function Ie(e){return v.isValid(e)?{id:e,valid:!0,type:`uuid`,version:7}:_.isValid(e)?{id:e,valid:!0,type:`uuid`,version:4}:{id:e,valid:!1,type:`uuid`,error:`invalid UUID format`}}function Le(e){return g.isValid(e)?{id:e,valid:!0,type:`ulid`}:{id:e,valid:!1,type:`ulid`,error:`invalid ULID format`}}function Re(e){return m.isValid(e)?{id:e,valid:!0,type:`ksuid`}:{id:e,valid:!1,type:`ksuid`,error:`invalid KSUID format`}}function ze(e){return f.isValid(e)?{id:e,valid:!0,type:`cuid`}:{id:e,valid:!1,type:`cuid`,error:`invalid CUID format`}}function Be(e){return h.isValid(e)?{id:e,valid:!0,type:`nanoid`}:{id:e,valid:!1,type:`nanoid`,error:`invalid Nanoid format`}}function Ve(e,t){let n=t??He(e);if(!n)return null;switch(n){case`uuid`:return Ue(e);case`ulid`:return We(e);case`ksuid`:return Ge(e);case`cuid`:return Ke(e);case`nanoid`:return qe(e)}}function He(e){let t=V(e);return t.valid?t.type??null:null}function Ue(e){if(v.isValid(e)){let t=v.timestamp(e),n=v.toBytes(e),r=Buffer.from(n.slice(10)).toString(`hex`);return{id:e,type:`uuid`,version:7,timestamp:new Date(t).toISOString(),timestamp_ms:t,random:r}}return _.isValid(e)?{id:e,type:`uuid`,version:4,note:`This ID type contains no decodable metadata.`}:{id:e,type:`uuid`,note:`Unrecognized UUID version.`}}function We(e){let t=g.timestamp(e),n=e.slice(10);return{id:e,type:`ulid`,timestamp:new Date(t).toISOString(),timestamp_ms:t,random:n}}function Ge(e){let t=m.timestamp(e),n=m.toBytes(e),r=Buffer.from(n.slice(4)).toString(`hex`);return{id:e,type:`ksuid`,timestamp:new Date(t).toISOString(),timestamp_ms:t,random:r}}function Ke(e){return{id:e,type:`cuid`,note:`This ID type contains no decodable metadata.`}}function qe(e){return{id:e,type:`nanoid`,note:`This ID type contains no decodable metadata.`}}function Je(e){let t=e.indexOf(`--`),n=(t===-1?e:e.slice(0,t)).map(e=>e===`-V`?`--version`:e);if(t===-1)return n;let r=e.slice(t+1);return Qe(n)?[...n,...r.map(Ze)]:[...n,`--`,...r]}const H=`\0uniku-literal:`,Ye=new Set([`inspect`,`validate`]),Xe=new Set([`--completions`,`--log-level`]);function U(e){return e.startsWith(H)?e.slice(15):e}function Ze(e){return`${H}${e}`}function Qe(e){for(let t=0;t<e.length;t+=1){let n=e[t];if(n.startsWith(`-`)){Xe.has(n)&&(t+=1);continue}return Ye.has(n)}return!1}const $e=s.string(`id`).pipe(s.withDescription(`The ID to inspect`)),et=l.choice(`type`,[`uuid`,`ulid`,`nanoid`,`cuid`,`ksuid`]).pipe(l.withDescription(`ID type (auto-detected if omitted)`),l.optional),tt=l.boolean(`json`).pipe(l.withDescription(`Output as JSON`),l.withDefault(!1)),nt=c.make(`inspect`,{id:$e,type:et,json:tt},r.fn(`cli.inspect`)(function*({id:e,type:t,json:n}){let r=yield*D,i=o.getOrUndefined(t),a=U(e),s=Ve(a,i);if(!s)return yield*new w({code:`UNKNOWN_ID_TYPE`,message:`Could not identify ID type for: "${a}"`,hint:`Use --type to specify the ID type`});yield*r.write(_e(s),{json:n})})).pipe(c.withDescription(`Decode and inspect an ID`),c.withExamples([{command:`uniku inspect 01J9YR2V5TZB8Q4W6X0E1N7M3S --json`,description:`Decode an ID to structured JSON (type, version, timestamp)`},{command:`uniku inspect --type uuid 3F2504E0-4F89-41D3-9A0C-0305E82C3301`,description:`Skip auto-detection`},{command:`uniku inspect -- --tricky-id`,description:`Inspect an ID that starts with a dash`}]));var W=class e extends y.Service()(`uniku/cli/StdinService`){static layer=a.succeed(e,e.of({readLines:r.fn(`StdinService.readLines`)(()=>r.callback(e=>{let t=[];process.stdin.on(`data`,e=>{t.push(e)}),process.stdin.on(`end`,()=>{let n=Buffer.concat(t).toString(`utf-8`).split(`
4
+ `).map(e=>e.trim()).filter(e=>e.length>0);e(r.succeed(n))}),process.stdin.on(`error`,t=>{e(r.fail(new w({code:`STDIN_ERROR`,message:t.message})))}),process.stdin.resume()}))}))};const rt=s.string(`id`).pipe(s.withDescription(`The ID to validate`),s.optional),it=l.choice(`type`,[`uuid`,`ulid`,`nanoid`,`cuid`,`ksuid`]).pipe(l.withDescription(`Expected ID type (auto-detected if omitted)`),l.optional),at=l.boolean(`stdin`).pipe(l.withDescription(`Read IDs from stdin (one per line)`),l.withDefault(!1)),ot=l.boolean(`json`).pipe(l.withDescription(`Output validation results as JSON`),l.withDefault(!1)),st=l.boolean(`quiet`).pipe(l.withDescription(`No output, exit code only`),l.withDefault(!1)),ct=c.make(`validate`,{id:rt,type:it,stdin:at,json:ot,quiet:st},r.fn(`cli.validate`)(function*({id:e,type:t,stdin:n,json:r,quiet:i}){let a=yield*D,s=yield*W,c=o.getOrUndefined(t),l;if(n){if(l=yield*s.readLines(),l.length===0)return yield*new w({code:`NO_INPUT`,message:`No IDs provided on stdin`})}else if(o.isSome(e))l=[U(e.value)];else return yield*new w({code:`NO_INPUT`,message:`No ID provided`,hint:`Pass an ID as argument or use --stdin`});let u=l.map(e=>c?Fe(e,c):V(e));if(i||(yield*a.write(ge(u),{json:r})),u.some(e=>!e.valid))return yield*new ce({message:`One or more IDs are invalid`})})).pipe(c.withDescription(`Check if an ID is valid`),c.withExamples([{command:`uniku validate 3F2504E0-4F89-41D3-9A0C-0305E82C3301 --json`,description:`Validate one ID, result as JSON`},{command:`cat ids.txt | uniku validate --stdin --json`,description:`Validate many IDs (one per line), results as a JSON array`},{command:`uniku validate --quiet 01J9YR2V5TZB8Q4W6X0E1N7M3S`,description:`Exit code only: 0 valid, 2 invalid`}])),lt=c.make(`uniku`).pipe(c.withDescription(`Generate and validate unique identifiers`),c.withExamples([{command:`uniku uuid -n 5 --json`,description:`Generate 5 UUIDs as a JSON array (machine-readable)`},{command:`uniku ulid`,description:`Generate one ULID`},{command:`uniku inspect <id> --json`,description:`Decode an ID (type, version, timestamp) as JSON`},{command:`cat ids.txt | uniku validate --stdin --json`,description:`Validate IDs from stdin, one per line`}]),c.withSubcommands([De,ct,nt,Oe,ke,Ae,je,Me])),ut=e=>c.runWith(lt,{version:e});function dt(e){return e.includes(`--json`)}const ft=b.type().pipe(b.tag(`CliError`,e=>e.exitCode),b.tag(`ValidationFailedError`,e=>e.exitCode),b.tag(`ShowHelp`,e=>e.errors.length>0?1:0),b.tag(`UnrecognizedOption`,`DuplicateOption`,`MissingOption`,`MissingArgument`,`InvalidValue`,`UnknownSubcommand`,`UserError`,()=>1),b.exhaustive),pt=r.fn(`cli.handleCliFailure`)(function*(e,t){yield*b.value(e).pipe(b.tag(`CliError`,`ValidationFailedError`,e=>D.use(n=>n.writeError(ve(e),{json:dt(t)}))),b.tag(`ShowHelp`,()=>r.void),b.tag(`UnrecognizedOption`,`DuplicateOption`,`MissingOption`,`MissingArgument`,`InvalidValue`,`UnknownSubcommand`,`UserError`,e=>ee.error(`Error: ${e.message}`)),b.exhaustive),process.exitCode=ft(e)});var G=class e extends y.Service()(`uniku/cli/UpdateCheckService`){static layer=a.sync(e,()=>wt())};const K=`@uniku/cli`;function mt(){let e=process.getuid;if(typeof e==`function`)return`uid-${e()}`;try{let e=oe().username.replace(/[^0-9A-Za-z._-]/g,`_`);return e?`user-${e}`:null}catch{return null}}function ht(){let e=mt(),t=e?`uniku-update-check-${e}.json`:`uniku-update-check.json`;return S(ae(),t)}const gt=ht();function q(e){let t=e.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);return t?{major:Number(t[1]),minor:Number(t[2]),patch:Number(t[3]),prerelease:t[4]??null}:null}function J(e,t){let n=q(e),r=q(t);return!n||!r?!1:n.major===r.major?n.minor===r.minor?n.patch===r.patch?n.prerelease===null&&r.prerelease!==null?!0:(n.prerelease!==null&&r.prerelease,!1):n.patch>r.patch:n.minor>r.minor:n.major>r.major}function Y(e){return C.option(C.string(e)).pipe(r.catch(()=>r.succeed(o.none())))}function X(e){return o.isSome(e)&&e.value.length>0}const _t=r.all({noUpdateNotifier:Y(`NO_UPDATE_NOTIFIER`),ci:Y(`CI`),continuousIntegration:Y(`CONTINUOUS_INTEGRATION`),nodeEnv:Y(`NODE_ENV`)});function vt(e=process.stderr.isTTY){return _t.pipe(r.map(t=>X(t.noUpdateNotifier)||X(t.ci)||X(t.continuousIntegration)||o.isSome(t.nodeEnv)&&t.nodeEnv.value===`test`||!e))}function yt(e,t){if(t){let t=e.isStandaloneBinary?`Download at https://github.com/jkomyno/uniku/releases`:`Run \`npm install -g ${K}\` to update`;return[``,` Update available: ${e.currentVersion} → ${e.latestVersion}`,` ${t}`,` Set NO_UPDATE_NOTIFIER=1 to disable`,``].join(`
5
+ `)}let n=`\x1B[2m`,r=`\x1B[36m`,i=`\x1B[0m`,a=e.isStandaloneBinary?`Download at ${r}https://github.com/jkomyno/uniku/releases${i}`:`Run ${r}\`npm install -g ${K}\`${i} to update`;return[``,` ${n}Update available:${i} ${n}${e.currentVersion}${i} ${n}→${i} ${e.latestVersion}${i}`,` ${a}`,` ${n}Set NO_UPDATE_NOTIFIER=1 to disable${i}`,``].join(`
6
+ `)}function bt(e){return Y(`NO_COLOR`).pipe(r.map(t=>yt(e,X(t))))}function Z(e,t){return o.isSome(t)&&!e.includes(`--json`)}function xt(e){try{let t=ne(e,`utf-8`),n=JSON.parse(t);if(typeof n!=`object`||!n)return null;let r=n;return typeof r.checkedAt!=`number`||!Number.isFinite(r.checkedAt)||r.latestVersion!==void 0&&typeof r.latestVersion!=`string`?null:r.latestVersion===void 0?{checkedAt:r.checkedAt}:{latestVersion:r.latestVersion,checkedAt:r.checkedAt}}catch{return null}}function Q(e,t){try{te(x(t),{recursive:!0});let n=`${t}.tmp`;ie(n,JSON.stringify(e)),re(n,t)}catch{}}function St(e){return r.tryPromise({try:t=>fetch(`https://registry.npmjs.org/%40uniku%2Fcli/latest`,{headers:{Accept:`application/json`,"User-Agent":`${K}/${e}`},signal:AbortSignal.any([t,AbortSignal.timeout(5e3)])}).then(async e=>{if(!e.ok)throw Error(`HTTP ${e.status}`);let t=await e.json();if(!t.version)throw Error(`Missing version field`);return t.version}),catch:()=>Error(`fetch failed`)}).pipe(r.catch(()=>r.succeed(null)))}function Ct(){try{return typeof __STANDALONE_BINARY__<`u`&&__STANDALONE_BINARY__===!0}catch{return!1}}function wt(e={}){let t=e.cacheFile??gt,n=e.fetchLatestVersion??St,i=e.now??Date.now,a=e.isStandaloneBinary??Ct,s=e.isStderrTTY??(()=>process.stderr.isTTY),c=e.writeStderr??(e=>process.stderr.write(e));return G.of({check:r.fn(`UpdateCheckService.check`)(function*(e){if(yield*vt(s()))return o.none();let r=xt(t),c=i();if(r&&c-r.checkedAt<864e5)return r.latestVersion&&J(r.latestVersion,e)?o.some({currentVersion:e,latestVersion:r.latestVersion,isStandaloneBinary:a()}):o.none();let l=yield*n(e);return l===null?(Q({checkedAt:c},t),o.none()):(Q({latestVersion:l,checkedAt:c},t),J(l,e)?o.some({currentVersion:e,latestVersion:l,isStandaloneBinary:a()}):o.none())},r.catch(()=>r.succeed(o.none()))),notify:r.fn(`UpdateCheckService.notify`)(function*(e){let t=yield*bt(e);yield*r.sync(()=>{c(t)})})})}var $=`0.1.0`;const Tt=ut($),Et=a.mergeAll(D.layer,W.layer,G.layer,t.layer);r.gen(function*(){let e=yield*G,t=Je(process.argv.slice(2)),a=yield*r.forkChild(e.check($),{startImmediately:!0});yield*Tt(t).pipe(r.catch(e=>pt(e,t)));let s=yield*i.join(a).pipe(r.timeoutOption(n.millis(250)));yield*i.interrupt(a);let c=o.flatten(s);Z(t,c)&&(yield*e.notify(c.value))}).pipe(r.provide(Et),e.runMain);export{};
6
7
  //# sourceMappingURL=bin.mjs.map
package/build/bin.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.mjs","names":["NANOID_ALPHABET_PRESETS: Record<string, string>","code: string","hint?: string","exitCode: number","obj: { error: string; code: string; hint?: string }","ids: string[]","ids: string[]","ids: string[]","ids: string[]","ids: string[]","lines: string[]","jsonOption","idArg","typeOption","jsonOption","chunks: Buffer[]","type: IdType | undefined","ids: readonly string[]","results: ValidationResult[]","version","updateCmd","pkg.version"],"sources":["../src/domain/constants.ts","../src/domain/errors.ts","../src/generators/cuid.ts","../src/generators/ksuid.ts","../src/generators/nanoid.ts","../src/generators/ulid.ts","../src/generators/uuid.ts","../src/services/OutputService.ts","../src/commands/generate.cmd.ts","../src/validators/validate.ts","../src/inspectors/inspect.ts","../src/commands/inspect.cmd.ts","../src/services/StdinService.ts","../src/commands/validate.cmd.ts","../src/commands/index.ts","../src/services/UpdateCheckService.ts","../package.json","../src/bin.ts"],"sourcesContent":["/** Default count for ID generation. */\nexport const COUNT_DEFAULT = 1\n\n/** Valid UUID versions. */\nexport const UUID_VERSIONS = [4, 7] as const\n\n/** Default UUID version. */\nexport const UUID_VERSION_DEFAULT = 4\n\n/** Default nanoid size. */\nexport const NANOID_SIZE_DEFAULT = 21\n\n/** Nanoid size range. */\nexport const NANOID_SIZE_MIN = 1\nexport const NANOID_SIZE_MAX = 256\n\n/** Default CUID2 length. */\nexport const CUID_LENGTH_DEFAULT = 24\n\n/** CUID2 length range. */\nexport const CUID_LENGTH_MIN = 2\nexport const CUID_LENGTH_MAX = 32\n\n/** Nanoid alphabet presets. */\nexport const NANOID_ALPHABET_PRESETS: Record<string, string> = {\n hex: '0123456789abcdef',\n numeric: '0123456789',\n alpha: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',\n}\n\n/** Environment variable for default generate type. */\nexport const ENV_DEFAULT_TYPE = 'UNIKU_DEFAULT_TYPE'\n","import type { UniqueIdError } from 'uniku/errors'\n\n/**\n * Structured CLI error with optional hint and exit code.\n */\nexport class CliError extends Error {\n constructor(\n readonly code: string,\n message: string,\n readonly hint?: string,\n readonly exitCode: number = 1,\n ) {\n super(message)\n this.name = 'CliError'\n }\n}\n\n/**\n * Error indicating validation failure (exit code 2).\n */\nexport class ValidationFailedError extends CliError {\n constructor(message: string) {\n super('VALIDATION_FAILED', message, undefined, 2)\n this.name = 'ValidationFailedError'\n }\n}\n\n/**\n * Maps a uniku library error into a CliError, preserving code and message.\n */\nexport function fromUnikuError(err: UniqueIdError): CliError {\n return new CliError(err.code, err.message)\n}\n\n/**\n * Converts a CliError to a JSON-serializable object for stderr output.\n */\nexport function errorToJson(err: CliError): { error: string; code: string; hint?: string } {\n const obj: { error: string; code: string; hint?: string } = {\n error: err.message,\n code: err.code,\n }\n if (err.hint) {\n obj.hint = err.hint\n }\n return obj\n}\n","import * as Effect from 'effect/Effect'\nimport { cuid2 } from 'uniku/cuid2'\nimport { UniqueIdError } from 'uniku/errors'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type CuidGenerateOptions = {\n readonly count: number\n readonly length: number\n}\n\nexport function generateCuid(options: CuidGenerateOptions): Effect.Effect<string[], CliError> {\n return Effect.try({\n try: () => {\n const ids: string[] = []\n for (let i = 0; i < options.count; i++) {\n ids.push(cuid2({ length: options.length }))\n }\n return ids\n },\n catch: (err) => {\n if (err instanceof UniqueIdError) return fromUnikuError(err)\n return new CliError('GENERATE_FAILED', String(err))\n },\n })\n}\n","import * as Effect from 'effect/Effect'\nimport { UniqueIdError } from 'uniku/errors'\nimport { ksuid } from 'uniku/ksuid'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type KsuidGenerateOptions = {\n readonly count: number\n readonly timestamp?: number\n}\n\nexport function generateKsuid(options: KsuidGenerateOptions): Effect.Effect<string[], CliError> {\n return Effect.try({\n try: () => {\n const ids: string[] = []\n for (let i = 0; i < options.count; i++) {\n const ksuidOpts = options.timestamp != null ? { secs: options.timestamp } : undefined\n ids.push(ksuid(ksuidOpts))\n }\n return ids\n },\n catch: (err) => {\n if (err instanceof UniqueIdError) return fromUnikuError(err)\n return new CliError('GENERATE_FAILED', String(err))\n },\n })\n}\n","import * as Effect from 'effect/Effect'\nimport { UniqueIdError } from 'uniku/errors'\nimport { nanoid } from 'uniku/nanoid'\nimport { NANOID_ALPHABET_PRESETS } from '@/src/domain/constants'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type NanoidGenerateOptions = {\n readonly count: number\n readonly size: number\n readonly alphabet?: string\n}\n\nfunction resolveAlphabet(input?: string): string | undefined {\n if (!input) return undefined\n return NANOID_ALPHABET_PRESETS[input] ?? input\n}\n\nexport function generateNanoid(options: NanoidGenerateOptions): Effect.Effect<string[], CliError> {\n return Effect.try({\n try: () => {\n const alphabet = resolveAlphabet(options.alphabet)\n const ids: string[] = []\n for (let i = 0; i < options.count; i++) {\n ids.push(nanoid({ size: options.size, alphabet }))\n }\n return ids\n },\n catch: (err) => {\n if (err instanceof UniqueIdError) return fromUnikuError(err)\n return new CliError('GENERATE_FAILED', String(err))\n },\n })\n}\n","import * as Effect from 'effect/Effect'\nimport { UniqueIdError } from 'uniku/errors'\nimport { ulid } from 'uniku/ulid'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type UlidGenerateOptions = {\n readonly count: number\n readonly monotonic: boolean\n readonly timestamp?: number\n readonly lowercase: boolean\n}\n\nexport function generateUlid(options: UlidGenerateOptions): Effect.Effect<string[], CliError> {\n if (options.monotonic && options.timestamp != null) {\n return Effect.fail(\n new CliError(\n 'INVALID_OPTIONS',\n '--monotonic and --timestamp are mutually exclusive',\n 'Use --monotonic for monotonically increasing ULIDs, or --timestamp to specify a fixed timestamp',\n ),\n )\n }\n\n return Effect.try({\n try: () => {\n const ids: string[] = []\n for (let i = 0; i < options.count; i++) {\n const ulidOpts = options.timestamp != null ? { msecs: options.timestamp } : undefined\n let id = ulid(ulidOpts)\n if (options.lowercase) {\n id = id.toLowerCase()\n }\n ids.push(id)\n }\n return ids\n },\n catch: (err) => {\n if (err instanceof UniqueIdError) return fromUnikuError(err)\n return new CliError('GENERATE_FAILED', String(err))\n },\n })\n}\n","import * as Effect from 'effect/Effect'\nimport { UniqueIdError } from 'uniku/errors'\nimport { uuidv4 } from 'uniku/uuid/v4'\nimport { uuidv7 } from 'uniku/uuid/v7'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type UuidGenerateOptions = {\n readonly count: number\n readonly version: number\n readonly lowercase: boolean\n}\n\nexport function generateUuid(options: UuidGenerateOptions): Effect.Effect<string[], CliError> {\n return Effect.try({\n try: () => {\n const gen = options.version === 7 ? uuidv7 : uuidv4\n const ids: string[] = []\n for (let i = 0; i < options.count; i++) {\n let id = gen()\n if (options.lowercase) {\n id = id.toLowerCase()\n }\n ids.push(id)\n }\n return ids\n },\n catch: (err) => {\n if (err instanceof UniqueIdError) return fromUnikuError(err)\n return new CliError('GENERATE_FAILED', String(err))\n },\n })\n}\n","import * as Context from 'effect/Context'\nimport * as Effect from 'effect/Effect'\nimport { type CliError, errorToJson } from '@/src/domain/errors'\nimport type { InspectResult, ValidationResult } from '@/src/domain/types'\n\nexport type OutputOptions = {\n readonly json?: boolean\n readonly quiet?: boolean\n}\n\nexport class OutputService extends Context.Tag('OutputService')<\n OutputService,\n {\n readonly writeIds: (ids: readonly string[], options: OutputOptions) => Effect.Effect<void>\n readonly writeValidation: (results: readonly ValidationResult[], options: OutputOptions) => Effect.Effect<void>\n readonly writeInspect: (result: InspectResult, options: OutputOptions) => Effect.Effect<void>\n readonly writeError: (error: CliError, options: OutputOptions) => Effect.Effect<void>\n }\n>() {}\n\nfunction formatValidationHuman(result: ValidationResult): string {\n if (result.valid) {\n const parts = [`valid (${result.type}`]\n if (result.version != null) {\n parts.push(` v${result.version}`)\n }\n parts.push(')')\n return parts.join('')\n }\n return `invalid: ${result.error ?? 'malformed identifier'}`\n}\n\nfunction formatInspectHuman(result: InspectResult): string {\n const lines: string[] = []\n const typeLabel = result.version != null ? `${result.type} (v${result.version})` : result.type\n lines.push(`Type: ${typeLabel}`)\n if (result.timestamp) {\n lines.push(`Timestamp: ${result.timestamp}`)\n }\n if (result.random) {\n lines.push(`Random: ${result.random}`)\n }\n if (result.note) {\n lines.push(`Note: ${result.note}`)\n }\n return lines.join('\\n')\n}\n\n/**\n * Default implementation writing to process.stdout / process.stderr.\n */\nexport const OutputServiceLive = OutputService.of({\n writeIds(ids, options) {\n return Effect.sync(() => {\n if (options.json) {\n const out = ids.length === 1 ? JSON.stringify(ids[0]) : JSON.stringify(ids)\n process.stdout.write(`${out}\\n`)\n } else {\n for (const id of ids) {\n process.stdout.write(`${id}\\n`)\n }\n }\n })\n },\n\n writeValidation(results, options) {\n return Effect.sync(() => {\n if (options.quiet) return\n\n if (options.json) {\n const out = results.length === 1 ? JSON.stringify(results[0]) : JSON.stringify(results)\n process.stdout.write(`${out}\\n`)\n } else {\n for (const result of results) {\n process.stdout.write(`${formatValidationHuman(result)}\\n`)\n }\n }\n })\n },\n\n writeInspect(result, options) {\n return Effect.sync(() => {\n if (options.json) {\n process.stdout.write(`${JSON.stringify(result)}\\n`)\n } else {\n process.stdout.write(`${formatInspectHuman(result)}\\n`)\n }\n })\n },\n\n writeError(error, options) {\n return Effect.sync(() => {\n if (options.json) {\n process.stderr.write(`${JSON.stringify(errorToJson(error))}\\n`)\n } else {\n let msg = `Error: ${error.message}`\n if (error.hint) {\n msg += `\\n ${error.hint}`\n }\n process.stderr.write(`${msg}\\n`)\n }\n })\n },\n})\n","import { Command, Options } from '@effect/cli'\nimport * as Effect from 'effect/Effect'\nimport * as Option from 'effect/Option'\nimport { COUNT_DEFAULT, CUID_LENGTH_DEFAULT, NANOID_SIZE_DEFAULT, UUID_VERSION_DEFAULT } from '@/src/domain/constants'\nimport { CliError } from '@/src/domain/errors'\nimport { generateCuid } from '@/src/generators/cuid'\nimport { generateKsuid } from '@/src/generators/ksuid'\nimport { generateNanoid } from '@/src/generators/nanoid'\nimport { generateUlid } from '@/src/generators/ulid'\nimport { generateUuid } from '@/src/generators/uuid'\nimport { OutputService } from '@/src/services/OutputService'\n\n// ── Common options ──────────────────────────────────────────────────\n\nconst countOption = Options.integer('count').pipe(\n Options.withAlias('n'),\n Options.withDescription('Number of IDs to generate'),\n Options.withDefault(COUNT_DEFAULT),\n)\n\nconst jsonOption = Options.boolean('json').pipe(Options.withDescription('Output as JSON'), Options.withDefault(false))\n\n// ── UUID subcommand ─────────────────────────────────────────────────\n\nconst uuidVersionOption = Options.choiceWithValue('version', [\n ['4', 4],\n ['7', 7],\n] as const).pipe(\n Options.withAlias('v'),\n Options.withDescription('UUID version: 4, 7'),\n Options.withDefault(UUID_VERSION_DEFAULT as 4 | 7),\n)\n\nconst lowercaseOption = Options.boolean('lowercase').pipe(\n Options.withAlias('l'),\n Options.withDescription('Output in lowercase'),\n Options.withDefault(false),\n)\n\nconst uuidSubcommand = Command.make(\n 'uuid',\n {\n count: countOption,\n json: jsonOption,\n version: uuidVersionOption,\n lowercase: lowercaseOption,\n },\n ({ count, json, version, lowercase }) =>\n Effect.gen(function* () {\n const output = yield* OutputService\n const ids = yield* generateUuid({ count, version, lowercase })\n yield* output.writeIds(ids, { json })\n }),\n).pipe(Command.withDescription('Generate UUIDs (v4 or v7)'))\n\n// ── ULID subcommand ─────────────────────────────────────────────────\n\nconst monotonicOption = Options.boolean('monotonic').pipe(\n Options.withDescription('Generate monotonically increasing ULIDs'),\n Options.withDefault(false),\n)\n\nconst ulidTimestampOption = Options.text('timestamp').pipe(\n Options.withDescription('Unix timestamp in milliseconds (or \"now\")'),\n Options.optional,\n)\n\nconst ulidSubcommand = Command.make(\n 'ulid',\n {\n count: countOption,\n json: jsonOption,\n monotonic: monotonicOption,\n timestamp: ulidTimestampOption,\n lowercase: lowercaseOption,\n },\n ({ count, json, monotonic, timestamp: timestampOpt, lowercase }) =>\n Effect.gen(function* () {\n const output = yield* OutputService\n const timestamp = Option.isSome(timestampOpt) ? parseTimestampMs(Option.getOrThrow(timestampOpt)) : undefined\n const ids = yield* generateUlid({ count, monotonic, timestamp, lowercase })\n yield* output.writeIds(ids, { json })\n }),\n).pipe(Command.withDescription('Generate ULIDs'))\n\n// ── Nanoid subcommand ───────────────────────────────────────────────\n\nconst sizeOption = Options.integer('size').pipe(\n Options.withAlias('s'),\n Options.withDescription('Length of ID (1-256)'),\n Options.withDefault(NANOID_SIZE_DEFAULT),\n)\n\nconst alphabetOption = Options.text('alphabet').pipe(\n Options.withAlias('a'),\n Options.withDescription('Custom alphabet or preset: hex, numeric, alpha'),\n Options.optional,\n)\n\nconst nanoidSubcommand = Command.make(\n 'nanoid',\n {\n count: countOption,\n json: jsonOption,\n size: sizeOption,\n alphabet: alphabetOption,\n },\n ({ count, json, size, alphabet: alphabetOpt }) =>\n Effect.gen(function* () {\n const output = yield* OutputService\n const alphabet = Option.isSome(alphabetOpt) ? Option.getOrThrow(alphabetOpt) : undefined\n const ids = yield* generateNanoid({ count, size, alphabet })\n yield* output.writeIds(ids, { json })\n }),\n).pipe(Command.withDescription('Generate Nanoids'))\n\n// ── CUID subcommand ─────────────────────────────────────────────────\n\nconst lengthOption = Options.integer('length').pipe(\n Options.withAlias('l'),\n Options.withDescription('Length of ID (2-32)'),\n Options.withDefault(CUID_LENGTH_DEFAULT),\n)\n\nconst cuidSubcommand = Command.make(\n 'cuid',\n {\n count: countOption,\n json: jsonOption,\n length: lengthOption,\n },\n ({ count, json, length }) =>\n Effect.gen(function* () {\n const output = yield* OutputService\n const ids = yield* generateCuid({ count, length })\n yield* output.writeIds(ids, { json })\n }),\n).pipe(Command.withDescription('Generate CUIDs (v2)'))\n\n// ── KSUID subcommand ────────────────────────────────────────────────\n\nconst ksuidTimestampOption = Options.text('timestamp').pipe(\n Options.withDescription('Unix timestamp in seconds (or \"now\")'),\n Options.optional,\n)\n\nconst ksuidSubcommand = Command.make(\n 'ksuid',\n {\n count: countOption,\n json: jsonOption,\n timestamp: ksuidTimestampOption,\n },\n ({ count, json, timestamp: timestampOpt }) =>\n Effect.gen(function* () {\n const output = yield* OutputService\n const timestamp = Option.isSome(timestampOpt) ? parseTimestampSecs(Option.getOrThrow(timestampOpt)) : undefined\n const ids = yield* generateKsuid({ count, timestamp })\n yield* output.writeIds(ids, { json })\n }),\n).pipe(Command.withDescription('Generate KSUIDs'))\n\n// ── Generate parent command ─────────────────────────────────────────\n\nexport const generateCommand = Command.make('generate').pipe(\n Command.withDescription('Generate new IDs'),\n Command.withSubcommands([uuidSubcommand, ulidSubcommand, nanoidSubcommand, cuidSubcommand, ksuidSubcommand]),\n)\n\n// ── Shorthand commands (top-level: `uniku uuid`, `uniku ulid`, etc.) ─\n\nexport const uuidShorthand = uuidSubcommand\nexport const ulidShorthand = ulidSubcommand\nexport const nanoidShorthand = nanoidSubcommand\nexport const cuidShorthand = cuidSubcommand\nexport const ksuidShorthand = ksuidSubcommand\n\n// ── Helpers ─────────────────────────────────────────────────────────\n\nfunction parseTimestampMs(input: string): number {\n if (input === 'now') return Date.now()\n const n = Number(input)\n if (!Number.isFinite(n) || n < 0) {\n throw new CliError(\n 'INVALID_TIMESTAMP',\n `Invalid timestamp: \"${input}\"`,\n 'Provide a Unix timestamp in milliseconds or \"now\"',\n )\n }\n return n\n}\n\nfunction parseTimestampSecs(input: string): number {\n if (input === 'now') return Math.floor(Date.now() / 1000)\n const n = Number(input)\n if (!Number.isFinite(n) || n < 0) {\n throw new CliError(\n 'INVALID_TIMESTAMP',\n `Invalid timestamp: \"${input}\"`,\n 'Provide a Unix timestamp in seconds or \"now\"',\n )\n }\n return n\n}\n","import { cuid2 } from 'uniku/cuid2'\nimport { ksuid } from 'uniku/ksuid'\nimport { nanoid } from 'uniku/nanoid'\nimport { ulid } from 'uniku/ulid'\nimport { uuidv4 } from 'uniku/uuid/v4'\nimport { uuidv7 } from 'uniku/uuid/v7'\nimport type { IdType, ValidationResult } from '@/src/domain/types'\n\n/**\n * Validate a single ID against a specific type.\n */\nexport function validateAs(id: string, type: IdType): ValidationResult {\n switch (type) {\n case 'uuid':\n return validateUuid(id)\n case 'ulid':\n return validateUlid(id)\n case 'ksuid':\n return validateKsuid(id)\n case 'cuid':\n return validateCuid(id)\n case 'nanoid':\n return validateNanoid(id)\n }\n}\n\n/**\n * Auto-detect ID type and validate.\n * Detection order: UUID > ULID > KSUID > CUID > Nanoid.\n */\nexport function validateAutoDetect(id: string): ValidationResult {\n // 1. UUID (36 chars, 8-4-4-4-12 format with hyphens)\n if (uuidv7.isValid(id)) {\n return { id, valid: true, type: 'uuid', version: 7 }\n }\n if (uuidv4.isValid(id)) {\n return { id, valid: true, type: 'uuid', version: 4 }\n }\n\n // 2. ULID (26 chars, Crockford Base32)\n if (ulid.isValid(id)) {\n return { id, valid: true, type: 'ulid' }\n }\n\n // 3. KSUID (27 chars, Base62)\n if (ksuid.isValid(id)) {\n return { id, valid: true, type: 'ksuid' }\n }\n\n // 4. CUID (starts with letter, Base36)\n if (cuid2.isValid(id)) {\n return { id, valid: true, type: 'cuid' }\n }\n\n // 5. Nanoid (fallback: URL-safe A-Za-z0-9_- and length 1-256)\n if (nanoid.isValid(id)) {\n return { id, valid: true, type: 'nanoid' }\n }\n\n return { id, valid: false, error: 'malformed identifier' }\n}\n\nfunction validateUuid(id: string): ValidationResult {\n if (uuidv7.isValid(id)) {\n return { id, valid: true, type: 'uuid', version: 7 }\n }\n if (uuidv4.isValid(id)) {\n return { id, valid: true, type: 'uuid', version: 4 }\n }\n return { id, valid: false, type: 'uuid', error: 'invalid UUID format' }\n}\n\nfunction validateUlid(id: string): ValidationResult {\n if (ulid.isValid(id)) {\n return { id, valid: true, type: 'ulid' }\n }\n return { id, valid: false, type: 'ulid', error: 'invalid ULID format' }\n}\n\nfunction validateKsuid(id: string): ValidationResult {\n if (ksuid.isValid(id)) {\n return { id, valid: true, type: 'ksuid' }\n }\n return { id, valid: false, type: 'ksuid', error: 'invalid KSUID format' }\n}\n\nfunction validateCuid(id: string): ValidationResult {\n if (cuid2.isValid(id)) {\n return { id, valid: true, type: 'cuid' }\n }\n return { id, valid: false, type: 'cuid', error: 'invalid CUID format' }\n}\n\nfunction validateNanoid(id: string): ValidationResult {\n if (nanoid.isValid(id)) {\n return { id, valid: true, type: 'nanoid' }\n }\n return { id, valid: false, type: 'nanoid', error: 'invalid Nanoid format' }\n}\n","import { ksuid } from 'uniku/ksuid'\nimport { ulid } from 'uniku/ulid'\nimport { uuidv4 } from 'uniku/uuid/v4'\nimport { uuidv7 } from 'uniku/uuid/v7'\nimport type { IdType, InspectResult } from '@/src/domain/types'\nimport { validateAutoDetect } from '@/src/validators/validate'\n\n/**\n * Inspect an ID and extract metadata.\n * If type is not provided, auto-detect is used.\n */\nexport function inspectId(id: string, type?: IdType): InspectResult | null {\n const resolvedType = type ?? detectType(id)\n if (!resolvedType) return null\n\n switch (resolvedType) {\n case 'uuid':\n return inspectUuid(id)\n case 'ulid':\n return inspectUlid(id)\n case 'ksuid':\n return inspectKsuid(id)\n case 'cuid':\n return inspectCuid(id)\n case 'nanoid':\n return inspectNanoid(id)\n }\n}\n\nfunction detectType(id: string): IdType | null {\n const result = validateAutoDetect(id)\n return result.valid ? (result.type ?? null) : null\n}\n\nfunction inspectUuid(id: string): InspectResult {\n if (uuidv7.isValid(id)) {\n const ms = uuidv7.timestamp(id)\n const bytes = uuidv7.toBytes(id)\n // Random component: last 6 bytes (bytes 10-15)\n const random = Buffer.from(bytes.slice(10)).toString('hex')\n return {\n id,\n type: 'uuid',\n version: 7,\n timestamp: new Date(ms).toISOString(),\n timestamp_ms: ms,\n random,\n }\n }\n\n if (uuidv4.isValid(id)) {\n return {\n id,\n type: 'uuid',\n version: 4,\n note: 'This ID type contains no decodable metadata.',\n }\n }\n\n return {\n id,\n type: 'uuid',\n note: 'Unrecognized UUID version.',\n }\n}\n\nfunction inspectUlid(id: string): InspectResult {\n const ms = ulid.timestamp(id)\n // Random component: last 16 chars of the 26-char ULID\n const random = id.slice(10)\n return {\n id,\n type: 'ulid',\n timestamp: new Date(ms).toISOString(),\n timestamp_ms: ms,\n random,\n }\n}\n\nfunction inspectKsuid(id: string): InspectResult {\n const ms = ksuid.timestamp(id)\n const bytes = ksuid.toBytes(id)\n // Random payload: last 16 bytes (bytes 4-19)\n const random = Buffer.from(bytes.slice(4)).toString('hex')\n return {\n id,\n type: 'ksuid',\n timestamp: new Date(ms).toISOString(),\n timestamp_ms: ms,\n random,\n }\n}\n\nfunction inspectCuid(id: string): InspectResult {\n return {\n id,\n type: 'cuid',\n note: 'This ID type contains no decodable metadata.',\n }\n}\n\nfunction inspectNanoid(id: string): InspectResult {\n return {\n id,\n type: 'nanoid',\n note: 'This ID type contains no decodable metadata.',\n }\n}\n","import { Args, Command, Options } from '@effect/cli'\nimport * as Effect from 'effect/Effect'\nimport * as Option from 'effect/Option'\nimport { CliError } from '@/src/domain/errors'\nimport type { IdType } from '@/src/domain/types'\nimport { inspectId } from '@/src/inspectors/inspect'\nimport { OutputService } from '@/src/services/OutputService'\n\nconst idArg = Args.text({ name: 'id' }).pipe(Args.withDescription('The ID to inspect'))\n\nconst typeOption = Options.choice('type', ['uuid', 'ulid', 'nanoid', 'cuid', 'ksuid'] as const).pipe(\n Options.withDescription('ID type (auto-detected if omitted)'),\n Options.optional,\n)\n\nconst jsonOption = Options.boolean('json').pipe(Options.withDescription('Output as JSON'), Options.withDefault(false))\n\nexport const inspectCommand = Command.make(\n 'inspect',\n {\n id: idArg,\n type: typeOption,\n json: jsonOption,\n },\n ({ id, type: typeOpt, json }) =>\n Effect.gen(function* () {\n const output = yield* OutputService\n const type: IdType | undefined = Option.isSome(typeOpt) ? Option.getOrThrow(typeOpt) : undefined\n\n const result = inspectId(id, type)\n if (!result) {\n yield* Effect.fail(\n new CliError(\n 'UNKNOWN_ID_TYPE',\n `Could not identify ID type for: \"${id}\"`,\n 'Use --type to specify the ID type',\n ),\n )\n return\n }\n\n yield* output.writeInspect(result, { json })\n }),\n).pipe(Command.withDescription('Decode and inspect an ID'))\n","import * as Context from 'effect/Context'\nimport * as Effect from 'effect/Effect'\nimport { CliError } from '@/src/domain/errors'\n\nexport class StdinService extends Context.Tag('StdinService')<\n StdinService,\n {\n readonly readLines: () => Effect.Effect<readonly string[], CliError>\n }\n>() {}\n\n/**\n * Reads all lines from process.stdin until EOF.\n * Filters out empty lines.\n */\nexport const StdinServiceLive = StdinService.of({\n readLines() {\n return Effect.async<readonly string[], CliError>((resume) => {\n const chunks: Buffer[] = []\n\n process.stdin.on('data', (chunk: Buffer) => {\n chunks.push(chunk)\n })\n\n process.stdin.on('end', () => {\n const text = Buffer.concat(chunks).toString('utf-8')\n const lines = text\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n resume(Effect.succeed(lines))\n })\n\n process.stdin.on('error', (err) => {\n resume(Effect.fail(new CliError('STDIN_ERROR', err.message)))\n })\n\n process.stdin.resume()\n })\n },\n})\n","import { Args, Command, Options } from '@effect/cli'\nimport * as Effect from 'effect/Effect'\nimport * as Option from 'effect/Option'\nimport { CliError, ValidationFailedError } from '@/src/domain/errors'\nimport type { IdType, ValidationResult } from '@/src/domain/types'\nimport { OutputService } from '@/src/services/OutputService'\nimport { StdinService } from '@/src/services/StdinService'\nimport { validateAs, validateAutoDetect } from '@/src/validators/validate'\n\nconst idArg = Args.text({ name: 'id' }).pipe(Args.withDescription('The ID to validate'), Args.optional)\n\nconst typeOption = Options.choice('type', ['uuid', 'ulid', 'nanoid', 'cuid', 'ksuid'] as const).pipe(\n Options.withDescription('Expected ID type (auto-detected if omitted)'),\n Options.optional,\n)\n\nconst stdinOption = Options.boolean('stdin').pipe(\n Options.withDescription('Read IDs from stdin (one per line)'),\n Options.withDefault(false),\n)\n\nconst jsonOption = Options.boolean('json').pipe(\n Options.withDescription('Output validation results as JSON'),\n Options.withDefault(false),\n)\n\nconst quietOption = Options.boolean('quiet').pipe(\n Options.withDescription('No output, exit code only'),\n Options.withDefault(false),\n)\n\nexport const validateCommand = Command.make(\n 'validate',\n {\n id: idArg,\n type: typeOption,\n stdin: stdinOption,\n json: jsonOption,\n quiet: quietOption,\n },\n ({ id: idOpt, type: typeOpt, stdin, json, quiet }) =>\n Effect.gen(function* () {\n const output = yield* OutputService\n const stdinService = yield* StdinService\n const type: IdType | undefined = Option.isSome(typeOpt) ? Option.getOrThrow(typeOpt) : undefined\n\n let ids: readonly string[]\n\n if (stdin) {\n ids = yield* stdinService.readLines()\n if (ids.length === 0) {\n yield* Effect.fail(new CliError('NO_INPUT', 'No IDs provided on stdin'))\n return\n }\n } else if (Option.isSome(idOpt)) {\n ids = [Option.getOrThrow(idOpt)]\n } else {\n yield* Effect.fail(new CliError('NO_INPUT', 'No ID provided', 'Pass an ID as argument or use --stdin'))\n return\n }\n\n const results: ValidationResult[] = ids.map((id) => (type ? validateAs(id, type) : validateAutoDetect(id)))\n\n yield* output.writeValidation(results, { json, quiet })\n\n const hasInvalid = results.some((r) => !r.valid)\n if (hasInvalid) {\n yield* Effect.fail(new ValidationFailedError('One or more IDs are invalid'))\n }\n }),\n).pipe(Command.withDescription('Check if an ID is valid'))\n","import { Command } from '@effect/cli'\nimport {\n cuidShorthand,\n generateCommand,\n ksuidShorthand,\n nanoidShorthand,\n ulidShorthand,\n uuidShorthand,\n} from '@/src/commands/generate.cmd'\nimport { inspectCommand } from '@/src/commands/inspect.cmd'\nimport { validateCommand } from '@/src/commands/validate.cmd'\n\n// ── Root command ────────────────────────────────────────────────────\n\nexport const rootCommand = Command.make('uniku').pipe(\n Command.withDescription('Generate and validate unique identifiers'),\n Command.withSubcommands([\n generateCommand,\n validateCommand,\n inspectCommand,\n // Shorthand commands: `uniku uuid` = `uniku generate uuid`\n uuidShorthand,\n ulidShorthand,\n nanoidShorthand,\n cuidShorthand,\n ksuidShorthand,\n ]),\n)\n\n// ── CLI runner (reusable for testing) ───────────────────────────────\n\nexport const makeCliRunner = (version: string) =>\n Command.run(rootCommand, {\n name: 'uniku',\n version,\n })\n","import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport * as Context from 'effect/Context'\nimport * as Effect from 'effect/Effect'\nimport * as Option from 'effect/Option'\n\n// ── Types ────────────────────────────────────────────────────────────\n\nexport interface UpdateInfo {\n readonly currentVersion: string\n readonly latestVersion: string\n readonly isStandaloneBinary: boolean\n}\n\ninterface UpdateCache {\n readonly latestVersion: string\n readonly checkedAt: number\n}\n\n// ── Service tag ──────────────────────────────────────────────────────\n\nexport class UpdateCheckService extends Context.Tag('UpdateCheckService')<\n UpdateCheckService,\n {\n /** Check for available updates. Returns Some(info) if update available, None otherwise. */\n readonly check: (currentVersion: string) => Effect.Effect<Option.Option<UpdateInfo>>\n /** Print the update notification to stderr. */\n readonly notify: (info: UpdateInfo) => Effect.Effect<void>\n }\n>() {}\n\n// ── Constants ────────────────────────────────────────────────────────\n\nconst PACKAGE_NAME = '@uniku/cli'\nconst REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}/latest`\nconst CACHE_FILE = join(tmpdir(), 'uniku-update-check.json')\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours\nconst FETCH_TIMEOUT_MS = 5_000\n\n// ── Version comparison ───────────────────────────────────────────────\n\n/**\n * Parse a semver version string into its components.\n * Returns null if the string is not a valid semver.\n */\nexport function parseSemver(version: string) {\n const match = version.match(/^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-(.+))?$/)\n if (!match) return null\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: match[4] ?? null,\n }\n}\n\n/**\n * Returns true if `latest` is newer than `current`.\n *\n * Handles pre-release correctly:\n * - 1.0.0 > 1.0.0-beta.1 (stable is newer than pre-release of same version)\n * - 1.0.0-beta.1 > 0.9.0 (pre-release of higher version is newer)\n */\nexport function isNewerVersion(latest: string, current: string): boolean {\n const l = parseSemver(latest)\n const c = parseSemver(current)\n if (!l || !c) return false\n\n if (l.major !== c.major) return l.major > c.major\n if (l.minor !== c.minor) return l.minor > c.minor\n if (l.patch !== c.patch) return l.patch > c.patch\n\n // Same major.minor.patch — stable (no prerelease) beats pre-release\n if (l.prerelease === null && c.prerelease !== null) return true\n if (l.prerelease !== null && c.prerelease === null) return false\n\n return false\n}\n\n// ── Skip conditions ──────────────────────────────────────────────────\n\nexport function shouldSkipUpdateCheck(): boolean {\n return (\n !!process.env.NO_UPDATE_NOTIFIER ||\n !!process.env.CI ||\n !!process.env.CONTINUOUS_INTEGRATION ||\n process.env.NODE_ENV === 'test' ||\n !process.stderr.isTTY\n )\n}\n\n// ── Notification formatting ──────────────────────────────────────────\n\nexport function formatNotification(info: UpdateInfo): string {\n const noColor = !!process.env.NO_COLOR\n\n if (noColor) {\n const updateCmd = info.isStandaloneBinary\n ? `Download at https://github.com/jkomyno/uniku/releases`\n : `Run \\`npm install -g ${PACKAGE_NAME}\\` to update`\n return [\n '',\n ` Update available: ${info.currentVersion} → ${info.latestVersion}`,\n ` ${updateCmd}`,\n ` Set NO_UPDATE_NOTIFIER=1 to disable`,\n '',\n ].join('\\n')\n }\n\n const dim = '\\x1b[2m'\n const cyan = '\\x1b[36m'\n const boldCyan = '\\x1b[1;36m'\n const reset = '\\x1b[0m'\n\n const updateCmd = info.isStandaloneBinary\n ? `Download at ${cyan}https://github.com/jkomyno/uniku/releases${reset}`\n : `Run ${cyan}\\`npm install -g ${PACKAGE_NAME}\\`${reset} to update`\n\n return [\n '',\n ` ${dim}Update available:${reset} ${dim}${info.currentVersion}${reset} ${dim}→${reset} ${boldCyan}${info.latestVersion}${reset}`,\n ` ${updateCmd}`,\n ` ${dim}Set NO_UPDATE_NOTIFIER=1 to disable${reset}`,\n '',\n ].join('\\n')\n}\n\n// ── Cache helpers (plain Node.js — maximally resilient) ──────────────\n\nfunction readCache(): UpdateCache | null {\n try {\n if (!existsSync(CACHE_FILE)) return null\n const content = readFileSync(CACHE_FILE, 'utf-8')\n return JSON.parse(content) as UpdateCache\n } catch {\n return null\n }\n}\n\nfunction writeCache(cache: UpdateCache): void {\n try {\n const dir = dirname(CACHE_FILE)\n mkdirSync(dir, { recursive: true })\n const tmpPath = `${CACHE_FILE}.tmp`\n writeFileSync(tmpPath, JSON.stringify(cache))\n renameSync(tmpPath, CACHE_FILE)\n } catch {\n // Silently ignore write errors\n }\n}\n\n// ── Registry fetch ───────────────────────────────────────────────────\n\nfunction fetchLatestVersion(currentVersion: string): Effect.Effect<string | null> {\n return Effect.tryPromise({\n try: (signal) =>\n fetch(REGISTRY_URL, {\n headers: {\n Accept: 'application/json',\n 'User-Agent': `${PACKAGE_NAME}/${currentVersion}`,\n },\n signal: AbortSignal.any([signal, AbortSignal.timeout(FETCH_TIMEOUT_MS)]),\n }).then(async (res) => {\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = (await res.json()) as { version?: string }\n if (!data.version) throw new Error('Missing version field')\n return data.version\n }),\n catch: () => new Error('fetch failed'),\n }).pipe(Effect.catchAll(() => Effect.succeed(null)))\n}\n\n// ── Standalone binary detection ──────────────────────────────────────\n\ndeclare const __STANDALONE_BINARY__: boolean | undefined\n\nfunction isStandaloneBinary(): boolean {\n try {\n return typeof __STANDALONE_BINARY__ !== 'undefined' && __STANDALONE_BINARY__ === true\n } catch {\n return false\n }\n}\n\n// ── Live implementation ──────────────────────────────────────────────\n\nexport const UpdateCheckServiceLive = UpdateCheckService.of({\n check(currentVersion) {\n return Effect.gen(function* () {\n if (shouldSkipUpdateCheck()) {\n return Option.none()\n }\n\n const cached = readCache()\n const now = Date.now()\n\n // Cache is fresh — use cached result\n if (cached && now - cached.checkedAt < CACHE_TTL_MS) {\n if (isNewerVersion(cached.latestVersion, currentVersion)) {\n return Option.some<UpdateInfo>({\n currentVersion,\n latestVersion: cached.latestVersion,\n isStandaloneBinary: isStandaloneBinary(),\n })\n }\n return Option.none()\n }\n\n // Cache is stale or missing — fetch from registry\n const latestVersion = yield* fetchLatestVersion(currentVersion)\n\n if (latestVersion === null) {\n return Option.none()\n }\n\n writeCache({ latestVersion, checkedAt: now })\n\n if (isNewerVersion(latestVersion, currentVersion)) {\n return Option.some<UpdateInfo>({\n currentVersion,\n latestVersion,\n isStandaloneBinary: isStandaloneBinary(),\n })\n }\n\n return Option.none()\n }).pipe(Effect.catchAll(() => Effect.succeed(Option.none())))\n },\n\n notify(info) {\n return Effect.sync(() => {\n process.stderr.write(formatNotification(info))\n })\n },\n})\n","","import { BunContext, BunRuntime } from '@effect/platform-bun'\nimport * as Duration from 'effect/Duration'\nimport * as Effect from 'effect/Effect'\nimport * as Fiber from 'effect/Fiber'\nimport * as Layer from 'effect/Layer'\nimport * as Option from 'effect/Option'\nimport { makeCliRunner } from '@/src/commands'\nimport { CliError } from '@/src/domain/errors'\nimport { OutputService, OutputServiceLive } from '@/src/services/OutputService'\nimport { StdinService, StdinServiceLive } from '@/src/services/StdinService'\nimport { UpdateCheckService, UpdateCheckServiceLive } from '@/src/services/UpdateCheckService'\nimport pkg from '../package.json' with { type: 'json' }\n\n// ── CLI runner ──────────────────────────────────────────────────────\n\nconst cli = makeCliRunner(pkg.version)\n\n// ── Arg preprocessing ───────────────────────────────────────────────\n\nexport function preprocessArgs(argv: readonly string[]): string[] {\n const args = [...argv]\n\n // Replace -V with --version (Effect CLI doesn't alias -V by default)\n for (let i = 2; i < args.length; i++) {\n if (args[i] === '-V') {\n args[i] = '--version'\n }\n }\n\n // If no command args beyond the executable path, inject --help\n // argv is typically: [bun, script.ts, ...userArgs]\n if (args.length <= 2) {\n args.push('--help')\n }\n\n return args\n}\n\n// ── Service layers ──────────────────────────────────────────────────\n\nconst ServicesLayer = Layer.mergeAll(\n Layer.succeed(OutputService, OutputServiceLive),\n Layer.succeed(StdinService, StdinServiceLive),\n Layer.succeed(UpdateCheckService, UpdateCheckServiceLive),\n)\n\nconst MainLayer = Layer.mergeAll(ServicesLayer, BunContext.layer)\n\n// ── Run ─────────────────────────────────────────────────────────────\n\nconst program = Effect.gen(function* () {\n const updateCheck = yield* UpdateCheckService\n const args = preprocessArgs(process.argv)\n\n // Fork update check as a background fiber\n const fiber = yield* Effect.fork(updateCheck.check(pkg.version))\n\n // Run the main CLI command\n yield* Effect.suspend(() => cli(args)).pipe(\n Effect.catchAll((err) =>\n Effect.sync(() => {\n if (err instanceof CliError) {\n process.stderr.write(`Error: ${err.message}\\n`)\n if (err.hint) {\n process.stderr.write(` ${err.hint}\\n`)\n }\n process.exitCode = err.exitCode\n } else {\n process.stderr.write(`Error: ${String(err)}\\n`)\n process.exitCode = 1\n }\n }),\n ),\n )\n\n // After main command, join fiber with timeout\n const result = yield* Fiber.join(fiber).pipe(\n Effect.timeout(Duration.seconds(5)),\n Effect.catchAll(() => Effect.succeed(Option.none())),\n )\n\n // Show notification unless --json is active\n if (Option.isSome(result) && !args.includes('--json')) {\n yield* updateCheck.notify(result.value)\n }\n})\n\nprogram.pipe(Effect.provide(MainLayer), BunRuntime.runMain)\n"],"mappings":"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"}
1
+ {"version":3,"file":"bin.mjs","names":["NANOID_ALPHABET_PRESETS: Record<string, string>","obj: { error: string; code: string; hint?: string }","ids: string[]","ids: string[]","ids: string[]","ids: string[]","ids: string[]","version","lines: string[]","jsonFlag","idArg","typeFlag","jsonFlag","type: IdType | undefined","chunks: Buffer[]","type: IdType | undefined","ids: readonly string[]","results: ValidationResult[]","exitCodeFor: (error: CliRunFailure) => number","version","updateCmd","pkg.version"],"sources":["../src/domain/constants.ts","../src/domain/errors.ts","../src/generators/cuid.ts","../src/generators/ksuid.ts","../src/generators/nanoid.ts","../src/generators/ulid.ts","../src/generators/uuid.ts","../src/services/OutputService.ts","../src/commands/generate.cmd.ts","../src/validators/validate.ts","../src/inspectors/inspect.ts","../src/runtime/args.ts","../src/commands/inspect.cmd.ts","../src/services/StdinService.ts","../src/commands/validate.cmd.ts","../src/commands/index.ts","../src/runtime/cli-failure.ts","../src/services/UpdateCheckService.ts","../package.json","../src/bin.ts"],"sourcesContent":["/** Default count for ID generation. */\nexport const COUNT_DEFAULT = 1\n\n/** Valid UUID versions. */\nexport const UUID_VERSIONS = [4, 7] as const\n\n/** Default UUID version. */\nexport const UUID_VERSION_DEFAULT = 4\n\n/** Default nanoid size. */\nexport const NANOID_SIZE_DEFAULT = 21\n\n/** Nanoid size range. */\nexport const NANOID_SIZE_MIN = 1\nexport const NANOID_SIZE_MAX = 256\n\n/** Default CUID2 length. */\nexport const CUID_LENGTH_DEFAULT = 24\n\n/** CUID2 length range. */\nexport const CUID_LENGTH_MIN = 2\nexport const CUID_LENGTH_MAX = 32\n\n/** Nanoid alphabet presets. */\nexport const NANOID_ALPHABET_PRESETS: Record<string, string> = {\n hex: '0123456789abcdef',\n numeric: '0123456789',\n alpha: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',\n}\n\n/** Environment variable for default generate type. */\nexport const ENV_DEFAULT_TYPE = 'UNIKU_DEFAULT_TYPE'\n","import * as Schema from 'effect/Schema'\nimport type { UniqueIdError } from 'uniku/errors'\n\n/**\n * Structured CLI error with optional hint. Exit code 1.\n */\nexport class CliError extends Schema.TaggedErrorClass<CliError>()('CliError', {\n code: Schema.String,\n message: Schema.String,\n hint: Schema.optionalKey(Schema.String),\n}) {\n readonly exitCode: number = 1\n}\n\n/**\n * Error indicating validation failure (exit code 2).\n */\nexport class ValidationFailedError extends Schema.TaggedErrorClass<ValidationFailedError>()('ValidationFailedError', {\n message: Schema.String,\n}) {\n readonly code: string = 'VALIDATION_FAILED'\n readonly hint: string | undefined = undefined\n readonly exitCode: number = 2\n}\n\n/**\n * Union of all CLI-owned expected failures.\n */\nexport type CliFailure = CliError | ValidationFailedError\n\n/**\n * Maps a uniku library error into a CliError, preserving code and message.\n */\nexport function fromUnikuError(err: UniqueIdError): CliError {\n return new CliError({ code: err.code, message: err.message })\n}\n\n/**\n * Converts a CLI failure to a JSON-serializable object for stderr output.\n */\nexport function errorToJson(err: CliFailure): { error: string; code: string; hint?: string } {\n const obj: { error: string; code: string; hint?: string } = {\n error: err.message,\n code: err.code,\n }\n if (err.hint) {\n obj.hint = err.hint\n }\n return obj\n}\n","import * as Effect from 'effect/Effect'\nimport { cuid2 } from 'uniku/cuid2'\nimport { UniqueIdError } from 'uniku/errors'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type CuidGenerateOptions = {\n readonly count: number\n readonly length: number\n}\n\nexport function generateCuid(options: CuidGenerateOptions): Effect.Effect<string[], CliError> {\n return Effect.try({\n try: () => {\n const ids: string[] = []\n for (let i = 0; i < options.count; i++) {\n ids.push(cuid2({ length: options.length }))\n }\n return ids\n },\n catch: (err) => {\n if (err instanceof UniqueIdError) return fromUnikuError(err)\n return new CliError({ code: 'GENERATE_FAILED', message: String(err) })\n },\n })\n}\n","import * as Effect from 'effect/Effect'\nimport { UniqueIdError } from 'uniku/errors'\nimport { ksuid } from 'uniku/ksuid'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type KsuidGenerateOptions = {\n readonly count: number\n readonly timestamp?: number\n}\n\nexport function generateKsuid(options: KsuidGenerateOptions): Effect.Effect<string[], CliError> {\n return Effect.try({\n try: () => {\n const ids: string[] = []\n for (let i = 0; i < options.count; i++) {\n const ksuidOpts = options.timestamp != null ? { secs: options.timestamp } : undefined\n ids.push(ksuid(ksuidOpts))\n }\n return ids\n },\n catch: (err) => {\n if (err instanceof UniqueIdError) return fromUnikuError(err)\n return new CliError({ code: 'GENERATE_FAILED', message: String(err) })\n },\n })\n}\n","import * as Effect from 'effect/Effect'\nimport { UniqueIdError } from 'uniku/errors'\nimport { nanoid } from 'uniku/nanoid'\nimport { NANOID_ALPHABET_PRESETS } from '@/src/domain/constants'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type NanoidGenerateOptions = {\n readonly count: number\n readonly size: number\n readonly alphabet?: string\n}\n\nfunction resolveAlphabet(input?: string): string | undefined {\n if (!input) return undefined\n return NANOID_ALPHABET_PRESETS[input] ?? input\n}\n\nexport function generateNanoid(options: NanoidGenerateOptions): Effect.Effect<string[], CliError> {\n return Effect.try({\n try: () => {\n const alphabet = resolveAlphabet(options.alphabet)\n const ids: string[] = []\n for (let i = 0; i < options.count; i++) {\n ids.push(nanoid({ size: options.size, alphabet }))\n }\n return ids\n },\n catch: (err) => {\n if (err instanceof UniqueIdError) return fromUnikuError(err)\n return new CliError({ code: 'GENERATE_FAILED', message: String(err) })\n },\n })\n}\n","import * as Effect from 'effect/Effect'\nimport { UniqueIdError } from 'uniku/errors'\nimport { ulid } from 'uniku/ulid'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type UlidGenerateOptions = {\n readonly count: number\n readonly monotonic: boolean\n readonly timestamp?: number\n readonly lowercase: boolean\n}\n\nexport function generateUlid(options: UlidGenerateOptions): Effect.Effect<string[], CliError> {\n if (options.monotonic && options.timestamp != null) {\n return Effect.fail(\n new CliError({\n code: 'INVALID_OPTIONS',\n message: '--monotonic and --timestamp are mutually exclusive',\n hint: 'Use --monotonic for monotonically increasing ULIDs, or --timestamp to specify a fixed timestamp',\n }),\n )\n }\n\n return Effect.try({\n try: () => {\n const ids: string[] = []\n for (let i = 0; i < options.count; i++) {\n const ulidOpts = options.timestamp != null ? { msecs: options.timestamp } : undefined\n let id = ulid(ulidOpts)\n if (options.lowercase) {\n id = id.toLowerCase()\n }\n ids.push(id)\n }\n return ids\n },\n catch: (err) => {\n if (err instanceof UniqueIdError) return fromUnikuError(err)\n return new CliError({ code: 'GENERATE_FAILED', message: String(err) })\n },\n })\n}\n","import * as Effect from 'effect/Effect'\nimport { UniqueIdError } from 'uniku/errors'\nimport { uuidv4 } from 'uniku/uuid/v4'\nimport { uuidv7 } from 'uniku/uuid/v7'\nimport { CliError, fromUnikuError } from '@/src/domain/errors'\n\nexport type UuidGenerateOptions = {\n readonly count: number\n readonly version: number\n readonly lowercase: boolean\n}\n\nexport function generateUuid(options: UuidGenerateOptions): Effect.Effect<string[], CliError> {\n return Effect.try({\n try: () => {\n const gen = options.version === 7 ? uuidv7 : uuidv4\n const ids: string[] = []\n for (let i = 0; i < options.count; i++) {\n let id = gen()\n if (options.lowercase) {\n id = id.toLowerCase()\n }\n ids.push(id)\n }\n return ids\n },\n catch: (err) => {\n if (err instanceof UniqueIdError) return fromUnikuError(err)\n return new CliError({ code: 'GENERATE_FAILED', message: String(err) })\n },\n })\n}\n","import * as Context from 'effect/Context'\nimport * as Effect from 'effect/Effect'\nimport * as Layer from 'effect/Layer'\nimport { type CliFailure, errorToJson } from '@/src/domain/errors'\nimport type { InspectResult, ValidationResult } from '@/src/domain/types'\n\nexport type OutputOptions = {\n readonly json: boolean\n}\n\n/**\n * A command's primary output: a JSON-serializable value plus a human-readable\n * text rendering. Text is a list of records, each written on its own line\n * (a record may itself span multiple lines, e.g. inspect output).\n */\nexport interface Render {\n readonly json: () => unknown\n readonly text: () => ReadonlyArray<string>\n}\n\n/**\n * Renders a primary-output value to the records to write. This is the only\n * place where output-format branching exists.\n */\nexport function render(value: Render, options: OutputOptions): ReadonlyArray<string> {\n return options.json ? [JSON.stringify(value.json())] : value.text()\n}\n\n/**\n * Writes a command's primary output. Commands build one `Render` value and\n * emit it exactly once — stdout carries only the primary output, errors go\n * to stderr.\n */\nexport class OutputService extends Context.Service<\n OutputService,\n {\n readonly write: (value: Render, options: OutputOptions) => Effect.Effect<void>\n readonly writeError: (value: Render, options: OutputOptions) => Effect.Effect<void>\n }\n>()('uniku/cli/OutputService') {\n /**\n * Default implementation writing to process.stdout / process.stderr.\n */\n static readonly layer = Layer.succeed(\n OutputService,\n OutputService.of({\n write: (value, options) => Effect.sync(() => writeRecords(process.stdout, render(value, options))),\n writeError: (value, options) => Effect.sync(() => writeRecords(process.stderr, render(value, options))),\n }),\n )\n}\n\nfunction writeRecords(sink: NodeJS.WritableStream, records: ReadonlyArray<string>): void {\n for (const record of records) {\n sink.write(`${record}\\n`)\n }\n}\n\n// ── Primary-output values ───────────────────────────────────────────\n\nexport function idsOutput(ids: readonly string[]): Render {\n return {\n json: () => (ids.length === 1 ? ids[0] : ids),\n text: () => ids,\n }\n}\n\nexport function validationOutput(results: readonly ValidationResult[]): Render {\n return {\n json: () => (results.length === 1 ? results[0] : results),\n text: () => results.map(formatValidationHuman),\n }\n}\n\nexport function inspectOutput(result: InspectResult): Render {\n return {\n json: () => result,\n text: () => [formatInspectHuman(result)],\n }\n}\n\nexport function errorOutput(error: CliFailure): Render {\n return {\n json: () => errorToJson(error),\n text: () => [formatErrorHuman(error)],\n }\n}\n\n// ── Human renderings ────────────────────────────────────────────────\n\nfunction formatValidationHuman(result: ValidationResult): string {\n if (result.valid) {\n const version = result.version != null ? ` v${result.version}` : ''\n return `valid (${result.type}${version})`\n }\n return `invalid: ${result.error ?? 'malformed identifier'}`\n}\n\nfunction formatInspectHuman(result: InspectResult): string {\n const lines: string[] = []\n const typeLabel = result.version != null ? `${result.type} (v${result.version})` : result.type\n lines.push(`Type: ${typeLabel}`)\n if (result.timestamp) {\n lines.push(`Timestamp: ${result.timestamp}`)\n }\n if (result.random) {\n lines.push(`Random: ${result.random}`)\n }\n if (result.note) {\n lines.push(`Note: ${result.note}`)\n }\n return lines.join('\\n')\n}\n\nfunction formatErrorHuman(error: CliFailure): string {\n return error.hint ? `Error: ${error.message}\\n ${error.hint}` : `Error: ${error.message}`\n}\n","import * as Clock from 'effect/Clock'\nimport * as Effect from 'effect/Effect'\nimport * as Option from 'effect/Option'\nimport { Command, Flag } from 'effect/unstable/cli'\nimport { COUNT_DEFAULT, CUID_LENGTH_DEFAULT, NANOID_SIZE_DEFAULT, UUID_VERSION_DEFAULT } from '@/src/domain/constants'\nimport { CliError } from '@/src/domain/errors'\nimport { generateCuid } from '@/src/generators/cuid'\nimport { generateKsuid } from '@/src/generators/ksuid'\nimport { generateNanoid } from '@/src/generators/nanoid'\nimport { generateUlid } from '@/src/generators/ulid'\nimport { generateUuid } from '@/src/generators/uuid'\nimport { idsOutput, OutputService } from '@/src/services/OutputService'\n\n// ── Common flags ────────────────────────────────────────────────────\n\nconst countFlag = Flag.integer('count').pipe(\n Flag.withAlias('n'),\n Flag.withDescription('Number of IDs to generate'),\n Flag.withDefault(COUNT_DEFAULT),\n)\n\nconst jsonFlag = Flag.boolean('json').pipe(Flag.withDescription('Output as JSON'), Flag.withDefault(false))\n\n// ── UUID subcommand ─────────────────────────────────────────────────\n\nconst uuidVersionFlag = Flag.choiceWithValue('uuid-version', [\n ['4', 4],\n ['7', 7],\n] as const).pipe(\n Flag.withAlias('v'),\n Flag.withDescription('UUID version: 4, 7'),\n Flag.withDefault(UUID_VERSION_DEFAULT as 4 | 7),\n)\n\nconst lowercaseFlag = Flag.boolean('lowercase').pipe(\n Flag.withDescription('Output in lowercase'),\n Flag.withDefault(false),\n)\n\nconst uuidSubcommand = Command.make(\n 'uuid',\n {\n count: countFlag,\n json: jsonFlag,\n version: uuidVersionFlag,\n lowercase: lowercaseFlag,\n },\n Effect.fn('cli.generate.uuid')(function* ({ count, json, version, lowercase }) {\n const output = yield* OutputService\n const ids = yield* generateUuid({ count, version, lowercase })\n yield* output.write(idsOutput(ids), { json })\n }),\n).pipe(\n Command.withDescription('Generate UUIDs (v4 or v7)'),\n Command.withExamples([\n { command: 'uniku uuid -n 5 --json', description: 'Generate 5 UUIDs as a JSON array (machine-readable)' },\n { command: 'uniku uuid -v 7', description: 'Generate a time-sortable UUID v7' },\n { command: 'uniku uuid', description: 'Generate one random UUID v4' },\n ]),\n)\n\n// ── ULID subcommand ─────────────────────────────────────────────────\n\nconst monotonicFlag = Flag.boolean('monotonic').pipe(\n Flag.withDescription('Generate monotonically increasing ULIDs'),\n Flag.withDefault(false),\n)\n\nconst ulidTimestampFlag = Flag.string('timestamp').pipe(\n Flag.withDescription('Unix timestamp in milliseconds (or \"now\")'),\n Flag.optional,\n)\n\nconst ulidSubcommand = Command.make(\n 'ulid',\n {\n count: countFlag,\n json: jsonFlag,\n monotonic: monotonicFlag,\n timestamp: ulidTimestampFlag,\n lowercase: lowercaseFlag,\n },\n Effect.fn('cli.generate.ulid')(function* ({ count, json, monotonic, timestamp: timestampOpt, lowercase }) {\n const output = yield* OutputService\n const timestampInput = Option.getOrUndefined(timestampOpt)\n const timestamp = timestampInput !== undefined ? yield* parseTimestampMs(timestampInput) : undefined\n const ids = yield* generateUlid({ count, monotonic, timestamp, lowercase })\n yield* output.write(idsOutput(ids), { json })\n }),\n).pipe(\n Command.withDescription('Generate ULIDs'),\n Command.withExamples([\n {\n command: 'uniku ulid -n 10 --monotonic --json',\n description: 'Generate 10 strictly ordered ULIDs as a JSON array',\n },\n { command: 'uniku ulid --timestamp 1720000000000', description: 'Generate a ULID for a fixed Unix timestamp (ms)' },\n ]),\n)\n\n// ── Nanoid subcommand ───────────────────────────────────────────────\n\nconst sizeFlag = Flag.integer('size').pipe(\n Flag.withAlias('s'),\n Flag.withDescription('Length of ID (1-256)'),\n Flag.withDefault(NANOID_SIZE_DEFAULT),\n)\n\nconst alphabetFlag = Flag.string('alphabet').pipe(\n Flag.withAlias('a'),\n Flag.withDescription('Custom alphabet or preset: hex, numeric, alpha'),\n Flag.optional,\n)\n\nconst nanoidSubcommand = Command.make(\n 'nanoid',\n {\n count: countFlag,\n json: jsonFlag,\n size: sizeFlag,\n alphabet: alphabetFlag,\n },\n Effect.fn('cli.generate.nanoid')(function* ({ count, json, size, alphabet: alphabetOpt }) {\n const output = yield* OutputService\n const alphabet = Option.getOrUndefined(alphabetOpt)\n const ids = yield* generateNanoid({ count, size, alphabet })\n yield* output.write(idsOutput(ids), { json })\n }),\n).pipe(\n Command.withDescription('Generate Nanoids'),\n Command.withExamples([\n { command: 'uniku nanoid -n 5 --json', description: 'Generate 5 Nanoids as a JSON array' },\n { command: 'uniku nanoid --size 10 --alphabet hex', description: 'Generate a 10-char ID from the hex preset' },\n ]),\n)\n\n// ── CUID subcommand ─────────────────────────────────────────────────\n\nconst lengthFlag = Flag.integer('length').pipe(\n Flag.withAlias('l'),\n Flag.withDescription('Length of ID (2-32)'),\n Flag.withDefault(CUID_LENGTH_DEFAULT),\n)\n\nconst cuidSubcommand = Command.make(\n 'cuid',\n {\n count: countFlag,\n json: jsonFlag,\n length: lengthFlag,\n },\n Effect.fn('cli.generate.cuid')(function* ({ count, json, length }) {\n const output = yield* OutputService\n const ids = yield* generateCuid({ count, length })\n yield* output.write(idsOutput(ids), { json })\n }),\n).pipe(\n Command.withDescription('Generate CUIDs (v2)'),\n Command.withExamples([\n { command: 'uniku cuid -n 5 --json', description: 'Generate 5 CUIDs as a JSON array' },\n { command: 'uniku cuid --length 10', description: 'Generate a 10-char CUID' },\n ]),\n)\n\n// ── KSUID subcommand ────────────────────────────────────────────────\n\nconst ksuidTimestampFlag = Flag.string('timestamp').pipe(\n Flag.withDescription('Unix timestamp in seconds (or \"now\")'),\n Flag.optional,\n)\n\nconst ksuidSubcommand = Command.make(\n 'ksuid',\n {\n count: countFlag,\n json: jsonFlag,\n timestamp: ksuidTimestampFlag,\n },\n Effect.fn('cli.generate.ksuid')(function* ({ count, json, timestamp: timestampOpt }) {\n const output = yield* OutputService\n const timestampInput = Option.getOrUndefined(timestampOpt)\n const timestamp = timestampInput !== undefined ? yield* parseTimestampSecs(timestampInput) : undefined\n const ids = yield* generateKsuid({ count, timestamp })\n yield* output.write(idsOutput(ids), { json })\n }),\n).pipe(\n Command.withDescription('Generate KSUIDs'),\n Command.withExamples([\n { command: 'uniku ksuid -n 5 --json', description: 'Generate 5 KSUIDs as a JSON array' },\n { command: 'uniku ksuid --timestamp 1720000000', description: 'Generate a KSUID for a fixed Unix timestamp (s)' },\n ]),\n)\n\n// ── Generate parent command ─────────────────────────────────────────\n\nexport const generateCommand = Command.make('generate').pipe(\n Command.withDescription('Generate new IDs'),\n Command.withSubcommands([uuidSubcommand, ulidSubcommand, nanoidSubcommand, cuidSubcommand, ksuidSubcommand]),\n Command.withExamples([\n { command: 'uniku generate uuid -n 5 --json', description: 'Generate 5 UUIDs as a JSON array' },\n {\n command: 'uniku generate ulid',\n description: 'Generate one ULID (subcommands also work top-level: `uniku ulid`)',\n },\n ]),\n)\n\n// ── Shorthand commands (top-level: `uniku uuid`, `uniku ulid`, etc.) ─\n\nexport const uuidShorthand = uuidSubcommand\nexport const ulidShorthand = ulidSubcommand\nexport const nanoidShorthand = nanoidSubcommand\nexport const cuidShorthand = cuidSubcommand\nexport const ksuidShorthand = ksuidSubcommand\n\n// ── Helpers ─────────────────────────────────────────────────────────\n\nconst parseTimestamp = Effect.fn('cli.generate.parseTimestamp')(function* (\n input: string,\n fromMillis: (millis: number) => number,\n hint: string,\n) {\n if (input === 'now') {\n return fromMillis(yield* Clock.currentTimeMillis)\n }\n const n = Number(input)\n if (!Number.isFinite(n) || n < 0) {\n return yield* new CliError({ code: 'INVALID_TIMESTAMP', message: `Invalid timestamp: \"${input}\"`, hint })\n }\n return n\n})\n\nconst parseTimestampMs = (input: string): Effect.Effect<number, CliError> =>\n parseTimestamp(input, (millis) => millis, 'Provide a Unix timestamp in milliseconds or \"now\"')\n\nconst parseTimestampSecs = (input: string): Effect.Effect<number, CliError> =>\n parseTimestamp(input, (millis) => Math.floor(millis / 1000), 'Provide a Unix timestamp in seconds or \"now\"')\n","import { cuid2 } from 'uniku/cuid2'\nimport { ksuid } from 'uniku/ksuid'\nimport { nanoid } from 'uniku/nanoid'\nimport { ulid } from 'uniku/ulid'\nimport { uuidv4 } from 'uniku/uuid/v4'\nimport { uuidv7 } from 'uniku/uuid/v7'\nimport type { IdType, ValidationResult } from '@/src/domain/types'\n\n/**\n * Validate a single ID against a specific type.\n */\nexport function validateAs(id: string, type: IdType): ValidationResult {\n switch (type) {\n case 'uuid':\n return validateUuid(id)\n case 'ulid':\n return validateUlid(id)\n case 'ksuid':\n return validateKsuid(id)\n case 'cuid':\n return validateCuid(id)\n case 'nanoid':\n return validateNanoid(id)\n }\n}\n\n/**\n * Auto-detect ID type and validate.\n * Detection order: UUID > ULID > KSUID > CUID > Nanoid.\n */\nexport function validateAutoDetect(id: string): ValidationResult {\n // 1. UUID (36 chars, 8-4-4-4-12 format with hyphens)\n if (uuidv7.isValid(id)) {\n return { id, valid: true, type: 'uuid', version: 7 }\n }\n if (uuidv4.isValid(id)) {\n return { id, valid: true, type: 'uuid', version: 4 }\n }\n\n // 2. ULID (26 chars, Crockford Base32)\n if (ulid.isValid(id)) {\n return { id, valid: true, type: 'ulid' }\n }\n\n // 3. KSUID (27 chars, Base62)\n if (ksuid.isValid(id)) {\n return { id, valid: true, type: 'ksuid' }\n }\n\n // 4. CUID (starts with letter, Base36)\n if (cuid2.isValid(id)) {\n return { id, valid: true, type: 'cuid' }\n }\n\n // 5. Nanoid (fallback: URL-safe A-Za-z0-9_- and length 1-256)\n if (nanoid.isValid(id)) {\n return { id, valid: true, type: 'nanoid' }\n }\n\n return { id, valid: false, error: 'malformed identifier' }\n}\n\nfunction validateUuid(id: string): ValidationResult {\n if (uuidv7.isValid(id)) {\n return { id, valid: true, type: 'uuid', version: 7 }\n }\n if (uuidv4.isValid(id)) {\n return { id, valid: true, type: 'uuid', version: 4 }\n }\n return { id, valid: false, type: 'uuid', error: 'invalid UUID format' }\n}\n\nfunction validateUlid(id: string): ValidationResult {\n if (ulid.isValid(id)) {\n return { id, valid: true, type: 'ulid' }\n }\n return { id, valid: false, type: 'ulid', error: 'invalid ULID format' }\n}\n\nfunction validateKsuid(id: string): ValidationResult {\n if (ksuid.isValid(id)) {\n return { id, valid: true, type: 'ksuid' }\n }\n return { id, valid: false, type: 'ksuid', error: 'invalid KSUID format' }\n}\n\nfunction validateCuid(id: string): ValidationResult {\n if (cuid2.isValid(id)) {\n return { id, valid: true, type: 'cuid' }\n }\n return { id, valid: false, type: 'cuid', error: 'invalid CUID format' }\n}\n\nfunction validateNanoid(id: string): ValidationResult {\n if (nanoid.isValid(id)) {\n return { id, valid: true, type: 'nanoid' }\n }\n return { id, valid: false, type: 'nanoid', error: 'invalid Nanoid format' }\n}\n","import { ksuid } from 'uniku/ksuid'\nimport { ulid } from 'uniku/ulid'\nimport { uuidv4 } from 'uniku/uuid/v4'\nimport { uuidv7 } from 'uniku/uuid/v7'\nimport type { IdType, InspectResult } from '@/src/domain/types'\nimport { validateAutoDetect } from '@/src/validators/validate'\n\n/**\n * Inspect an ID and extract metadata.\n * If type is not provided, auto-detect is used.\n */\nexport function inspectId(id: string, type?: IdType): InspectResult | null {\n const resolvedType = type ?? detectType(id)\n if (!resolvedType) return null\n\n switch (resolvedType) {\n case 'uuid':\n return inspectUuid(id)\n case 'ulid':\n return inspectUlid(id)\n case 'ksuid':\n return inspectKsuid(id)\n case 'cuid':\n return inspectCuid(id)\n case 'nanoid':\n return inspectNanoid(id)\n }\n}\n\nfunction detectType(id: string): IdType | null {\n const result = validateAutoDetect(id)\n return result.valid ? (result.type ?? null) : null\n}\n\nfunction inspectUuid(id: string): InspectResult {\n if (uuidv7.isValid(id)) {\n const ms = uuidv7.timestamp(id)\n const bytes = uuidv7.toBytes(id)\n // Random component: last 6 bytes (bytes 10-15)\n const random = Buffer.from(bytes.slice(10)).toString('hex')\n return {\n id,\n type: 'uuid',\n version: 7,\n timestamp: new Date(ms).toISOString(),\n timestamp_ms: ms,\n random,\n }\n }\n\n if (uuidv4.isValid(id)) {\n return {\n id,\n type: 'uuid',\n version: 4,\n note: 'This ID type contains no decodable metadata.',\n }\n }\n\n return {\n id,\n type: 'uuid',\n note: 'Unrecognized UUID version.',\n }\n}\n\nfunction inspectUlid(id: string): InspectResult {\n const ms = ulid.timestamp(id)\n // Random component: last 16 chars of the 26-char ULID\n const random = id.slice(10)\n return {\n id,\n type: 'ulid',\n timestamp: new Date(ms).toISOString(),\n timestamp_ms: ms,\n random,\n }\n}\n\nfunction inspectKsuid(id: string): InspectResult {\n const ms = ksuid.timestamp(id)\n const bytes = ksuid.toBytes(id)\n // Random payload: last 16 bytes (bytes 4-19)\n const random = Buffer.from(bytes.slice(4)).toString('hex')\n return {\n id,\n type: 'ksuid',\n timestamp: new Date(ms).toISOString(),\n timestamp_ms: ms,\n random,\n }\n}\n\nfunction inspectCuid(id: string): InspectResult {\n return {\n id,\n type: 'cuid',\n note: 'This ID type contains no decodable metadata.',\n }\n}\n\nfunction inspectNanoid(id: string): InspectResult {\n return {\n id,\n type: 'nanoid',\n note: 'This ID type contains no decodable metadata.',\n }\n}\n","/**\n * Normalizes user-facing CLI arguments (everything after the executable and\n * script path) before they reach Command.runWith.\n */\nexport function preprocessArgs(args: readonly string[]): string[] {\n const doubleDash = args.indexOf('--')\n\n // Rewrite -V to --version (the built-in version flag only aliases -v).\n // Post-`--` tokens are literal, so only the head is rewritten.\n const head = (doubleDash === -1 ? args : args.slice(0, doubleDash)).map((arg) => (arg === '-V' ? '--version' : arg))\n\n if (doubleDash === -1) {\n return head\n }\n\n // Effect v4's parser attaches operands found after `--` to the parent\n // command instead of the resolved subcommand (internal/parser.ts keeps\n // `trailingOperands` at the level that lexed them and recurses with `[]`).\n // For commands whose public contract accepts a literal positional ID,\n // encode each operand — the prefix stops it from parsing as a flag — and\n // drop the marker so the parser routes it to the selected subcommand.\n // Commands decode with `decodePreprocessedArg`.\n const operands = args.slice(doubleDash + 1)\n return acceptsLiteralIdOperand(head) ? [...head, ...operands.map(encodeLiteralArg)] : [...head, '--', ...operands]\n}\n\nconst literalArgPrefix = '\\0uniku-literal:'\nconst literalIdCommands = new Set(['inspect', 'validate'])\n\n// The built-in global flags whose value is a separate token (`--log-level\n// info`). Mirrors the value-taking entries of `GlobalFlag.BuiltIns` in the\n// pinned effect beta (the published dist exposes no way to derive them);\n// re-check this list when bumping the beta.\nconst valueTakingGlobalFlags = new Set(['--completions', '--log-level'])\n\nexport function decodePreprocessedArg(arg: string): string {\n return arg.startsWith(literalArgPrefix) ? arg.slice(literalArgPrefix.length) : arg\n}\n\nfunction encodeLiteralArg(arg: string): string {\n return `${literalArgPrefix}${arg}`\n}\n\n/**\n * Whether the first command-like token (skipping global flags and their\n * values) is a command that takes a literal positional ID.\n */\nfunction acceptsLiteralIdOperand(argsBeforeDoubleDash: readonly string[]): boolean {\n for (let index = 0; index < argsBeforeDoubleDash.length; index += 1) {\n const arg = argsBeforeDoubleDash[index]\n\n if (arg.startsWith('-')) {\n // `--flag=value` is a single token; `--flag value` needs its value skipped.\n if (valueTakingGlobalFlags.has(arg)) {\n index += 1\n }\n continue\n }\n\n return literalIdCommands.has(arg)\n }\n\n return false\n}\n","import * as Effect from 'effect/Effect'\nimport * as Option from 'effect/Option'\nimport { Argument, Command, Flag } from 'effect/unstable/cli'\nimport { CliError } from '@/src/domain/errors'\nimport type { IdType } from '@/src/domain/types'\nimport { inspectId } from '@/src/inspectors/inspect'\nimport { decodePreprocessedArg } from '@/src/runtime/args'\nimport { inspectOutput, OutputService } from '@/src/services/OutputService'\n\nconst idArg = Argument.string('id').pipe(Argument.withDescription('The ID to inspect'))\n\nconst typeFlag = Flag.choice('type', ['uuid', 'ulid', 'nanoid', 'cuid', 'ksuid'] as const).pipe(\n Flag.withDescription('ID type (auto-detected if omitted)'),\n Flag.optional,\n)\n\nconst jsonFlag = Flag.boolean('json').pipe(Flag.withDescription('Output as JSON'), Flag.withDefault(false))\n\nexport const inspectCommand = Command.make(\n 'inspect',\n {\n id: idArg,\n type: typeFlag,\n json: jsonFlag,\n },\n Effect.fn('cli.inspect')(function* ({ id, type: typeOpt, json }) {\n const output = yield* OutputService\n const type: IdType | undefined = Option.getOrUndefined(typeOpt)\n const input = decodePreprocessedArg(id)\n\n const result = inspectId(input, type)\n if (!result) {\n return yield* new CliError({\n code: 'UNKNOWN_ID_TYPE',\n message: `Could not identify ID type for: \"${input}\"`,\n hint: 'Use --type to specify the ID type',\n })\n }\n\n yield* output.write(inspectOutput(result), { json })\n }),\n).pipe(\n Command.withDescription('Decode and inspect an ID'),\n Command.withExamples([\n {\n command: 'uniku inspect 01J9YR2V5TZB8Q4W6X0E1N7M3S --json',\n description: 'Decode an ID to structured JSON (type, version, timestamp)',\n },\n { command: 'uniku inspect --type uuid 3F2504E0-4F89-41D3-9A0C-0305E82C3301', description: 'Skip auto-detection' },\n { command: 'uniku inspect -- --tricky-id', description: 'Inspect an ID that starts with a dash' },\n ]),\n)\n","import * as Context from 'effect/Context'\nimport * as Effect from 'effect/Effect'\nimport * as Layer from 'effect/Layer'\nimport { CliError } from '@/src/domain/errors'\n\nexport class StdinService extends Context.Service<\n StdinService,\n {\n readonly readLines: () => Effect.Effect<readonly string[], CliError>\n }\n>()('uniku/cli/StdinService') {\n /**\n * Reads all lines from process.stdin until EOF.\n * Filters out empty lines.\n */\n static readonly layer = Layer.succeed(\n StdinService,\n StdinService.of({\n readLines: Effect.fn('StdinService.readLines')(() =>\n Effect.callback<readonly string[], CliError>((resume) => {\n const chunks: Buffer[] = []\n\n process.stdin.on('data', (chunk: Buffer) => {\n chunks.push(chunk)\n })\n\n process.stdin.on('end', () => {\n const text = Buffer.concat(chunks).toString('utf-8')\n const lines = text\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n resume(Effect.succeed(lines))\n })\n\n process.stdin.on('error', (err) => {\n resume(Effect.fail(new CliError({ code: 'STDIN_ERROR', message: err.message })))\n })\n\n process.stdin.resume()\n }),\n ),\n }),\n )\n}\n","import * as Effect from 'effect/Effect'\nimport * as Option from 'effect/Option'\nimport { Argument, Command, Flag } from 'effect/unstable/cli'\nimport { CliError, ValidationFailedError } from '@/src/domain/errors'\nimport type { IdType, ValidationResult } from '@/src/domain/types'\nimport { decodePreprocessedArg } from '@/src/runtime/args'\nimport { OutputService, validationOutput } from '@/src/services/OutputService'\nimport { StdinService } from '@/src/services/StdinService'\nimport { validateAs, validateAutoDetect } from '@/src/validators/validate'\n\nconst idArg = Argument.string('id').pipe(Argument.withDescription('The ID to validate'), Argument.optional)\n\nconst typeFlag = Flag.choice('type', ['uuid', 'ulid', 'nanoid', 'cuid', 'ksuid'] as const).pipe(\n Flag.withDescription('Expected ID type (auto-detected if omitted)'),\n Flag.optional,\n)\n\nconst stdinFlag = Flag.boolean('stdin').pipe(\n Flag.withDescription('Read IDs from stdin (one per line)'),\n Flag.withDefault(false),\n)\n\nconst jsonFlag = Flag.boolean('json').pipe(\n Flag.withDescription('Output validation results as JSON'),\n Flag.withDefault(false),\n)\n\nconst quietFlag = Flag.boolean('quiet').pipe(Flag.withDescription('No output, exit code only'), Flag.withDefault(false))\n\nexport const validateCommand = Command.make(\n 'validate',\n {\n id: idArg,\n type: typeFlag,\n stdin: stdinFlag,\n json: jsonFlag,\n quiet: quietFlag,\n },\n Effect.fn('cli.validate')(function* ({ id: idOpt, type: typeOpt, stdin, json, quiet }) {\n const output = yield* OutputService\n const stdinService = yield* StdinService\n const type: IdType | undefined = Option.getOrUndefined(typeOpt)\n\n let ids: readonly string[]\n\n if (stdin) {\n ids = yield* stdinService.readLines()\n if (ids.length === 0) {\n return yield* new CliError({ code: 'NO_INPUT', message: 'No IDs provided on stdin' })\n }\n } else if (Option.isSome(idOpt)) {\n ids = [decodePreprocessedArg(idOpt.value)]\n } else {\n return yield* new CliError({\n code: 'NO_INPUT',\n message: 'No ID provided',\n hint: 'Pass an ID as argument or use --stdin',\n })\n }\n\n const results: ValidationResult[] = ids.map((id) => (type ? validateAs(id, type) : validateAutoDetect(id)))\n\n if (!quiet) {\n yield* output.write(validationOutput(results), { json })\n }\n\n const hasInvalid = results.some((r) => !r.valid)\n if (hasInvalid) {\n return yield* new ValidationFailedError({ message: 'One or more IDs are invalid' })\n }\n }),\n).pipe(\n Command.withDescription('Check if an ID is valid'),\n Command.withExamples([\n {\n command: 'uniku validate 3F2504E0-4F89-41D3-9A0C-0305E82C3301 --json',\n description: 'Validate one ID, result as JSON',\n },\n {\n command: 'cat ids.txt | uniku validate --stdin --json',\n description: 'Validate many IDs (one per line), results as a JSON array',\n },\n { command: 'uniku validate --quiet 01J9YR2V5TZB8Q4W6X0E1N7M3S', description: 'Exit code only: 0 valid, 2 invalid' },\n ]),\n)\n","import { Command } from 'effect/unstable/cli'\nimport {\n cuidShorthand,\n generateCommand,\n ksuidShorthand,\n nanoidShorthand,\n ulidShorthand,\n uuidShorthand,\n} from '@/src/commands/generate.cmd'\nimport { inspectCommand } from '@/src/commands/inspect.cmd'\nimport { validateCommand } from '@/src/commands/validate.cmd'\n\n// ── Root command ────────────────────────────────────────────────────\n\nexport const rootCommand = Command.make('uniku').pipe(\n Command.withDescription('Generate and validate unique identifiers'),\n Command.withExamples([\n { command: 'uniku uuid -n 5 --json', description: 'Generate 5 UUIDs as a JSON array (machine-readable)' },\n { command: 'uniku ulid', description: 'Generate one ULID' },\n { command: 'uniku inspect <id> --json', description: 'Decode an ID (type, version, timestamp) as JSON' },\n { command: 'cat ids.txt | uniku validate --stdin --json', description: 'Validate IDs from stdin, one per line' },\n ]),\n Command.withSubcommands([\n generateCommand,\n validateCommand,\n inspectCommand,\n // Shorthand commands: `uniku uuid` = `uniku generate uuid`\n uuidShorthand,\n ulidShorthand,\n nanoidShorthand,\n cuidShorthand,\n ksuidShorthand,\n ]),\n)\n\n// ── CLI runner (reusable for testing) ───────────────────────────────\n\nexport const makeCliRunner = (version: string) => Command.runWith(rootCommand, { version })\n","import * as Console from 'effect/Console'\nimport * as Effect from 'effect/Effect'\nimport * as Match from 'effect/Match'\nimport type { CliError as CliFrameworkError } from 'effect/unstable/cli'\nimport type { CliFailure } from '@/src/domain/errors'\nimport { errorOutput, OutputService } from '@/src/services/OutputService'\n\nconst EXIT_CODE_SUCCESS = 0\nconst EXIT_CODE_FAILURE = 1\n\n/**\n * Every failure the CLI runner can produce: CLI-owned expected failures\n * plus the Effect CLI framework's parse/help errors.\n */\nexport type CliRunFailure = CliFailure | CliFrameworkError.CliError\n\nfunction usesJsonOutput(args: readonly string[]): boolean {\n return args.includes('--json')\n}\n\n/**\n * Maps the full CLI failure union to a process exit code.\n *\n * `ShowHelp` is a success (exit 0) when help was requested explicitly\n * (no parse errors attached), a failure otherwise.\n */\nexport const exitCodeFor: (error: CliRunFailure) => number = Match.type<CliRunFailure>().pipe(\n Match.tag('CliError', (error) => error.exitCode),\n Match.tag('ValidationFailedError', (error) => error.exitCode),\n Match.tag('ShowHelp', (error) => (error.errors.length > 0 ? EXIT_CODE_FAILURE : EXIT_CODE_SUCCESS)),\n Match.tag(\n 'UnrecognizedOption',\n 'DuplicateOption',\n 'MissingOption',\n 'MissingArgument',\n 'InvalidValue',\n 'UnknownSubcommand',\n 'UserError',\n () => EXIT_CODE_FAILURE,\n ),\n Match.exhaustive,\n)\n\nexport const handleCliFailure = Effect.fn('cli.handleCliFailure')(function* (\n error: CliRunFailure,\n args: readonly string[],\n) {\n yield* Match.value(error).pipe(\n // CLI-owned failures are written by us.\n Match.tag('CliError', 'ValidationFailedError', (failure) =>\n OutputService.use((output) => output.writeError(errorOutput(failure), { json: usesJsonOutput(args) })),\n ),\n // Command.runWith renders ShowHelp (and the parse errors it wraps) itself.\n Match.tag('ShowHelp', () => Effect.void),\n // Global-flag parse failures (e.g. --log-level bogus) escape Command.runWith\n // unrendered.\n Match.tag(\n 'UnrecognizedOption',\n 'DuplicateOption',\n 'MissingOption',\n 'MissingArgument',\n 'InvalidValue',\n 'UnknownSubcommand',\n 'UserError',\n (failure) => Console.error(`Error: ${failure.message}`),\n ),\n Match.exhaustive,\n )\n process.exitCode = exitCodeFor(error)\n})\n","import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { tmpdir, userInfo } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport * as Config from 'effect/Config'\nimport * as Context from 'effect/Context'\nimport * as Effect from 'effect/Effect'\nimport * as Layer from 'effect/Layer'\nimport * as Option from 'effect/Option'\n\n// ── Types ────────────────────────────────────────────────────────────\n\nexport interface UpdateInfo {\n readonly currentVersion: string\n readonly latestVersion: string\n readonly isStandaloneBinary: boolean\n}\n\ninterface UpdateCache {\n readonly latestVersion?: string\n readonly checkedAt: number\n}\n\ninterface UpdateCheckServiceOptions {\n readonly cacheFile?: string\n readonly fetchLatestVersion?: (currentVersion: string) => Effect.Effect<string | null>\n readonly isStandaloneBinary?: () => boolean\n readonly isStderrTTY?: () => boolean\n readonly now?: () => number\n readonly writeStderr?: (message: string) => void\n}\n\n// ── Service ──────────────────────────────────────────────────────────\n\nexport class UpdateCheckService extends Context.Service<\n UpdateCheckService,\n {\n /** Check for available updates. Returns Some(info) if update available, None otherwise. */\n readonly check: (currentVersion: string) => Effect.Effect<Option.Option<UpdateInfo>>\n /** Print the update notification to stderr. */\n readonly notify: (info: UpdateInfo) => Effect.Effect<void>\n }\n>()('uniku/cli/UpdateCheckService') {\n static readonly layer = Layer.sync(UpdateCheckService, () => makeUpdateCheckService())\n}\n\n// ── Constants ────────────────────────────────────────────────────────\n\nconst PACKAGE_NAME = '@uniku/cli'\nconst REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}/latest`\nexport const CACHE_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours\nconst FETCH_TIMEOUT_MS = 5_000\n\nfunction cacheUserSegment(): string | null {\n const getuid = (process as { getuid?: () => number }).getuid\n if (typeof getuid === 'function') {\n return `uid-${getuid()}`\n }\n\n try {\n const segment = userInfo().username.replace(/[^0-9A-Za-z._-]/g, '_')\n return segment ? `user-${segment}` : null\n } catch {\n return null\n }\n}\n\nfunction defaultCacheFile(): string {\n const userSegment = cacheUserSegment()\n const filename = userSegment ? `uniku-update-check-${userSegment}.json` : 'uniku-update-check.json'\n return join(tmpdir(), filename)\n}\n\nexport const DEFAULT_CACHE_FILE = defaultCacheFile()\n\n// ── Version comparison ───────────────────────────────────────────────\n\n/**\n * Parse a semver version string into its components.\n * Returns null if the string is not a valid semver.\n */\nexport function parseSemver(version: string) {\n const match = version.match(/^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?$/)\n if (!match) return null\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: match[4] ?? null,\n }\n}\n\n/**\n * Returns true if `latest` is newer than `current`.\n *\n * Handles pre-release correctly:\n * - 1.0.0 > 1.0.0-beta.1 (stable is newer than pre-release of same version)\n * - 1.0.0-beta.1 > 0.9.0 (pre-release of higher version is newer)\n */\nexport function isNewerVersion(latest: string, current: string): boolean {\n const l = parseSemver(latest)\n const c = parseSemver(current)\n if (!l || !c) return false\n\n if (l.major !== c.major) return l.major > c.major\n if (l.minor !== c.minor) return l.minor > c.minor\n if (l.patch !== c.patch) return l.patch > c.patch\n\n // Same major.minor.patch — stable (no prerelease) beats pre-release\n if (l.prerelease === null && c.prerelease !== null) return true\n if (l.prerelease !== null && c.prerelease === null) return false\n\n return false\n}\n\n// ── Skip conditions ──────────────────────────────────────────────────\n\nfunction optionalConfigString(name: string): Effect.Effect<Option.Option<string>> {\n return Config.option(Config.string(name)).pipe(Effect.catch(() => Effect.succeed(Option.none())))\n}\n\nfunction isTruthyConfig(value: Option.Option<string>): boolean {\n return Option.isSome(value) && value.value.length > 0\n}\n\nconst updateCheckConfig = Effect.all({\n noUpdateNotifier: optionalConfigString('NO_UPDATE_NOTIFIER'),\n ci: optionalConfigString('CI'),\n continuousIntegration: optionalConfigString('CONTINUOUS_INTEGRATION'),\n nodeEnv: optionalConfigString('NODE_ENV'),\n})\n\nexport function shouldSkipUpdateCheck(isStderrTTY = process.stderr.isTTY): Effect.Effect<boolean> {\n return updateCheckConfig.pipe(\n Effect.map(\n (config) =>\n isTruthyConfig(config.noUpdateNotifier) ||\n isTruthyConfig(config.ci) ||\n isTruthyConfig(config.continuousIntegration) ||\n (Option.isSome(config.nodeEnv) && config.nodeEnv.value === 'test') ||\n !isStderrTTY,\n ),\n )\n}\n\n// ── Notification formatting ──────────────────────────────────────────\n\nfunction formatNotificationWithColor(info: UpdateInfo, noColor: boolean): string {\n if (noColor) {\n const updateCmd = info.isStandaloneBinary\n ? `Download at https://github.com/jkomyno/uniku/releases`\n : `Run \\`npm install -g ${PACKAGE_NAME}\\` to update`\n return [\n '',\n ` Update available: ${info.currentVersion} → ${info.latestVersion}`,\n ` ${updateCmd}`,\n ` Set NO_UPDATE_NOTIFIER=1 to disable`,\n '',\n ].join('\\n')\n }\n\n const dim = '\\x1b[2m'\n const cyan = '\\x1b[36m'\n const boldCyan = '\\x1b[1;36m'\n const reset = '\\x1b[0m'\n\n const updateCmd = info.isStandaloneBinary\n ? `Download at ${cyan}https://github.com/jkomyno/uniku/releases${reset}`\n : `Run ${cyan}\\`npm install -g ${PACKAGE_NAME}\\`${reset} to update`\n\n return [\n '',\n ` ${dim}Update available:${reset} ${dim}${info.currentVersion}${reset} ${dim}→${reset} ${boldCyan}${info.latestVersion}${reset}`,\n ` ${updateCmd}`,\n ` ${dim}Set NO_UPDATE_NOTIFIER=1 to disable${reset}`,\n '',\n ].join('\\n')\n}\n\nexport function formatNotification(info: UpdateInfo): Effect.Effect<string> {\n return optionalConfigString('NO_COLOR').pipe(\n Effect.map((noColor) => formatNotificationWithColor(info, isTruthyConfig(noColor))),\n )\n}\n\nexport function shouldNotifyUpdate(\n args: readonly string[],\n result: Option.Option<UpdateInfo>,\n): result is Option.Some<UpdateInfo> {\n return Option.isSome(result) && !args.includes('--json')\n}\n\n// ── Cache helpers (plain Node.js — maximally resilient) ──────────────\n\nfunction readCache(cacheFile: string): UpdateCache | null {\n try {\n const content = readFileSync(cacheFile, 'utf-8')\n const parsed = JSON.parse(content) as unknown\n\n if (typeof parsed !== 'object' || parsed === null) return null\n const cache = parsed as { checkedAt?: unknown; latestVersion?: unknown }\n if (typeof cache.checkedAt !== 'number' || !Number.isFinite(cache.checkedAt)) return null\n if (cache.latestVersion !== undefined && typeof cache.latestVersion !== 'string') return null\n\n return cache.latestVersion === undefined\n ? { checkedAt: cache.checkedAt }\n : { latestVersion: cache.latestVersion, checkedAt: cache.checkedAt }\n } catch {\n return null\n }\n}\n\nfunction writeCache(cache: UpdateCache, cacheFile: string): void {\n try {\n const dir = dirname(cacheFile)\n mkdirSync(dir, { recursive: true })\n const tmpPath = `${cacheFile}.tmp`\n writeFileSync(tmpPath, JSON.stringify(cache))\n renameSync(tmpPath, cacheFile)\n } catch {\n // Silently ignore write errors\n }\n}\n\n// ── Registry fetch ───────────────────────────────────────────────────\n\nfunction fetchLatestVersion(currentVersion: string): Effect.Effect<string | null> {\n return Effect.tryPromise({\n try: (signal) =>\n fetch(REGISTRY_URL, {\n headers: {\n Accept: 'application/json',\n 'User-Agent': `${PACKAGE_NAME}/${currentVersion}`,\n },\n signal: AbortSignal.any([signal, AbortSignal.timeout(FETCH_TIMEOUT_MS)]),\n }).then(async (res) => {\n if (!res.ok) throw new Error(`HTTP ${res.status}`)\n const data = (await res.json()) as { version?: string }\n if (!data.version) throw new Error('Missing version field')\n return data.version\n }),\n catch: () => new Error('fetch failed'),\n }).pipe(Effect.catch(() => Effect.succeed(null)))\n}\n\n// ── Standalone binary detection ──────────────────────────────────────\n\ndeclare const __STANDALONE_BINARY__: boolean | undefined\n\nfunction isStandaloneBinary(): boolean {\n try {\n return typeof __STANDALONE_BINARY__ !== 'undefined' && __STANDALONE_BINARY__ === true\n } catch {\n return false\n }\n}\n\n// ── Live implementation ──────────────────────────────────────────────\n\nexport function makeUpdateCheckService(options: UpdateCheckServiceOptions = {}) {\n const cacheFile = options.cacheFile ?? DEFAULT_CACHE_FILE\n const fetchVersion = options.fetchLatestVersion ?? fetchLatestVersion\n const getNow = options.now ?? Date.now\n const detectStandaloneBinary = options.isStandaloneBinary ?? isStandaloneBinary\n const isStderrTTY = options.isStderrTTY ?? (() => process.stderr.isTTY)\n const writeStderr = options.writeStderr ?? ((message: string) => process.stderr.write(message))\n\n return UpdateCheckService.of({\n check: Effect.fn('UpdateCheckService.check')(\n function* (currentVersion: string) {\n if (yield* shouldSkipUpdateCheck(isStderrTTY())) {\n return Option.none<UpdateInfo>()\n }\n\n const cached = readCache(cacheFile)\n const now = getNow()\n\n // Cache is fresh — use cached result\n if (cached && now - cached.checkedAt < CACHE_TTL_MS) {\n if (cached.latestVersion && isNewerVersion(cached.latestVersion, currentVersion)) {\n return Option.some<UpdateInfo>({\n currentVersion,\n latestVersion: cached.latestVersion,\n isStandaloneBinary: detectStandaloneBinary(),\n })\n }\n return Option.none<UpdateInfo>()\n }\n\n // Cache is stale or missing — fetch from registry\n const latestVersion = yield* fetchVersion(currentVersion)\n\n if (latestVersion === null) {\n writeCache({ checkedAt: now }, cacheFile)\n return Option.none<UpdateInfo>()\n }\n\n writeCache({ latestVersion, checkedAt: now }, cacheFile)\n\n if (isNewerVersion(latestVersion, currentVersion)) {\n return Option.some<UpdateInfo>({\n currentVersion,\n latestVersion,\n isStandaloneBinary: detectStandaloneBinary(),\n })\n }\n\n return Option.none<UpdateInfo>()\n },\n Effect.catch(() => Effect.succeed(Option.none<UpdateInfo>())),\n ),\n\n notify: Effect.fn('UpdateCheckService.notify')(function* (info: UpdateInfo) {\n const message = yield* formatNotification(info)\n yield* Effect.sync(() => {\n writeStderr(message)\n })\n }),\n })\n}\n","","#!/usr/bin/env node\n\n// Deep imports: the package barrel pulls in modules that import the `bun`\n// builtin, which does not exist when the published bin runs under Node.\nimport * as BunRuntime from '@effect/platform-bun/BunRuntime'\nimport * as BunServices from '@effect/platform-bun/BunServices'\nimport * as Duration from 'effect/Duration'\nimport * as Effect from 'effect/Effect'\nimport * as Fiber from 'effect/Fiber'\nimport * as Layer from 'effect/Layer'\nimport * as Option from 'effect/Option'\nimport { makeCliRunner } from '@/src/commands'\nimport { preprocessArgs } from '@/src/runtime/args'\nimport { handleCliFailure } from '@/src/runtime/cli-failure'\nimport { OutputService } from '@/src/services/OutputService'\nimport { StdinService } from '@/src/services/StdinService'\nimport { shouldNotifyUpdate, UpdateCheckService } from '@/src/services/UpdateCheckService'\nimport pkg from '../package.json' with { type: 'json' }\n\n// ── CLI runner ──────────────────────────────────────────────────────\n\nconst runCli = makeCliRunner(pkg.version)\n\n// ── Service layers ──────────────────────────────────────────────────\n\nconst MainLayer = Layer.mergeAll(OutputService.layer, StdinService.layer, UpdateCheckService.layer, BunServices.layer)\n\n// ── Run ─────────────────────────────────────────────────────────────\n\nconst program = Effect.gen(function* () {\n const updateCheck = yield* UpdateCheckService\n // Drop the executable and script path — Command.runWith takes user args only.\n const args = preprocessArgs(process.argv.slice(2))\n\n // Fork update check as a background fiber\n const fiber = yield* Effect.forkChild(updateCheck.check(pkg.version), { startImmediately: true })\n\n // Run the main CLI command\n yield* runCli(args).pipe(Effect.catch((error) => handleCliFailure(error, args)))\n\n // After the main command, wait briefly for the update check, then interrupt\n // it — v4's runtime keeps the process alive while fibers are suspended.\n const result = yield* Fiber.join(fiber).pipe(Effect.timeoutOption(Duration.millis(250)))\n yield* Fiber.interrupt(fiber)\n\n const update = Option.flatten(result)\n if (shouldNotifyUpdate(args, update)) {\n yield* updateCheck.notify(update.value)\n }\n})\n\nprogram.pipe(Effect.provide(MainLayer), BunRuntime.runMain)\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@uniku/cli",
4
- "version": "0.0.12",
4
+ "version": "0.1.0",
5
5
  "description": "CLI tool for generating and validating unique identifiers",
6
6
  "author": {
7
7
  "name": "Alberto Schiabel",
@@ -18,6 +18,9 @@
18
18
  "bin": {
19
19
  "uniku": "./build/bin.mjs"
20
20
  },
21
+ "engines": {
22
+ "node": ">=20.19.0"
23
+ },
21
24
  "publishConfig": {
22
25
  "registry": "https://registry.npmjs.org/",
23
26
  "access": "public"
@@ -27,16 +30,14 @@
27
30
  "README.md"
28
31
  ],
29
32
  "dependencies": {
30
- "effect": "3.19.16",
31
- "@effect/cli": "0.73.2",
32
- "@effect/platform": "0.94.3",
33
- "@effect/platform-bun": "0.87.1",
34
- "uniku": "0.0.12"
33
+ "effect": "4.0.0-beta.93",
34
+ "@effect/platform-bun": "4.0.0-beta.93",
35
+ "uniku": "0.0.13"
35
36
  },
36
37
  "devDependencies": {
37
38
  "@types/bun": "^1.3.8",
38
- "@effect/vitest": "0.27.0",
39
- "vitest": "~3.2.0"
39
+ "@effect/vitest": "4.0.0-beta.93",
40
+ "vitest": "^4.1.9"
40
41
  },
41
42
  "scripts": {
42
43
  "clean": "rimraf build .turbo",
@@ -45,6 +46,7 @@
45
46
  "install:binary": "bun scripts/install-binary.ts",
46
47
  "typecheck": "tsc --noEmit",
47
48
  "test": "vitest run",
49
+ "test:unit": "vitest run",
48
50
  "test:watch": "vitest"
49
51
  }
50
52
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"bin.d.mts","names":[],"sources":["../src/bin.ts"],"sourcesContent":[],"mappings":";iBAmBgB,cAAA"}